坚持一定很酷!
学习学习!!
- 判断数组是否已经放满:有效长度==实际数组长度。
扩容:数组名 = Arrays.copyOf(数组名,扩容后的长度)
一般情况下,扩容不会失败;但是如果扩容的数据太大,可能就会无法扩容,就会报负数异常:所以可以try…catch 再进行异常处理。- 注意插入元素操作:
把usedSize-1位置的元素向后挪,一直到想要插入的
pos位置;(>=pos)的元素都向后挪,再把元素插入到
pos位置- add(int pos,int data):首先检查元素是否合法,然后
再判断是否满以及扩容问题,最后进行插入操作
add(int data):先判断是否满,然后进行扩容,然后再
进行尾插(usedSize位置插入)- 是否包含contains:for循环usedSize
- 基本上都要判断下标合法性
remove():后一个覆盖前一个,然后最后一个元素置空
则:for循环只到 (- 删除等操作要进行手动置空(尤其是引用类型),简单类型可以不写
- 向右移>>1 :表示除以2
- 注意联动改变(子串与原来字符串)
package arraysList;
import java.util.Arrays;
// 顺序表以数组形式进行存储
public class SeqList {
// 首先创建必要的量:数组、有效数记录、默认数组长度
public int[] array;
public int usedSize;
public static final int DEFAULT_SIZE = 5;
// 构造方法进行初始化(初始化数组大小,为数组开辟空间)
public SeqList() {
array = new int[DEFAULT_SIZE];
}
// 不采用以下方法,采用报异常的方式!!
/*// 检查下标的合法性:不能跳着进行存放
public boolean isLegal(int pos) {
if((pos<0)||(pos>usedSize)) {
return false;
} else {
return true;
}
}*/
// 检查下标的合法性:不能跳着进行存放
// 抛出异常以及自定义异常
public void isLegal(int pos) {
if((pos<0)||(pos>usedSize)) {
throw new PosIndexNotLegalException("下标不合法!");
}
}
// 判断是否满
public boolean isFull() {
return (this.usedSize == array.length);
}
// 打印顺序表-打印有效位即可
public void display() {
/* // 使用for-each进行打印-no-因为会全部打印!!
for (int x:array) {
System.out.println(x);
}*/
// 尽量使用this!!!
for (int i = 0; i < this.usedSize; i++) {
System.out.print(this.array[i] + " ");
}
System.out.println();
}
// 新增元素,默认在数组最后新增
public void add(int data) {
// 判断是否已满
try {
if(isFull()) {
array = Arrays.copyOf(array,-1);
}
} catch (NegativeArraySizeException e) {
e.printStackTrace();
array = Arrays.copyOf(array,2*array.length); //扩容两倍
}
// 在usedSize位置进行元素存储,然后usedSize++
array[usedSize++] = data;
}
// 在 pos 位置新增元素
public void add(int pos, int data) {
// 检查pos是否合法--try...catch方式
// 判断是否满以及扩容
// 将pos以及之后的位置全部向后挪一位:注意应该从后往前挪!!
try {
isLegal(pos);
if(isFull()) { // 满了就扩容,不需要进行异常抛出
array = Arrays.copyOf(array,2*array.length);
}
for (int i = usedSize-1; i >= pos; i++) {
array[i+1] =array[i];
}
array[pos] = data;
usedSize++; // 更新有效数据个数
} catch (PosIndexNotLegalException e) {
e.printStackTrace();
}
}
// 判定是否包含某个元素
public boolean contains(int toFind) {
// 进行遍历
for (int i = 0; i < usedSize; i++) {
if(array[i] == toFind) {
return true;
}
}
return false;
}
// 查找某个元素对应的位置
public int indexOf(int toFind) {
// 进行遍历
for (int i = 0; i < usedSize; i++) {
if(array[i] == toFind) {
return i;
}
}
return -1; // 不存在就输出-1
}
// 获取 pos 位置的元素
public int get(int pos) {
// 首先判断pos是否合法
// 合法且找到才输出元素
try {
isLegal(pos);
return array[pos];
} catch (PosIndexNotLegalException e) {
e.printStackTrace();
}
return -1;
}
// 给 pos 位置的元素设为 value
public void set(int pos, int value) {
// 首先进行合法性判断,然后将pos位置的元素进行替换
try {
isLegal(pos);
array[pos] = value;
} catch (PosIndexNotLegalException e) {
e.printStackTrace();
}
}
//删除第一次出现的关键字key
public void remove(int toRemove) {
// 遍历的方法不容易进行覆盖操作,则改用找该元素的首下标,找到就存在可以进行覆盖,否则不存在不用删除
/*//遍历
for (int i = 0; i < usedSize; i++) {
if(array[i]==toRemove) {
// 从该项开始进行覆盖,一直到usedSize-1
}
}*/
// 改用找该元素的首下标,找到就存在可以进行覆盖,否则不存在不用删除
int index = indexOf(toRemove);
if(index == -1) {
System.out.println("sorry 该关键字并不存在!");
return;
} else {
// 从该项开始进行覆盖,一直到usedSize-1: 从前往后+usedSize--
for (int i = index; i < usedSize-1; i++) {
array[i] = array[i+1];
}
}
// 有效元素--
usedSize--;
}
// 获取顺序表长度:有效长度
public int size() {
return usedSize;
}
// 清空顺序表
public void clear() {
/*for (int i = 0; i < usedSize; i++) {
array[i] = Integer.parseInt(null);
}*/
// 将有效个数置0就行
usedSize = 0;
System.out.println("清空成功!");
}
}
package arraysList;
// 自定义下标不合法异常-非受查异常-运行时异常
public class PosIndexNotLegalException extends RuntimeException{
public PosIndexNotLegalException() {
}
public PosIndexNotLegalException(String message) {
super(message);
}
}
- ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
- ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
- ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
- 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList
- ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表
package ArrayListTravel;
// 掌握ArrayList的常用方法
// ArrayList的遍历:三种方式
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class Test {
public static void main(String[] args) {
//List list = new List<>(); //错误!List是接口,不能进行实例化!!但是可以对具体子类进行初始化
List<Integer> list = new ArrayList<>();
// 增加元素!
list.add(12);
list.add(34);
list.add(2,56);
list.add(78);
list.add(4,90);
// for循环+下标进行遍历:注意获取长度的方法
System.out.println("使用for循环+下标进行遍历:");
for (int i = 0; i < list.size(); i++) {
// 注意获取下标对应元素的方法
System.out.print(list.get(i)+" ");
}
System.out.println();
// 使用for-each进行遍历:
System.out.println("使用for-each进行遍历:");
for (int x:list) {
System.out.print(x+" ");
}
System.out.println();
// 使用迭代器遍历
// 使用ListIterator
System.out.println("使用ListIterator迭代器遍历(调用List方法):");
ListIterator<Integer> listIterator = list.listIterator(); // 一定要注意该处的赋值内容是调用List的方法!!
while(listIterator.hasNext()) {
System.out.print(listIterator.next()+" ");
}
System.out.println();
// 使用Iterator
System.out.println("使用Iterator迭代器遍历(调用List方法):");
Iterator<Integer> iterator = list.iterator(); // 一定要注意该处的赋值内容是调用List的方法!!
while(iterator.hasNext()) {
System.out.print(iterator.next()+" ");
}
System.out.println();
}
}
- 检测是否真正需要扩容,如果是调用grow准备扩容
- 预估需要库容的大小
初步预估按照1.5倍大小扩容
如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容
真正扩容之前检测是否能扩容成功,防止太大导致扩容失败- 使用copyOf进行扩容
// 扩容
private void grow(int minCapacity) {
// 获取旧空间大小
int oldCapacity = elementData.length;
// 预计按照1.5倍方式扩容
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果用户需要扩容大小 超过 原空间1.5倍,按照用户所需大小扩容
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果需要扩容大小超过MAX_ARRAY_SIZE,重新计算容量大小
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 调用copyOf扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
- 进行洗牌:
随机数!!注意Random进行实例化的过程。- 抓牌过程要注意双层循环的顺序:
是先给每个人都发一张牌,而不是给一个人先发完五张牌
so:
顺序为:先进行5张牌循环,再进行3个人循环,这样才会
使得先给三个人每人一张牌,即用牌去循环人
package card;
// 首先准备一副牌的必要变量
public class Card {
public int value; // 牌面值
public char flower; //花色
// 构造方法进行初始化
public Card(int value, char flower) {
this.value = value;
this.flower = flower;
}
// toString 方法进行重写
@Override
public String toString() {
return "{" + value + flower +
"}";
}
}
package card;
// static只有一份,要改变就全部改变!
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
// 具体牌以及洗牌、出牌
public class CardDemo {
// 先给花色创建一个组-类似常数!!
public static final char[] SUITS = {'♥','♠','♦','♣'};
// 准备一副牌
// 注意每一张牌都是由花色以及牌面值组成的,也就是一个Card类型--所以使用List,以Card类型作为参数!
// List list = new ArrayList<>();// 注意该处进行修改,写为以下形式
private static List<Card> preDesk() { // 直接写为一个方法,返回值类型是List(整副牌)
List<Card> desk = new ArrayList<>(52); // 容量52:52张牌
// 进行牌的初始化
for (int i = 0; i < 4; i++) {
for (int j = 1; j <= 13; j++) {
Card card = new Card(j,SUITS[i]);
// 每初始化一张牌就把牌存储添加到desk里面(这副牌)
desk.add(card);
}
}
return desk;
}
// 进行洗牌 的实际操作
private static void washDeskWork(List<Card> deck,int i, int j) {
// 随机洗牌
Card fa = deck.get(j);
deck.set(j, deck.get(i));
deck.set(i,fa);
}
// 创建随机数 +洗牌
private static void washDesk(List<Card> deck) {
Random random = new Random(20220728); //种子数
for (int j = 1; j < deck.size(); j++) { //通过的是下标去打乱顺序,所以注意下标取值!
// 注意输入的j只能从1开始!!!
int i = random.nextInt(j);
// i代表随机下标 j代表该牌的实际位置下标
// 每获得一次随机位置就进行一次洗牌
washDeskWork(deck,i,j);
}
}
// 进行抓牌
private static List<List<Card>> hand(List<Card> deck) {
// 假设有3个人,每个人5张牌
// 3个人构成一个数组,而每个人受力的5张牌又是一个数组,
// 每张牌的返回类型是Card,每一组牌/每个人的返回类型其实是List
// 而这三个人和五张牌相当于二维数组--可以用List顺序表表示数组
List<List<Card>> table = new ArrayList<>();
table.add(new ArrayList<>()); // 二维数组中的其中一维进行第二维开辟开间
table.add(new ArrayList<>());
table.add(new ArrayList<>());
for (int i = 0; i < 5; i++) { //牌给每人一张
for (int j = 0; j < 3; j++) { // 人
/*table.get(j).set(i, deck.remove(i)); //remove的下标是0 永远删除的都是第一个元素!*/
// 是要将元素添加到table中,而不是设置修改元素,现在一个有效元素都没有!
table.get(j).add(deck.remove(0)); //注意下标!
}
}
return table;
}
public static void main(String[] args) {
CardDemo cardDemo = new CardDemo();
// 牌展示
System.out.println("准备好的完整牌:");
List<Card> desk = preDesk();
for (Card x:desk) {
System.out.print(x.toString() + " ");
}
System.out.println();
System.out.println("洗牌后:");
washDesk(desk);
for (Card x:desk) {
System.out.print(x.toString() + " ");
}
System.out.println();
// 抓牌
System.out.println("进行抓牌:");
List<List<Card>> hands = hand(desk);
// 余牌
System.out.println("抓牌后的余牌为:");
for (Card x:desk) {
System.out.print(x.toString()+" ");
}
System.out.println();
// 每个人的牌
System.out.println("所抓的每个人的牌进行展示:");
for (int i = 0; i < 3; i++) {
System.out.println("第"+(i+1)+"个人的牌展示:");
/*for (int j = 0; j < 5; j++) {
System.out.print(hands.get(i).get(j) +" ");
}
System.out.println();*/
System.out.println(hands.get(i)); //注意输出形式!!以一维数组形式进行输出
}
}
}
public List<List<Integer>> generate(int numRows) {
// List>:实际意义是一个二维数组,也就是两个一维数组,元素类型是int类型
// 每行第一个元素以及最后一个元素都是1,其余元素是上面两个元素之和
// 一定要注意二维数组要进行两次实例化new操作
List<List<Integer>> list = new ArrayList<>();
List<Integer> ret = new ArrayList<>();
ret.add(1);
list.add(ret);// 第一行第一列搞定!
// 从1一行开始是因为之前第一行已经搞定!
for(int i=1; i<numRows; i++) {
// 当前行-一维数组
List<Integer> curRow = new ArrayList<>();
curRow.add(1); // 当前每行第一列为1 ok!
/// 上一行
//List preRow = new ArrayList<>(); // 错误,这样并未给其初始化!
List<Integer> preRow = list.get(i-1); //注意!!
// 从1开始是因为首列值已经确定,以及只有从1开始才能取到前一行的首列0列
// 注意该处循环的次数!!
//for(int j=1; j
// 需要使用上一行最后一列,因为计算需要,但是每行总会比上一行多一列,最后一列为1,需要后面单独拎出来add1
for(int j=1; j<i; j++) {
curRow.add(preRow.get(j-1)+preRow.get(j)); //取之前行的两列相加之和!
}
curRow.add(1); // 每行最后一列为1
// 此时当前行就是完整一行了!
list.add(curRow); // 再将当前行传入到二维数组
}
return list;
// 以下是错误代码
/* for(int i=0; i());
for(int j=1; j
}