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 }
时间: 2024-08-03 21:54:48

JAVA数据结构--LinkedList双向链表的相关文章

I学霸官方免费教程三十六:Java数据结构之双向链表结构

数据结构之双向链表 例如:现有双向链表TwoWayLinked中存储着1,2,3,4四个元素,那么集合对象中会有4个节点A.B.C.D,由上述结构可以知道,节点A中存储着元素1和节点B:节点B中存储着元素2和节点A和节点C,节点C中存储着元素3和节点B和节点D,节点D中存储着元素4和节点C.如果现在要在元素2和3中间插入一个元素5: 过程如下: 1.创建节点E,E中存储元素5 2.将E中的上一个节点赋值为节点B 3.将B中的下一个节点修改为节点E 4.将E中的下一个节点赋值为节点C 5.将C中的

Java数据结构之双向链表

管理单向链表的缺点分析: 单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找. 单向链表不能自我删除,需要靠辅助节点 ,而双向链表,则可以自我删除,所以前面我们单链表删除时节点,总是找到temp,temp是待删除节点的前一个节点. 示意图 对上图的说明: 分析双向链表的遍历.添加.修改.删除的操作思路: 1)遍历:方法和单链表一样,只是可以向前查找,也可以向后查找 2)添加:(默认添加到双向链表的最后) 先找到双向链表的最后的节点 temp.next = newHeroNode;

Java之LinkedList源码解读(JDK 1.8)

java.util.LinkedList 双向链表实现的List. 基于JDK 1.8. 没有使用标准的注释,并适当调整了代码的缩进以方便介绍. 里面很多方法的实现是一样的,不过可以让外界感觉其提供了更多的行为. 需要花比ArrayList更多一点的时间理解 package com.anxpp.thinkinjava.chapter11.sourse; import java.util.AbstractSequentialList; import java.util.Collection; im

Java 的 LinkedList 的底层数据结构

1. 数据结构--LinkedList源码摘要 public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable { transient int size = 0; /** * Pointer to first node. * Invariant: (first == null &

java数据结构与算法之改良顺序表与双链表类似ArrayList和LinkedList(带Iterator迭代器与fast-fail机制)

转载请注明出处(请尊重原创!谢谢~): http://blog.csdn.net/javazejian/article/details/53073995 出自[zejian的博客] 关联文章: java数据结构与算法之顺序表与链表设计与实现分析 java数据结构与算法之双链表设计与实现 java数据结构与算法之改良顺序表与双链表类似ArrayList和LinkedList(带Iterator迭代器与fast-fail机制) ??这篇是数据结构与算法的第3篇,通过前两篇的介绍,对应顺序表和链表已有

Java数据结构之表的增删对比---ArrayList与LinkedList之一

一.Java_Collections表的实现 与c不同Java已经实现并封装了现成的表数据结构,顺序表以及链表. 1.ArrayList是基于数组的实现,因此具有的特点是:1.有索引值方便查找,对于get和set操作花费常数时间,2.但是其缺点是:插入/删除某个数据的代价比较大. 2.LinkedList是基于双链表实现,因此具有的特点是:1.基于链表方便插入与删除操作开销较小,2.但是不方便索引,不管是索引哪一个元素都需要从头开始逐次查找. 就增删操作下面举个简单例子:给出一个表(具体实现未知

java通过LinkedList实现堆栈和队列数据结构

1 package com.shb.java; 2 3 import java.util.LinkedList; 4 5 public class TestLinkedList { 6 7 /** 8 * @author shaobn 9 * @Describe :利用LinkedList实现队列和堆栈 10 * @param args 11 * @Time : 2015-8-27 下午10:28:33 12 */ 13 public static void main(String[] args

java数据结构与算法之双链表设计与实现

转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/53047590 出自[zejian的博客] 关联文章: 关联文章: java数据结构与算法之顺序表与链表设计与实现分析 java数据结构与算法之双链表设计与实现 java数据结构与算法之改良顺序表与双链表类似ArrayList和LinkedList(带Iterator迭代器与fast-fail机制) ??上一篇文章分析顺序表和单链表,本篇就接着上篇继续聊链表,在单链表

【Java数据结构学习笔记之一】线性表的存储结构及其代码实现

应用程序后在那个的数据大致有四种基本的逻辑结构: 集合:数据元素之间只有"同属于一个集合"的关系 线性结构:数据元素之间存在一个对一个的关系 树形结构:数据元素之间存在一个对多个关系 图形结构或网状结构:数据元素之间存在多个对多个的关系 对于数据不同的逻辑结构,计算机在物理磁盘上通常有两种屋里存储结构 顺序存储结构 链式存储结构 本篇博文主要讲的是线性结构,而线性结构主要是线性表,非线性结构主要是树和图. 线性表的基本特征: 总存在唯一的第一个数据元素 总存在唯一的最后一个数据元素 除