JAVA数据结构--LinkedList双向链表
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
本文是按照《数据结构与算法分析》一书实现的双向链表的内容,个人认为链表的难点在于插入和删除的操作,但这点也是链表的优势之处。
1 package DataStructures; 2 3 import java.util.ConcurrentModificationException; 4 import java.util.Iterator; 5 import java.util.NoSuchElementException; 6 7 public class MyLinkedList<AnyType> implements Iterable<AnyType> { 8 /* 9 * data当前节点的值 10 * prev当前节点的前缀节点 11 * next当前节点的后缀节点 12 * */ 13 private static class Node<AnyType>{ 14 public Node(AnyType d,Node<AnyType> p,Node<AnyType> n){ 15 data=d; 16 prev=p; 17 next=n; 18 } 19 public AnyType data; 20 public Node<AnyType> prev; 21 public Node<AnyType> next; 22 } 23 public MyLinkedList() { 24 doClear(); 25 // TODO Auto-generated constructor stub 26 } 27 public void clear(){ 28 doClear(); 29 } 30 /* doClear() 31 * 将头结点置空 32 * 尾节点的前缀置为头节点 33 * 头结点的后缀为尾节点 34 * */ 35 private void doClear(){ 36 beginMarker=new Node<AnyType>(null, null, null); 37 endMarker=new Node<AnyType>(null, beginMarker, null); 38 beginMarker.next=endMarker; 39 theSize=0; 40 modCount++; 41 } 42 43 public int size(){ 44 return theSize; 45 } 46 public boolean isEmpty(){ 47 return size()==0; 48 } 49 /* 50 * 在链表尾部插入新节点 51 * */ 52 public boolean add(AnyType x){ 53 add(size(), x); 54 return true; 55 } 56 /* 57 * 在链表中插入新节点 58 * */ 59 public void add(int idx,AnyType x){ 60 addBefore(getNode(idx,0,size()),x); 61 } 62 public AnyType get(int idx){ 63 return getNode(idx).data; 64 } 65 /* 66 * 修改某个节点的值 67 * */ 68 public AnyType set(int idx,AnyType newVal){ 69 Node<AnyType> p=getNode(idx);//p为需要修改的节点 70 AnyType oldVal=p.data; 71 p.data=newVal; 72 return oldVal; 73 } 74 public AnyType remove(int idx){ 75 return remove(getNode(idx)); 76 } 77 78 /* 79 * 在p节点前插入新的节点 80 * */ 81 private void addBefore(Node<AnyType> p,AnyType x){ 82 Node<AnyType> newNode=new Node<>(x, p.prev, p);//新节点的前缀为p的前缀,后缀为p 83 newNode.prev.next=newNode;//新节点的前缀的后缀为新节点 84 p.prev=newNode;//p节点的前缀为p 85 theSize++; 86 modCount++; 87 } 88 private AnyType remove(Node<AnyType> p){ 89 p.next.prev=p.prev; 90 p.prev.next=p.next; 91 theSize--; 92 modCount++; 93 return p.data; 94 } 95 private Node<AnyType> getNode(int idx){ 96 return getNode(idx,0,size()-1); 97 } 98 /* 99 * 获得某个节点 100 * */ 101 private Node<AnyType> getNode(int idx,int lower,int upper){ 102 Node<AnyType> p; 103 if(idx<lower||idx>upper) 104 throw new IndexOutOfBoundsException(); 105 if(idx<size()/2){//如果节点在前半部分,将从头结点向后开始遍历 106 p=beginMarker.next; 107 for(int i=0;i<idx;i++) 108 p=p.next; 109 } 110 else {//如果节点在后半部分,将从尾节点向前遍历 111 p=endMarker; 112 for(int i=size();i>idx;i--) 113 p=p.prev; 114 } 115 return p; 116 } 117 @Override 118 public Iterator<AnyType> iterator() { 119 // TODO Auto-generated method stub 120 return new LinkedListIterator(); 121 } 122 private class LinkedListIterator implements Iterator<AnyType>{ 123 private Node<AnyType> current=beginMarker; 124 private int expectedModCount=modCount; 125 private boolean okToRemove=false; 126 public boolean hasNext(){ 127 return current!=endMarker; 128 } 129 public AnyType next(){ 130 if(modCount!=expectedModCount) 131 throw new ConcurrentModificationException(); 132 if(!hasNext()) 133 throw new NoSuchElementException(); 134 AnyType nextItem=current.data; 135 current=current.next; 136 okToRemove=true; 137 return nextItem; 138 } 139 public void remove(){ 140 if(modCount!=expectedModCount) 141 throw new ConcurrentModificationException(); 142 if(!okToRemove) 143 throw new IllegalStateException(); 144 MyLinkedList.this.remove(current.prev); 145 expectedModCount++; 146 okToRemove=false; 147 } 148 } 149 150 private int theSize;//链表的长度 151 private int modCount;//链表改动的次数 152 private Node<AnyType> beginMarker;//头结点 153 private Node<AnyType> endMarker;//尾节点 154 }