zoukankan      html  css  js  c++  java
  • 数据结构之--双链表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 }
  • 相关阅读:
    【笔记】黄如花.信息检索.学习心得
    【心得】Lattice和Xilinx工具关键特性对比(Diamond、ISE)
    【导航】FPGA相关
    【笔记】黄如花.信息检索.前4章心得(新增大牛汇总的公开课资源)
    python正则表达式练习题
    python正则表达式(1)--特殊字符
    【转】什么时候 i = i + 1 并不等于 i += 1?
    Linux查看文件指定行数内容
    python mysqldb批量执行语句executemany
    linux命令行常用快捷键
  • 原文地址:https://www.cnblogs.com/OliverZhang/p/6610981.html
Copyright © 2011-2022 走看看