横看成岭侧成峰,远近高低各不同。
不识庐山真面目,只缘身在此山中。
——苏轼
这一块儿学的是云里雾里,咱们先从简单的入手。逐渐的拨开迷雾见太阳。本次先做List集合的三个实现类的学习笔记
List特点:有序,元素可重复。其实它的本质就是一个线性表(下面会说到)
先上图,Java集合有Collection体系和Map体系:
然后简单介绍一下数据结构和算法:
数据结构就是数据和数据之间的关系,好比分子结构,晶体结构。碳原子按照一定的方式组合在一起形成碳分子,碳分子再按照一定方式形成晶体。
算法是对解题步骤的描述,体现在计算机上就是指令的有限序列
数据结构分为逻辑结构和物理结构。
逻辑结构:
物理结构:
顺序存储结构和链式存储结构。
顺序存储结构:在内存中开辟若干的连续空间,将每个空间存入数据,数据关联与其地址一致。比如数组。
上代码:
1 public classTest01 {2
3 public static voidmain(String[] args) {4 Integer[] arr = new Integer[10];5 //向数组中插入元素
6 for (int i = 0; i < arr.length; i++) {7 arr[i] =i;8 }9 //将其中一个元素变为null;
10 arr[3] = null;11 //出现碎片
12 for(Integer item : arr) {13 System.out.println(item);14 }15 System.out.println("===========");16 arr[3] = 12;//存取方便,可直接赋值或取值17 //删除第X个元素,但要避免碎片产生:
18 int x = 2;19 arr[x-1]=null;//第二个元素引用变为null,该步骤可以省略,因为下面又更改了arr[x-1]的引用。写上仅为便于理解20 //第X个元素之后的元素前移,代码表现为把后面的值依次赋给前面,从第X个开始
21 for (int i = x-1; i < arr.length-1; i++) {22 arr[i] = arr[i+1];23 }24 //length-1,需要新建数组来保存原数组
25 Integer[] newArr = new Integer[arr.length-1];26 for (int i = 0; i < newArr.length; i++) {27 newArr[i]=arr[i];28 System.out.println(newArr[i]);29 }30 System.out.println("============");31 //第Y个位置插入一个元素
32 int y = 5;33 //需要后移,所以先创建数组length+1
34 Integer [] newArr2 = new Integer[newArr.length+1];35 for (int i = 0; i < newArr.length; i++) {36 newArr2[i] =newArr[i];37 }38 //后移
39 for (int i = newArr2.length-1; i > y-1 ; i--) {40 newArr2[i]=newArr2[i-1];41 }42 //插入
43 newArr2[y-1] = 22;44 //遍历输出
45 for (int i = 0; i < newArr2.length; i++) {46 System.out.println(newArr2[i]);47 }48 }49
50 }
View Code
出结论:
顺序存储结构:
优点:1无需为表示表中元素之间的逻辑关系而添加空间
2可以快速地存取表中任意位置的元素
缺点:1插入和删除操作需要移动大量元素
2需要考虑索引越界为题
3扩容空间可能会造成空间浪费,缩小空间又可能会索引越界
4null值会造成空间“碎片”
链式存储结构:每个元素只记住它下一个元素是谁(地址)。
链式存储结构有多种,这里只介绍Java的链式存储结构:双向链表
上代码:
1 public classMyLinkedListDemo {2
3 public static voidmain(String[] args) throws Exception {4 MyLinkList list = new MyLinkList<>();5 list.addFist("张三");6 list.addFist("李四");7 list.addLast("张三");8 list.addLast("李四");9 list.print();10 System.out.println("===========");11 list.add(2,"王五");12 list.print();13 System.out.println("===========");14 list.add(5,"王五");15 System.out.println(list.getSize());16 list.add(7,"王五");//这里会抛出空指针异常
17 }18 }
View Code
1 public class MyLinkList{2
3 Nodefirst;4 Nodelast;5
6 public voidaddFist(E e){7 if (first == null) {8 final Node newNode = new Node(null, e, null);//第一次加入数据,为first,last赋初值
9 first =newNode;10 last =newNode;11 }else{//否则把first的prev指向newNode,把newNode的next指向first,最后把newNode变为first
12 final Node newNode = new Node(null, e, first);13 first.prev =newNode;14 first =newNode;15 }16 }17 public voidaddLast(E e){18 if (last == null) {19 final Node newNode = new Node(null, e, null);//第一次加入数据,为first,last赋初值
20 first =newNode;21 last =newNode;22 }else{//否则把last的next指向newNode,把newNode的prev指向last,最后把newNode变为last
23 final Node newNode = new Node(last, e, null);24 last.next =newNode;25 last =newNode;26 }27 }28 public void add (int index,E e) throws Exception{//下标超出链表长度会空指针,因为超出长度的部分prev和next都是null
29 if(index == 0){30 addFist(e);31 }else if (index ==getSize()) {32 addLast(e);33 }else{34 //这里画张图想一下,我要在1处插入x,就要把x的prev指向0,next指向1,把0的next指向x,把1的prev指向x35 //这里的1和0就是index和index-1,通过循环Node.next获取index对应的Node36 //先拿到0和1
37 Node tempNodeNext =first;38 for (int i = 0; i < index; i++) {39 tempNodeNext =tempNodeNext.next;40 }41 Node tempNodePrev =tempNodeNext.prev;42 //这里改指向
43 final Node newNode = new Node(tempNodePrev, e, tempNodeNext);44 tempNodeNext.prev =newNode;45 tempNodePrev.next =newNode;46 }47 }48 public intgetSize (){49 Node temp =first;50 int i = 0;51 while(temp != null){52 temp =temp.next;53 i++;54 }55 returni;56 }57 //由于不实现Iterable,只能提供打印方法
58 public voidprint() {59 Node temp =first;60 while(temp != null){61 System.out.println(temp.item);62 temp =temp.next;63 }64 }65 private static class Node{66 Nodeprev;67 E item;68 Nodenext;69 Node(Node prev, E item, Nodenext) {70 super();71 this.prev =prev;72 this.item =item;73 this.next =next;74 }75 }76 }
View Code
出结论:
链式存储结构:
优点:插入和删除操作只需改变节点next和prev成员的指向即可,无需移位,无需扩容
缺点:失去了直接存取表中任意位置元素的能力
顺序存储结构和链式存储结构的对比:
1、存储分配方式:
顺序存储结构使用一段连续的存储单元依次存储线性表元素
链式存储结构使用任意存储单元存放线性表的元素
2、时间性能:
查找:
顺序存储结构O(1)
链式存储结构O(n)
插入和删除:
顺序存储结构O(n)
链式存储结构O(1)
3、空间性能:
顺序存储结构:空间分大了浪费,分小了上溢,还得扩容
链式存储结构:有空间就能分配,元素个数不受限制
言归正传。
ArrayList是顺序存储的线性表,LinkedList是链式存储的线性表
它们的特点都是有序,元素值可以重复。区别是底层算法不同。
Vector,这里我简单浏览了一下源代码,Vector底层算法和ArrayList是一样的
这里就不赘述了,直接说区别:
1、Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法线程不安全,由于线程的同步必然要影响性能,因此ArrayList的性能比Vector好。
2、Vector扩容时容量翻倍,而ArrayList只增加50%的大小,(直接查它们的grow()方法)这样,ArrayList就有利于节约内存空间。
总之ArrayList比Vector在性能方面(无论时间性能还是空间性能)都是能省则省。
List就说到这里。下一篇说说队列