数据结构之--双链表MyLinkedList

  双链表的手动实现中考虑三个类的实现:

1、MyLinkedList类本身的实现,包含到两端的链、表的大小以及一些方法。

2、Node节点,它可能是一个私有的内部嵌套类,这个类,嵌套在MyLinkedList的内部,数据域:data,前驱指针prev和后继指针next,以及合适的构造方法

3、LinkedListIterator类,该类抽象了位置的概念,是一个实现了Iterator接口的私有类,它提供了next、hashNext和remove等方法。于我而言这个迭代器的实现感觉比较的有收获。主要注意要实现的是:我们在使用迭代器件,确保链表集合中的元素不会被用户越过迭代器而修改。都有过这样的经历:在java中执行迭代操作的过程中,比如

1 LinkedList <Integet> kist = new LinkedList<Integer>();
2 ……
3 Iterator<Integer> it = list.iterator();
4 while(it.hasNext())
5 {
6     syso(it.next);
7     list.remove(1);// 这里就会报错,这里面有一套保护机制,确保在使用迭代期间不允许使用集合和修改内部元素
8    it.remove();       // 这样同通过迭代器的修改是允许的
9 }

主要实现上面的保护机制。其实就是一个维护一个互斥变量的感觉。

具体的实现代码如下:

  1 import java.util.Iterator;
  2 
  3 import org.omg.CORBA.Any;
  4 
  5 /**
  6  * 自己手动实现一个 LinkedList
  7  * 基于双向链表,其中,私有嵌套定义双向链表的节点
  8  * 注意了我哥双向链表,n个元素记做1~n,标准库中记为0~n-1
  9  * @author Administrator
 10  *
 11  */
 12 public class MyLinkedList <AnyType> implements Iterable<AnyType>{
 13     private int theSize;    //双向链表中的元素个数
 14     private int modCount;    //这个标记为了配合Iterator实现修改的保护,这一点后面专做论述,凡是做了增删修改,这个标记均变化
 15     private Node<AnyType> beginMarker;    // 双向链表的开始标记
 16     private Node<AnyType> endMarker;    //双向链表的尾部标记
 17     
 18     public MyLinkedList()
 19     {
 20         // 构造函数 先初始化双向聊表 调动 clear()函数
 21         clear();
 22     }
 23     public void clear()
 24     {// 确保双向链表处于空的状态 ----> 我们使用一个辅助的头结点
 25         // 头标记和尾标记 指向同一个 辅助头结点,和一个辅助的尾节点
 26         beginMarker = new Node<AnyType>(null, null, null);
 27         endMarker   = new Node<AnyType>(null, beginMarker, null);
 28         beginMarker.next = endMarker;
 29         
 30         theSize = 0;
 31         modCount ++;    //zhege
 32     }
 33     
 34     // 获取元素的个数
 35     public int size()
 36     {
 37         return theSize;
 38     }
 39     
 40     // 判断是否为空
 41     public boolean isEmpty()
 42     {
 43         return theSize == 0;
 44     }
 45     
 46     
 47     /*
 48      * 增删查改的操作
 49      */
 50     // 默认把元素插入到尾部,其中调用插入到指定位置的函数
 51     public boolean add(AnyType x)
 52     {
 53         add(size()+1, x);
 54         return true;
 55     }
 56     // 把元素插入到指定位置,其中调用插入到指定元素之前 函数
 57     public void add(int idx, AnyType x)
 58     {
 59         addBefore(getNode(idx), x);
 60     }
 61     // 重置某个节点的data值,并返回以前的 data值
 62     public AnyType set(int idx, AnyType newVal)
 63     {
 64         if(idx <1 || idx >size())
 65             throw new RuntimeException(new Exception("下表越界"));
 66         Node<AnyType> p = getNode(idx);
 67         AnyType oldVal = p.data;
 68         p.data = newVal;
 69         return oldVal;
 70     }
 71     // 删除第idx个节点,调用remove(Node)函数,返回删除节点的data值
 72     public AnyType remove(int idx)
 73     {
 74         if(idx <1 || idx >size())
 75             throw new RuntimeException(new Exception("下表越界"));
 76         return remove(getNode(idx));
 77     }
 78     
 79     
 80     
 81     /*
 82      * 下面这些函数都是一些private的都是位别的一些函数服务的
 83      */
 84     // 在p前面插入 x 元素
 85     private void addBefore(Node<AnyType>p, AnyType x)
 86     {
 87         Node<AnyType> newNode = new Node<AnyType>(x, p.prev, p);
 88         newNode.prev.next = newNode;
 89         p.prev = newNode;
 90         theSize ++;        //添加进来一个新元素之后,别忘了元素个数++
 91         modCount ++;    //无论增删 该标志 均++
 92     }
 93     // 获取 idx处的 节点引用
 94     private Node<AnyType> getNode(int idx)
 95     {
 96         if(idx < 1 || idx > size()+1)// 考虑在尾部插入的情况,如果取这个尾节点,其data = null
 97             throw new RuntimeException(new Exception("索引越界"));
 98         Node<AnyType> p = null;
 99         if( idx <= size()/2)    // 在前半边中找
100         {
101             p = beginMarker.next;
102             for( int i = 1; i < idx; i++)
103                 p = p.next;
104         }else{    //在后半边中找
105             p = endMarker;
106             for(int i = size(); i >= idx; i--)
107                 p = p.prev;
108         }
109         
110         return p;
111     }
112     // 返回 删除某个节点,并返回这个节点的data值
113     private AnyType remove(Node<AnyType> p)
114     {
115         p.prev.next = p.next;
116         p.next.prev = p.prev;
117         theSize --;
118         modCount --;
119         return p.data;
120     }
121     
122     
123     /*
124      * 实现迭代器
125      */
126     public Iterator<AnyType> iterator()
127     {
128         return new LinkedListIterator();
129     }
130     //实现迭代器
131     private class LinkedListIterator implements Iterator<AnyType>
132     {
133         private Node<AnyType> current = beginMarker.next;    //记住当前的位置,这和书序表中类似
134         private int expectedModCount = modCount;
135         private boolean okToRemove = false;
136         
137         @Override
138         public boolean hasNext() {
139             // TODO Auto-generated method stub
140             return current!=endMarker;
141         }
142 
143         @Override
144         public AnyType next() {
145             // 注意了 下面的 保护迭代期间 不允许 越过迭代器修改集合元素的 机制 是精髓
146             if(modCount != expectedModCount)
147                 throw new RuntimeException(new Exception("您刚刚越过迭代器修改了集合元素"));
148             if(!hasNext())
149                 throw new RuntimeException(new Exception("已经没有元素了"));
150                 
151             AnyType nextItem = current.data;
152             current = current.next;
153             okToRemove = true;
154             return nextItem;
155         }
156 
157         @Override
158         public void remove() {
159             // TODO Auto-generated method stub
160             if(modCount != expectedModCount)
161                 throw new RuntimeException(new Exception("您刚刚越过迭代器修改了集合元素"));
162             if(!okToRemove)
163                 throw new RuntimeException(new Exception("先next再删除"));
164             
165             MyLinkedList.this.remove(current.prev);
166             okToRemove = false;    // 与next()中的 okToRemove = false; 遥相呼应,以确保必须在next()之后才能remove
167             expectedModCount ++;    
168         }
169         
170     }
171     
172     /*
173      * 私有嵌套类的形式,定义内部节点,节点里面没有访问双向链表中的内容,所以使用私有嵌套类可也
174      * 如果访问了外面类的属性或者方法就只能使用内部类,去除static关键字,内部类的使用主要是为了可以简写,见单链表中的介绍
175      */
176     private static class Node<AnyType>{
177         // 构造函数
178         public Node(AnyType d, Node<AnyType>p, Node<AnyType>n) {
179             data = d; prev = p; next = n;
180         }
181         
182         public AnyType data;
183         public Node<AnyType> prev;
184         public Node<AnyType> next;
185     }
186     
187     public static void main(String[] args) {
188         MyLinkedList<Integer> list= new MyLinkedList<Integer>();
189         
190         System.out.println("size : "+list.size());
191         System.out.println("empty : "+list.isEmpty());
192         list.add(1);
193         list.add(2);
194         list.add(4);
195         list.add(3, 3);
196         System.out.println("size : "+list.size());
197         System.out.println("empty : "+list.isEmpty());
198         
199         list.set(4, 5);
200         
201         System.out.println("dlete 4th elements :"+list.remove(4));
202         System.out.println("size : "+list.size());
203     }
204 }

 

    原文作者:zhangoliver
    原文地址: https://www.cnblogs.com/OliverZhang/p/6610981.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