19、集合之LinkedList

来源:互联网 发布:淘宝刷到单如何赚钱 编辑:程序博客网 时间:2024/05/01 04:51

LinkedList——链表

相比较于ArrayList的方法,除了Add(),get(),remove(),size()等,LinkedList多了addLast(),addFirst(),getFirst

1、一般将数据结构分为两大类:线性数据结构和非线性数据结构。线性数据结构有线性表、栈、队列、串、数组和文件;非线性数据结构有树和图。

线性表的逻辑结构是n个数据元素的有限序列: (a1, a2,a3,…an),n为线性表的长度(n≥0),n=0的表称为空表。数据元素呈线性关系。必存在唯一的称为“第一个”的数据元素;必存在唯一的称为“最后一个”的数据元素;除第一个元素外,每个元素都有且只有一个前驱元素;除最后一个元素外,每个元素都有且只有一个后继元素。所有数据元素在同一个线性表中必须是相同的数据类型。

线性表按其存储结构可分为顺序表和链表。用顺序存储结构存储的线性表称为顺序表;用链式存储结构存储的线性表称为链表。将线性表中的数据元素依次存放在某个存储区域中,所形成的表称为顺序表。一维数组就是用顺序方式存储的线性表。ArrayList就相当于顺序表。LinkedList就相当于链表。

2、单向链表

链表的操作

[java] view plaincopyprint?
  1. public class Node 
  2.     String data; 
  3.     Node next; 
  4.      
  5.     public Node(String s) 
  6.     { 
  7.         data = s; 
  8.     } 
  9.  
  10. public class NodeTest 
  11.     public staticvoid main(String[] args) 
  12.     { 
  13.         Node node1 = new Node("node1"); 
  14.         Node node2 = new Node("node2"); 
  15.         Node node3 = new Node("node3"); 
  16.         Node node4 = new Node("node4"); 
  17.          
  18.         node1.next =node2; 
  19.         node2.next =node3; 
  20.          
  21.         node1.next = node4; 
  22.         node4.next = node2; 
  23.          
  24.         System.out.println(node1.next.data); 
  25.          
  26.         node1.next = node2; 
  27.         node4.next = null
  28.          
  29.         System.out.println(node1.next.data); 
  30.     } 


3、循环链表

双向循环列表

[java] view plaincopyprint?
  1. public class Node2 
  2.     Node2 previous; 
  3.     Node2 next; 
  4.     String data; 
  5.      
  6.     public Node2(String s) 
  7.     { 
  8.         data = s; 
  9.     } 
  10.  
  11. public class NodeTest2 
  12.     public staticvoid main(String[] args) 
  13.     { 
  14.         Node2 node1 = new Node2("node1"); 
  15.         Node2 node2 = new Node2("node2"); 
  16.         Node2 node3 = new Node2("node3"); 
  17.          
  18.         node1.next =node2; 
  19.         node1.previous = node3; 
  20.         node2.next =node3; 
  21.         node2.previous = node1; 
  22.         node3.next = node1; 
  23.         node3.previous = node2; 
  24.         //在node1和node2之间插入node4 
  25.         Node2 node4 = new Node2("node4"); 
  26.          
  27.         node1.next = node4; 
  28.         node4.previous =node1; 
  29.          
  30.         node2.previous =node4; 
  31.         node4.next =node2; 
  32.          
  33.         System.out.println("--------------"); 
  34.         //删除node4 
  35.         node1.next = node2; 
  36.         node2.previous =node1; 
  37.          
  38.         node4.next =null
  39.         node3.previous =null
  40.          
  41.          
  42.     } 


4、LinkedList源代码分析:LinkedList底层就是使用了双向循环链表实现

[java] view plaincopyprint?
  1. //先定义两个成员变量 
  2. private transient Entry<E> header =new Entry<E>(null,null, null); 
  3. private transientint size = 0
  4. //默认构造函数 
  5. public LinkedList() { 
  6.         header.next = header.previous = header; 
  7.     } 

看一下Entry:

[java] view plaincopyprint?
  1. private staticclass Entry<E> { 
  2.     E element; 
  3.     Entry<E> next; 
  4.     Entry<E> previous; 
  5.  
  6.     Entry(E element, Entry<E> next, Entry<E> previous) { 
  7.         this.element = element; 
  8.         this.next = next; 
  9.         this.previous = previous; 
  10.     } 
  11.     } 


它的定义就像Node2,有一个存放数据的成员变量element,还各有一个指向前驱和后继Entry的指针previous和next。

关于add()方法,参数是一个Object对象,作为Entry的element值

[java] view plaincopyprint?
  1. public boolean add(E e) { 
  2.     addBefore(e, header); 
  3.         return true
  4.     } 
  5.  
  6. private Entry<E> addBefore(E e, Entry<E> entry) { 
  7.     Entry<E> newEntry = new Entry<E>(e, entry, entry.previous); 
  8.     newEntry.previous.next = newEntry; 
  9.     newEntry.next.previous = newEntry; 
  10.     size++; 
  11.     modCount++; 
  12.     return newEntry; 
  13.     } 

add()方法默认调用addBefore()方法插入一个新的节点,addBefore看其字面意思,就是在指定的节点之前插入,而其参数默认为e和header,e是要保存的数据,header是链表的头节点,按照上面的图,头节点的前驱就是链表的最后一个节点,所以插入默认是插入到链表最后。addBefore方法先构建一个新的Entry节点,根据其参数,这个新节点的element=e,next=entry,(也就是header),previous=entry.previous,(也就是header.previous)。然后修改原来最后一个节点的后继指向新节点:newEntry.previous.next = newEntry;然后在修改原来的头节点的前驱指向新节点:newEntry.next.previous = newEntry;

5、关于ArrayList与LinkedList的比较分析

1)ArrayList底层采用数组实现,LinkedList底层采用双向链表实现。

2)当执行插入或删除操作时,采用LinkedList比较好。

3)当执行搜索操作时,采用ArrayList比较好。

6、list的删除操作只删除找到匹配的第一个节点,如linkedlist.add("aaa");linkedlist.add("aaa");删除时,remove("aaa")只删除第一个找到的aaa节点。

在get()方法取第n个元素时,调用了entry()方法,这个方法使用了一个优化性能的算法,先判断n是否大于链表元素个数的二分之一,如果不大于,说明距离头节点比较近,从头开始先后遍历寻找,否则说明距离末节点比较近,从尾部开始向前遍历寻找。

7、当向ArrayList添加一个对象时,实际上就是将该对象放置到了ArrayList底层所维护的数组当中;当向LinkedList中添加一个对象时,实际上LinkedList内部会生成一个Entry对象,该对象的结构为:

Entry

{

Entry previous;

Object element;

Entry next;

}

其中的Object类型的元素element就是我们向LinkedList中所添加的元素,然后Entry又构造好了向前与向后的引用previous、next,最后将生成的这个Entry对象加入到了链表当中。换句话说,LinkedList中所维护的是一个个的Entry对象。

0 0
原创粉丝点击