JAVA数据结构--LinkedList双向链表

Posted 三分自留地

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }

 

以上是关于JAVA数据结构--LinkedList双向链表的主要内容,如果未能解决你的问题,请参考以下文章

Java集合四LinkedList

恋上数据结构 双向链表(JDK-LinkedList底层)

Java 集合深入理解 :LinkedList链表源码研究,及双向队列如何实现

Java集合试读LinkedList源码

JAVA容器-模拟LinkedList实现(双链表)

6.Java集合-LinkedList实现原理及源码分析