List-顺序表--2

打印 上一主题 下一主题

主题 968|帖子 968|积分 2904

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
目次

1、ArrayList
2、ArrayList构造方法
3、ArrayList常见方法
4、ArrayList的遍历
5、ArrayList的扩容机制
6、ArrayList的具体使用
6.1、杨辉三角
6.2、简单的洗牌算法

1、ArrayList

在集合框架中,ArrayList 是一个普通的类,实现了 List 接口
   说明:
  1. ArrayList是以泛型方式实现的,使用时必须要先实例化
2. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
3. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
4. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
5. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList
6. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态范例的顺序表
  2、ArrayList构造方法


   底层代码分析:
  

  1. 带一个参数的构造方法,初始化 ArrayList 时可以指定初始容量
  

  2. 不带参数的构造方法,初始化时分配的是一个空数组
  

  既然没有分配内存,那这个 ArrayList 对象是怎样存数据的呢?
  ^
  继续查看 add 方法的原码,得出结论:
  结论1:虽然初始化时没有分配内存,但是第一次 add 的时间会分配巨细为10的内存
  结论2:对于ArrayList来说,当容量满了,采用的扩容方式是1.5倍扩容
  ^
  3. 有通配符的构造方法
  

  参数列表的含义:
  Collection:表示传入的参数是 Collection 范例的,实现了Collection接口的范例也可以
  <? extends E>:通配符上界,这里表示可以传入的参数范例是 E 或者 E 的子类
  ^
  比方:
  ArrayList<Integer> list = new ArrayList<>();
  ArrayList<Number> list1 = new ArrayList<>(list);
  首先,list 是实现了 Collection 接口的,?:Integer ;E: Number,Integer 是 Number 的子类,list 满足这两个条件,所以可以作为参数正确实行。相当于把 list 表中数据打包给到 list
  1.     public static void main(String[] args) {
  2.         LinkedList<Integer> list1 = new LinkedList<>();
  3.         list1.add(1);
  4.         list1.add(2);
  5.         list1.add(3);
  6.         ArrayList<Number> list2 = new ArrayList<>(list1);
  7.         list2.add(99);
  8.         list2.add(88);
  9.         System.out.println(list2); // 输出 [1,2,3,99,88]
  10.     }
复制代码
3、ArrayList常见方法


  1.     public static void main(String[] args) {
  2.         ArrayList<Integer> list = new ArrayList<>();
  3.         list.add(1);
  4.         list.add(2);
  5.         list.add(3);
  6.         ArrayList<Number> list123 = new ArrayList<>();
  7.         list123.addAll(list); // 与上述第三个构造方法类似
  8.         System.out.println(list123);//123
  9.         list123.remove(2); // 删除 2 位置元素
  10.         list123.remove(new Integer(2)); // 删除遇到的第一个 2
  11.         System.out.println(list123);//23
  12.         list123.get(0);
  13.         list123.set(1,2);
  14.         list123.contains(1);
  15.         list.add(4);
  16.         list.add(5);
  17.         //并不会产生新的对象!
  18.         List<Integer> list1 = list.subList(1,3); // [1,3)
  19.         System.out.println(list1);
  20.         System.out.println("==============");
  21.         list1.set(0,99);
  22.         System.out.println(list1);
  23.         System.out.println(list);
  24.     }
复制代码
  上述 subList 方法实行效果:
  list1:  [99,3]
  list:    [1, 99, 3,4, 5]
  发现通过 list1 修改,list 也会发生改变,所以 subList 的实行过程并不会产生新的对象,在这个案例中,list1 的起始位置指向 list 的 1 下标
  4、ArrayList的遍历

   1. for循环+下标
  1. public static void main(String[] args) {
  2.     List<Integer> list = new ArrayList<>();
  3.     list.add(1);
  4.     list.add(2);
  5.     list.add(3);
  6.     list.add(4);
  7.     list.add(5);
  8.     // 使用下标+for遍历
  9.     for (int i = 0; i < list.size(); i++) {
  10.         System.out.print(list.get(i) + " ");
  11.     }
  12.     System.out.println();
  13. }
