手書き古典的な双方向循環リスト

Q:双方向循環リストを書くと、追加、削除、検索

アイデア:リストを開始する場所を知っているので、最初にそこにする必要があり、また、その大きさでどのくらい知っています。リストをリンクされ、すべてのにきびは、私たちが独自の値を持つノード(ノード)を呼び出し、また、ノードと次のノードへの参照に存在し、これらのノードは、我々が一緒に連鎖したい、抗チェーンとチェーン週間です週。

1つの   プライベートノードヘッド。
2      プライベート int型のサイズ= 0 ;
3      プライベート クラスノード{
 4          ノード(E電子){
 5件の              データ= E。
6          }
 7つの         Eデータ、
8          次のノード。
9          ノードPREV。
10      }

 

①まず、追加要素の末尾に書きました

 

 

    //追加元素
    public boolean add(E e) {
        //如果什么都没有
        if(head == null) {
            //把新加进来的节点作为头节点
            head = new Node(e);
            //头节点的下一个是其本身
            head.next = head;
            //头节点的上一个是其本身
            head.prev = head;
        //如果刚开始有节点
        }else {
            Node node = new Node(e);
            //先找到最后一个节点,它就是头节点的上一个节点
            //注意:这是经典的双向循环链表,jdk8后最后一个节点是拿出来作为属性的
            Node last = head.prev;
            //把新加进来的元素链到末尾
            head.prev = node;
            node.prev = last;
            last.next = node;
            node.next = head;
        }
        size++;
        return true;
    }

 

②根据下标找对应的元素,当然,下标也是从0开始的

    //根据下标获取元素
    public E get(int index) {
        if(index < 0 || index > size) throw new IndexOutOfBoundsException("下标越界");
        
        Node node;
        node = find(index);
        return node.data;
            
        }

    //根据下标获取节点
    private Node find(int index) {
        Node node;
        //如果下标小于size的一半,则从头开始找
        if(index < size>>1) {
            node = head;
            for(int i = 0; i < index; i++) {
                node = node.next;
            }
        
        }else {
        //如果下标大于size的一半,则从最后一个开始往前找
        //其实一直是往后找也行,就是太笨了
            node = head.prev;
            for(int i = size - 1; i > index; i--) {
                node = node.prev;
            }
        }
        return node;
    }

 

③add()的重载方法,根据下标和给定的元素插入节点

    //根据下标插入元素e
    public boolean add(int index, E e) {
        
        if(index < 0 || index > size) throw new IndexOutOfBoundsException("下标越界");
        //如果下标等于size,那就是追加元素,调用add方法
        if(index == size) return add(e);
        //先根据下标找到元素,它就是即将要插入的节点的下一个节点
        Node next = find(index);
        //再找到上一个节点
        Node prev = next.prev;
        //准备好新节点
        Node node = new Node(e);
        //把新节点链进来,顺时针走一波,逆时针走一波
        prev.next = node;
        node.next = next;
        next.prev = node;
        node.prev = prev;
        //如果是在头部插入,再多做一个工作,就是把插入的节点作为新的头
        if(index == 0) head = node;
        
        size++;
        
        return true;
    }

 

④根据下标删元素

 

//根据下标删元素
    public E remove(int index) {
        
        if(index < 0 || index >= size) throw new IndexOutOfBoundsException("下标越界");
        //如果就剩个头
        if(size == 1) {
            //取出头节点的值
            E e = head.data;
            //头节点被gc回收掉
            head = null;
            size--;
            //返回取出来的值
            return e;
        }
        //先根据下标找到要删的节点
        Node node = find(index);
        Node prev = node.prev;
        Node next = node.next;
        //把要删的节点晾在一边
        next.prev = prev;
        prev.next = next;
        //下面可写可不写,我们写明显一点,让被删的节点回收掉
        node.next = null;
        node.prev = null;
        //你要是删头节点的话,把下一个节点当做新的头
        if(index == 0) head = next;
        
        size--;
        
        return node.data;
    }
    

 

 

