1. 程式人生 > 實用技巧 >2010_線性表之連結串列之雙向連結串列

2010_線性表之連結串列之雙向連結串列

2.2.2 雙向連結串列

2.2.2.1 API設計

類名 Node
構造器 Node(T t, Node pre, Node next)
成員變數 T item;儲存資料
Node next;指向下一個結點
Node pre;指向上一個結點

雙向連結串列API與單向連結串列一致, 新增如下方法

public T getFirst()獲取第一個元素
public T getLast();獲取最後一個元素

2.2.2.2 程式碼實現

package b_linear.b_linkedlist;

import java.util.Iterator;

public class TwoWayLinkList<T> implements Iterable{
    //成員變數
    private Node<T> head;
    private Node<T> last;
    private int n;




    //成員內部類
    private class Node<T> {
        //成員變數: 儲存元素
        public T item;
        //下一個結點
        public Node next;
        public Node pre;

        public Node(T item, Node pre, Node next) {
            this.item = item;
            this.pre = pre;
            this.next = next;
        }
    }

    //構造器
    public TwoWayLinkList() {
        //初始化頭結點
        this.head = new Node(null, null, null);
        //初始化尾結點
        this.last = null;

        //初始化元素個數
        this.n = 0;
    }

    //成員方法
    //清空
    public void clear() {
        this.head.next = null;
        this.last = null;
        this.n = 0;
    }

    //獲取長度,即元素個數
    public int length() {
        return this.n;
    }

    //是否為空
    public boolean isEmpty() {

        return this.n == 0;
    }

    //獲取第一個元素
    public T getFirst() {
        if (isEmpty()) {
            return null;
        }
        return (T) this.head.next.item;
    }

    //獲取最後一個元素
    public T getLast() {
        if (isEmpty()) {
            return null;
        }
        return this.last.item;
    }

    //獲取元素
    public T get(int i) {
        //通過迴圈, 從頭結點開始往後, 依次找到i位置
        Node<T> node = head.next;
        for (int index = 0; index < i; index++) {
            node = node.next;
        }
        return node.item;
    }

    //新增元素
    public void insert(T t) {
        //如果連結串列為空
        if (isEmpty()) {
            //建立新結點
            Node newNode = new Node(t, head, null);
            //新結點成為尾結點
            last = newNode;
            //頭結點指向尾結點
            head.next = last;
        } else {
            //如果不為空
            Node oldLast = last;
            //建立新結點
            Node newNode = new Node(t, oldLast, null);

            //當前尾結點指向尾結點
            oldLast.next = newNode;

            //新結點成為尾結點
            last = newNode;
        }
        //元素個數加1
        this.n++;
    }

    //指定位置新增元素
    public void insert(int i, T t) {
        //找到i位置的前一個結點
        Node pre = head;
        for (int index = 0; index < i; index++) {
            pre = pre.next;
        }
        //找到i位置的結點
        Node curr = pre.next;

        //建立新結點
        Node newNode = new Node(t, pre, curr);

        //讓i位置的前結點的下一個結點為新結點
        pre.next = newNode;
        //i位置的前一個結點變為新結點
        curr.pre= newNode;

        //元素個數加 1
        this.n++;
    }

    //刪除i位置處的元素
    public T remove(int i) {
        //找到i前一個位置的結點
        Node<T> pre = head;
        for (int index = 0; index <= i - 1; index++) {
            pre = pre.next;
        }
        //找到i位置的結節
        Node<T> curr = pre.next;
        //找到i位置下一個結點
        Node<T> nextNode = curr.next;
        //前一個節點指向下一個結點
        pre.next = nextNode;
        //下一個結點指向前一個結點
        nextNode.pre = pre;

        //元素個數一1
        this.n--;
        return curr.item;
    }

    //查詢元素首次出現位置
    public int indexOf(T t) {
        //從頭結點開始, 依次找出每一個結點, 取出item與t比較, 如果相迥找到了
        Node<T> node = head;
        for (int i = 0; node.next != null; i++) {
            node = node.next;
            if (node.item.equals(t)) {
                return i;
            }
        }
        return -1;
    }


    @Override
    public Iterator iterator() {
        return new TIterator();
    }
    private class TIterator implements Iterator {
        private Node node;
        public TIterator() {
            this.node = head;
        }
        @Override
        public boolean hasNext() {
          return node.next != null;
        }

        @Override
        public Object next() {
            node = node.next;
            return node.item;
        }
    }
}

2.2.2.3 測試

package b_linear.b_linkedlist;

/**
 * 雙向連結串列測試
 */
public class TwoWayLinkListTest {
    public static void main(String[] args) {
        //建立物件
        TwoWayLinkList<String> s1 = new TwoWayLinkList<>();
        //插入
        s1.insert("姚明");
        s1.insert("科比");
        s1.insert("麥迪");
        s1.insert(1, "詹姆斯");

        for(Object s : s1) {
            System.out.println((String)s);
        }
        System.out.println("-----");

        System.out.println("第一個: " + s1.getFirst() );
        System.out.println("最後一個: " + s1.getLast() );

        //獲取
        String getResult = s1.get(1);
        System.out.println(getResult);

        //刪除
        String removeResult = s1.remove(0);
        System.out.println(removeResult);


        //清空
        s1.clear();
        System.out.println("清空後的元素個數: " + s1.length());

    }
}

2.2.3 連結串列複雜度分析

  1. get(int i)方法 複雜度為O(n)
  2. inser(int i, T t); 複雜度為O(n)
  3. remove(int i); 複雜度為O(n)

增刪有優勢, 初始化時不需要指定長度.

2.2.4 連結串列反轉

  1. 實現

     //連結串列反轉
     public void reverse(){
         if(isEmpty()) {
             return;
         }
         reverse(head.next);
     }
     public Node reverse(Node curr) {
         if(curr.next == null) {
             head.next = curr;
             return curr;
         }
         //遞迴反轉curr下一個結點, 返回值為當前結點的上一個結點
         Node pre = reverse(curr.next);
         //返回的結點的下一個結點變為前結點curr
         pre.next = curr;
         //當前結點的下一個結點變為null
         curr.next = null;
         return curr;
     }
    
  2. 測試

    package b_linear.b_linkedlist;

    /**

    • 單向連結串列測試
      */
      public class LinkListTest2 {
      public static void main(String[] args) {
      //建立物件
      LinkList s1 = new LinkList<>();
      //插入
      s1.insert("姚明");
      s1.insert("科比");
      s1.insert("麥迪");
      s1.insert(1, "詹姆斯");

       for(Object s : s1) {
           System.out.println((String)s);
       }
       System.out.println("-----");
      
       //反轉
       s1.reverse();
       for(Object s : s1) {
           System.out.println((String)s);
       }
      

      }
      }

測試結果

姚明
詹姆斯
科比
麥迪
-----
麥迪
科比
詹姆斯
姚明