复制代码
2. foreach
  ^
  for(Integer x : list) {
    System.out.print(x+" ");
  }
System.out.println();
    3. 迭代器
  只有实现了 literable 接口的范例,才能使用迭代器;Map 就不能使用,由于他没有实现 literable 接口
  Iterator<Integer> it = list.iterator();    --  通用迭代器
  Iterator<Integer> it = list.listIterator();    --  List 的专属迭代器
  ^
  //使用 迭代器 遍历集合类 list
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
    System.out.println(it.next()+" ");
  }
  

  注意:ArrayList最长使用的遍历方式是:for循环+下标 以及 foreach 
5、ArrayList的扩容机制

在上述构造方法中,通过查看 add 方法的底层代码得出结论:ArrayList是一个动态范例的顺序表,即:在插入元素的过程中会主动扩容
   底层代码总结:
  1. 检测是否真正需要扩容,如果是调用grow准备扩容
2. 预估需要库容的巨细
  

  • 初步预估按照1.5倍巨细扩容
  • 如果用户所需巨细凌驾预估1.5倍巨细,则按照用户所需巨细扩容
  • 真正扩容之前检测是否能扩容乐成,防止太大导致扩容失败
  3. 使用copyOf举行扩容
  6、ArrayList的具体使用

6.1、杨辉三角

   力扣118
  

  分析 List<List<Integer>> 
  

  1. class Solution {
  2.     public List<List<Integer>> generate(int numRows) {
  3.         List<List<Integer>> ret = new ArrayList<>();
  4.         // 1. 先处理第一行
  5.         List<Integer> list = new ArrayList<>();
  6.         list.add(1);
  7.         ret.add(list);
  8.         // 2. 从第2行开始计算 每个list当中的数据
  9.         for(int i = 1;i < numRows;i++) {
  10.             // 3. 先准备当前行数据
  11.             List<Integer> curRow =  new ArrayList<>();
  12.             // 4. 准备当前行的第一个数据
  13.             curRow.add(1);
  14.             // 5. 准备当前的中间数据
  15.             List<Integer> prevRow = ret.get(i-1); // 拿到上一行的数据
  16.             for(int j = 1; j < i;j++) {
  17.                 // 上一行的当前列 + 上一行的前一列
  18.                 int val = prevRow.get(j) + prevRow.get(j-1);
  19.                 curRow.add(val);
  20.             }
  21.             // 6. 准备当前行最后一个数据
  22.             curRow.add(1);
  23.             // 7. 把这个数据放到二维数组当中去
  24.             ret.add(curRow);
  25.         }
  26.         return ret;
  27.     }
  28. }
复制代码
6.2、简单的洗牌算法

   实现这个算法要解决的标题:
  1.买一副牌【要天生一副扑克牌】放到哪里?
  2.洗牌,怎么洗?
  3.揭牌,每个人轮流抓5张牌,怎么抓牌?抓的牌放到哪里?
    1. 创建一个 card 类,定义 花色 和 数字 两个属性;天生 get 和 set 方法;天生toString方法
  1. package card;
  2. public class Card {
  3.     private String suit;//花色
  4.     private int rank;//数字
  5.     public Card(String suit, int rank) {
  6.         this.suit = suit;
  7.         this.rank = rank;
  8.     }
  9.     public String getSuit() {
  10.         return suit;
  11.     }
  12.     public void setSuit(String suit) {
  13.         this.suit = suit;
  14.     }
  15.     public int getRank() {
  16.         return rank;
  17.     }
  18.     public void setRank(int rank) {
  19.         this.rank = rank;
  20.     }
  21.     @Override
  22.     public String toString() {
  23.         return suit+":"+rank+" ";
  24.     }
  25. }