完整代码:

  1 //双向循环链表
  2 public class LinkedList<E> {
  3     private Node head;
  4     private int size = 0;
  5     private class Node{
  6         Node(E e) {
  7             data = e;
  8         }
  9         E data;
 10         Node next;
 11         Node prev;
 12     }
 13     //返回链表大小
 14     public int size() {
 15         return size;
 16     }
 17     //toString()方法
 18     public String toString() {
 19         if(head == null) {
 20             return "[]";
 21         }
 22         StringBuilder buf = new StringBuilder("[");
 23         buf.append(head.data);
 24         
 25         Node node = head.next;
 26         //咱这用的是node和head的关系,当然你也可以用index和size的关系来遍历链表
 27         while(node != head) {
 28             //这里一个逗号一个数据是成对出现的
 29             buf.append(", ").append(node.data);
 30             node = node.next;
 31         }
 32         buf.append("]");
 33         return buf.toString();
 34     }
 35     //根据下标删元素
 36     public E remove(int index) {
 37         
 38         if(index < 0 || index >= size) throw new IndexOutOfBoundsException("下标越界");
 39         //如果就剩个头
 40         if(size == 1) {
 41             //取出头节点的值
 42             E e = head.data;
 43             //头节点被gc回收掉
 44             head = null;
 45             size--;
 46             //返回取出来的值
 47             return e;
 48         }
 49         //先根据下标找到要删的节点
 50         Node node = find(index);
 51         Node prev = node.prev;
 52         Node next = node.next;
 53         //把要删的节点晾在一边
 54         next.prev = prev;
 55         prev.next = next;
 56         //下面可写可不写,我们写明显一点,让被删的节点回收掉
 57         node.next = null;
 58         node.prev = null;
 59         //你要是删头节点的话,把下一个节点当做新的头
 60         if(index == 0) head = next;
 61         
 62         size--;
 63         
 64         return node.data;
 65     }
 66     
 67     //根据下标插入元素e
 68     public boolean add(int index, E e) {
 69         
 70         if(index < 0 || index > size) throw new IndexOutOfBoundsException("下标越界");
 71         //如果下标等于size,那就是追加元素,调用add方法
 72         if(index == size) return add(e);
 73         //先根据下标找到元素,它就是即将要插入的节点的下一个节点
 74         Node next = find(index);
 75         //再找到上一个节点
 76         Node prev = next.prev;
 77         //准备好新节点
 78         Node node = new Node(e);
 79         //把新节点链进来,顺时针走一波,逆时针走一波
 80         prev.next = node;
 81         node.next = next;
 82         next.prev = node;
 83         node.prev = prev;
 84         //如果是在头部插入,再多做一个工作,就是把插入的节点作为新的头
 85         if(index == 0) head = node;
 86         
 87         size++;
 88         
 89         return true;
 90     }
 91     
 92     //追加元素
 93     public boolean add(E e) {
 94         //如果什么都没有
 95         if(head == null) {
 96             //把新加进来的节点作为头节点
 97             head = new Node(e);
 98             //头节点的下一个是其本身
 99             head.next = head;
100             //头节点的上一个是其本身
101             head.prev = head;
102         //如果刚开始有节点
103         }else {
104             Node node = new Node(e);
105             //先找到最后一个节点,它就是头节点的上一个节点
106             //注意:这是经典的双向循环链表,jdk8后最后一个节点是拿出来作为属性的
107             Node last = head.prev;
108             //把新加进来的元素链到末尾
109             head.prev = node;
110             node.prev = last;
111             last.next = node;
112             node.next = head;
113         }
114         size++;
115         return true;
116     }
117     
118     //根据下标获取元素
119     public E get(int index) {
120         if(index < 0 || index > size) throw new IndexOutOfBoundsException("下标越界");
121         
122         Node node;
123         node = find(index);
124         return node.data;
125             
126         }
127 
128     //根据下标获取节点
129     private Node find(int index) {
130         Node node;
131         //如果下标小于size的一半,则从头开始找
132         if(index < size>>1) {
133             node = head;
134             for(int i = 0; i < index; i++) {
135                 node = node.next;
136             }
137         
138         }else {
139         //如果下标大于size的一半,则从最后一个开始往前找
140         //其实一直是往后找也行,就是太笨了
141             node = head.prev;
142             for(int i = size - 1; i > index; i--) {
143                 node = node.prev;
144             }
145         }
146         return node;
147     }
148         
149 }

 

おすすめ

転載: www.cnblogs.com/stoneandatao/p/11258568.html