复制代码
   2. 创建 CardDemo 和 Test 类;CardDemo类中定义一个买牌的方法,在Test类中测试
      一共52张牌 1-k,此中1对应A、J对应11、Q对应12、K对应13
  

  

     3. 在CardDemo 类中再定义一个花色类,并完满buyCard方法
  

    4. 买完牌后洗牌,这里使用天生随机数的方式,从最后一张牌开始,与随机天生的牌交换
  

  

    5. 揭牌,3个人每人轮流揭5张,每次揭1张
  把三个人的关系用一个二维数组表示
  

  每揭一张牌,就把整副牌的0下标位置删除
  

  CardDemo 类的完整代码
  1. public class CardDemo {
  2.     private  final String[] suits = {"♥","♠","♦","♣"};
  3.     /**
  4.      * 52张 1-K
  5.      *      J   Q  K
  6.      *      11 12 13
  7.      * @return
  8.      */
  9.     public List<Card> buyCard() {
  10.         List<Card> cardList = new ArrayList<>();
  11.         for (int i = 0; i < 4; i++) {
  12.             for (int j = 1; j <= 13; j++) {
  13.                 Card card = new Card(suits[i],j);
  14.                 cardList.add(card);
  15.             }
  16.         }
  17.         return cardList;
  18.     }
  19.     public void shuffle(List<Card> cardList) {
  20.         Random random = new Random();
  21.         for (int i = cardList.size()-1; i > 0; i--) {
  22.             int index = random.nextInt(i);
  23.             //index  i 交换
  24.             swap(cardList,i,index);
  25.         }
  26.     }
  27.     private void swap(List<Card> cardList,int a,int b) {
  28.         Card tmp = cardList.get(a);
  29.         cardList.set(a,cardList.get(b));
  30.         cardList.set(b,tmp);
  31.         /**
  32.          * tmp = a
  33.          * a = b
  34.          * b = tmp
  35.          */
  36.     }
  37.     /**
  38.      * 揭牌
  39.      * 3个人 每个人轮流揭牌5张
  40.      * @param cardList
  41.      */
  42.     public void getCard(List<Card> cardList) {
  43.         List<Card> hand1 = new ArrayList<>();
  44.         List<Card> hand2 = new ArrayList<>();
  45.         List<Card> hand3 = new ArrayList<>();
  46.         List<List<Card>> hands = new ArrayList<>();
  47.         hands.add(hand1);
  48.         hands.add(hand2);
  49.         hands.add(hand3);
  50.        //3个人 轮流抓牌5张 每次揭牌1张
  51.         for (int i = 0; i < 5; i++) {
  52.             //j代表人
  53.             for (int j = 0; j < 3; j++) {
  54.                 Card card = cardList.remove(0);
  55.                 hands.get(j).add(card);
  56.             }
  57.         }
  58.         System.out.println("第1个揭牌如下:");
  59.         System.out.println(hand1);
  60.         System.out.println("第2个揭牌如下:");
  61.         System.out.println(hand2);
  62.         System.out.println("第3个揭牌如下:");
  63.         System.out.println(hand3);
  64.         System.out.println("剩下的牌:");
  65.         System.out.println(cardList);
  66.     }
  67. }
复制代码
Test 类中代码
  1. public class Test {
  2.     public static void main(String[] args) {
  3.         CardDemo cardDemo = new CardDemo();
  4.         List<Card> cardList =  cardDemo.buyCard();
  5.         System.out.println("买的牌如下:");
  6.         System.out.println(cardList);
  7.         System.out.println("洗牌:");
  8.         cardDemo.shuffle(cardList);
  9.         System.out.println(cardList);
  10.         System.out.println("揭牌:");
  11.         cardDemo.getCard(cardList);
  12.     }
  13. }
复制代码
7、顺序表的优缺点

缺点:

  • 插入数据必须移动其他数据,最坏环境下,就是插入到0位置。时间复杂度O(N)
  • 删除数据也需要移动数据,最坏环境下,就是删除0位置。时间复杂度O(N)
  • 扩容之后有大概会浪费空间
优点:在给定下标举行查找的时间,时间复杂度O(1)
总结:顺序表比较适合举行给定下标查找的场景。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

雁过留声

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表