《java數據結構》--鏈表

java數據結構

參考:數組、單鏈表和雙鏈表介紹 以及 雙向鏈表的C/C++/Java實現

主要有以下幾種類型

  • 單向鏈表
  • 雙端鏈表
  • 有序鏈表
  • 雙向鏈表
  • 有迭代器的鏈表

鏈表的效率

這裏順便談下鏈表和數組相比效率的優越性.在表頭插入和刪除的速度都很快,因爲只需要改變一下引用所以花費O(1)的時間.

平均起來查找,刪除和在指定節點後插入數據都需要搜索一半的鏈結點.需要O(N)次比較和數組一樣.然由於鏈表刪除插入的時候

不需要像數組那種元素的移動.所以效率還是要優於數組.

還有一點就是鏈表的內存可以隨時的擴展內存.而數組的內存是一開始就固定好的.這樣就會導致數組的效率和可用性大大下降.

鏈表劣勢在於隨機訪問,無法像數組那樣直接通過下標找到特定的數據項 

java代碼實現

單向鏈表

image

package cn.zlz.structure;

/**
 * 單向鏈表 持有一個首部節點,可以實現棧,後進先出
 */
public class LinkedList<V> {

    // 鏈表頭部
    private Node first;
    // 長度
    private int size;

    public LinkedList() {
        super();
    }

    // 首部插入新的節點
    public Node<V> insertFirst(V value) {
        Node<V> node = new Node<V>(value);
        // 新節點的next指向老節點
        node.setNext(first);
        first = node;
        // 長度+1
        size++;
        return node;
    }

    // 獲取指定位置節點
    public Node<V> get(int index) {
        if (this.isEmpty()) {
            throw new IndexOutOfBoundsException("鏈表爲空");
        }
        if (index >= size) {
            throw new IndexOutOfBoundsException("越界");
        }
        Node node = first;
        while (index-- > 0) {
            node = node.getNext();
        }
        return node;
    }

    // 刪除指定位置節點
    public Node<V> remove(int index) {
        if (this.isEmpty()) {
            throw new IndexOutOfBoundsException("鏈表爲空");
        }
        if (index >= size) {
            throw new IndexOutOfBoundsException("越界");
        }
        // 待刪除節點
        Node<V> removeNode = null;
        // 待刪除節點的上個節點
        Node<V> pre = null;
        if (index == 0) {
            // 沒有上個節點
            pre = null;
            removeNode = first;
            first = removeNode.next;
        } else {
            pre = this.get(index - 1);
            // 已通過長度驗證pre.next存在
            removeNode = pre.next;
            pre.next = removeNode.next;
        }
        if (--size <= 0) {
            first = null;
        }
        return removeNode;
    }

    // 判斷linkList是否爲空
    public boolean isEmpty() {
        return first == null;
    }

    // 獲取鏈表長度
    public int getSize() {
        return size;
    }

    @Override
    public String toString() {
        if (first == null) {
            return "LinkedList ";
        }
        return "LinkedList [" + first.toString() + "]";
    }

    // 節點類
    class Node<V> {
        private V value;
        private Node next;

        public Node() {
            super();
        }

        public Node(V value) {
            super();
            this.value = value;
        }

        public V getValue() {
            return value;
        }

        public void setValue(V value) {
            this.value = value;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }

        @Override
        public String toString() {
            return "Node [value=" + value + ", next=" + next + "]";
        }

    }

    // 測試
    public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<String>();
        linkedList.insertFirst("a");
        linkedList.insertFirst("b");
        linkedList.insertFirst("c");
        linkedList.insertFirst("d");
        linkedList.insertFirst("e");
        linkedList.insertFirst("f");
        System.out.println(linkedList.toString());
        LinkedList<String>.Node<String> node = linkedList.get(2);
        System.out.println(node.getValue());
        LinkedList<String>.Node<String> removeNode = linkedList.remove(0);
        System.out.println(linkedList.toString());
        System.out.println(node.getValue());

    }
}

雙端單向鏈表

image

package cn.zlz.structure;

/**
 * 雙端單向鏈表 持有一個首部節點引用和尾部節點引用,可以實現隊列,先進先出
 * 
 * 雙端鏈表與傳統鏈表非常相似.只是新增了一個屬性-即對最後一個鏈結點的引用,單向鏈表只能從首部開始操作,雙端鏈表首尾都可以
 */
public class DbPortLinkedList<V> {

    // 鏈表頭部
    private Node first;
    // 鏈表尾部
    private Node last;
    // 長度
    private int size;

    public DbPortLinkedList() {
        super();
    }

    // 首部添加新的節點
    public Node<V> insertFirst(V value) {
        Node<V> node = new Node<V>(value);
        // 新節點的next指向老節點
        if (this.isEmpty()) {
            last = node;
        }
        node.setNext(first);
        first = node;
        // 長度+1
        size++;
        return node;
    }

    // 尾部添加新的節點
    public Node<V> insertLast(V value) {
        Node<V> node = new Node<V>(value);
        // 新節點的next指向老節點
        if (this.isEmpty()) {
            first = node;
            last = node;
            return node;
        }
        last.setNext(node);
        last = node;
        // 長度+1
        size++;
        return node;
    }

    // 獲取指定位置節點
    public Node<V> get(int index) {
        if (this.isEmpty()) {
            throw new IndexOutOfBoundsException("鏈表爲空");
        }
        if (index >= size) {
            throw new IndexOutOfBoundsException("越界");
        }
        Node node = first;
        while (index-- > 0) {
            node = node.getNext();
        }
        return node;
    }

    // 刪除指定位置節點
    public Node<V> remove(int index) {
        if (this.isEmpty()) {
            throw new IndexOutOfBoundsException("鏈表爲空");
        }
        if (index >= size) {
            throw new IndexOutOfBoundsException("越界");
        }
        // 待刪除節點
        Node<V> removeNode = null;
        // 待刪除節點的上個節點
        Node<V> pre = null;
        if (index == 0) {
            // 沒有上個節點
            pre = null;
            removeNode = first;
            first = removeNode.next;
        } else {
            pre = this.get(index - 1);
            // 已通過長度驗證pre.next存在
            removeNode = pre.next;
            pre.next = removeNode.next;
        }
        // 長度-1,並驗證鏈表是否爲空
        if (--size <= 0) {
            first = null;
            last = null;
        }
        return removeNode;
    }

    // 判斷linkList是否爲空
    public boolean isEmpty() {
        return first == null && last == null;
    }

    // 獲取鏈表長度
    public int getSize() {
        return size;
    }

    @Override
    public String toString() {
        if (first == null) {
            return "DbPortLinkedList ";
        }
        return "DbPortLinkedList [" + first.toString() + "]";
    }

    // 節點類
    class Node<V> {
        private V value;
        private Node next;

        public Node() {
            super();
        }

        public Node(V value) {
            super();
            this.value = value;
        }

        public V getValue() {
            return value;
        }

        public void setValue(V value) {
            this.value = value;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }

        @Override
        public String toString() {
            return "Node [value=" + value + ", next=" + next + "]";
        }

    }

    // 測試
    public static void main(String[] args) {
        DbPortLinkedList<String> dbPortLinkedList = new DbPortLinkedList<String>();
        dbPortLinkedList.insertFirst("a");
        dbPortLinkedList.insertFirst("b");
        dbPortLinkedList.insertLast("c");
        dbPortLinkedList.insertFirst("d");
        dbPortLinkedList.insertLast("e");
        dbPortLinkedList.insertFirst("f");
        System.out.println(dbPortLinkedList.toString());
        DbPortLinkedList<String>.Node<String> node = dbPortLinkedList.get(2);
        System.out.println(node.getValue());
        DbPortLinkedList<String>.Node<String> removeNode = dbPortLinkedList.remove(0);
        System.out.println(dbPortLinkedList.toString());
        System.out.println(removeNode.getValue());

    }
}

有序鏈表

package cn.zlz.structure;

/**
 * 有序單向鏈表:鏈表中的數據按從小到大排列 持有一個首部節點
 * 有序鏈表插入數據效率爲O(N),但查找跟刪除最大數據就是表頭數據效率爲O(1).所以在最小數據存儲頻繁,但又不需要快速插入的時候有序鏈表是個不錯的選擇.
 */
public class SortedLinkedList {

    // 鏈表頭部
    private Node first;
    // 長度
    private int size;

    public SortedLinkedList() {
        super();
    }

    // 首部插入新的節點
    public Node insertFirst(Integer value) {
        Node node = new Node(value);

        // 查找位置,即找到前面一個節點和後面一個節點
        Node pre = null;//插入位置前面節點
        Node current = first;//插入位置後面節點
        while (current != null && current.getValue()<value) {
            pre = current;
            current=current.next;
        }
        //最小的,插在第一個位置
        if(pre == null){
            first = node;
        }else{
            pre.next = node;
        }
        //新插入的節點不管怎麼next都指向當前節點
        node.next = current;
        // 長度+1
        size++;
        return node;
    }

    // 獲取指定位置節點
    public Node get(int index) {
        if (this.isEmpty()) {
            throw new IndexOutOfBoundsException("鏈表爲空");
        }
        if (index >= size) {
            throw new IndexOutOfBoundsException("越界");
        }
        Node node = first;
        while (index-- > 0) {
            node = node.getNext();
        }
        return node;
    }

    // 刪除指定位置節點
    public Node remove(int index) {
        if (this.isEmpty()) {
            throw new IndexOutOfBoundsException("鏈表爲空");
        }
        if (index >= size) {
            throw new IndexOutOfBoundsException("越界");
        }
        // 待刪除節點
        Node removeNode = null;
        // 待刪除節點的上個節點
        Node pre = null;
        if (index == 0) {
            // 沒有上個節點
            pre = null;
            removeNode = first;
            first = removeNode.next;
        } else {
            pre = this.get(index - 1);
            // 已通過長度驗證pre.next存在
            removeNode = pre.next;
            pre.next = removeNode.next;
        }
        if (--size <= 0) {
            first = null;
        }
        return removeNode;
    }

    // 判斷linkList是否爲空
    public boolean isEmpty() {
        return first == null;
    }

    // 獲取鏈表長度
    public int getSize() {
        return size;
    }

    @Override
    public String toString() {
        if (first == null) {
            return "SortedLinkedList ";
        }
        return "SortedLinkedList [" + first.toString() + "]";
    }

    // 節點類
    class Node {
        private int value;
        private Node next;

        public Node() {
            super();
        }

        public Node(int value) {
            super();
            this.value = value;
        }

        public int getValue() {
            return value;
        }

        public void setValue(int value) {
            this.value = value;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }

        @Override
        public String toString() {
            return "Node [value=" + value + ", next=" + next + "]";
        }

    }

    // 測試
    public static void main(String[] args) {
        SortedLinkedList sortedLinkedList = new SortedLinkedList();
        sortedLinkedList.insertFirst(4);
        sortedLinkedList.insertFirst(2);
        sortedLinkedList.insertFirst(3);
        sortedLinkedList.insertFirst(5);
        System.out.println(sortedLinkedList);
    }
}

雙向鏈表

image
image
image

package cn.zlz.structure;

/**
 * 雙向鏈表,注意畫圖來看
 * 注意:雙向鏈表需要初始化一個header頭,但是這個header頭不屬於鏈表的一個元素
 */
public class DbLinkedList<V> {

    // 鏈表頭部
    private Node header;
    // 長度
    private int size;

    public DbLinkedList() {
        super();
        //創建表頭
        this.header = new Node(null, null, null);
        //表頭自循環
        this.header.next = this.header;
        this.header.pre = this.header;
    }

    // 首部添加新的節點
    public Node<V> insert(int index,V value) {
        if (index > size) {
            throw new IndexOutOfBoundsException("越界");
        }
        Node<V> current = null ;
        if(size == 0){
            current = this.header;
        }else{
            current = get(index);
        }
        Node<V> node = new Node<V>(value,current.pre,current);
        node.pre.next = node;
        node.next.pre = node;
        // 長度+1
        size++;
        return node;
    }
    public Node<V> insertFirst(int index,V value) {
        return this.insert(0, value);
    }
    public Node<V> insertLast(int index,V value) {
        //面向對象
        Node<V> node = new Node<V>(value,this.header.pre,this.header);
        node.pre.next = node;
        node.next.pre = node;
        // 長度+1
        size++;
        return node;
    }
    // 首部添加新的節點
    //注意:雙向鏈表中的元素不包括header
    public Node<V> get(int index) {
        if (size==0 || index > size) {
            throw new IndexOutOfBoundsException("越界");
        }
        Node<V> node = null;
        //如果是後半從後往前找
        if(index>(size)/2){
            System.out.println("從後往前找");
            //header不屬於鏈表,所以z最後一個是插入中的一個。
            node = this.header.pre;
            int round = size-index;
            while (round-->=0) {
                node = node.pre;
            }
        }else{//從前往後找
            System.out.println("從前往後找");
            //header不屬於鏈表,所以第一個是header的next,插入的時候對0單獨處理了,執行get的時候至少已經插入一條
            node = this.header.next;
            while (index-->0) {
                node = node.next;
            }
        }
        return node;
    }

    public Node<V> remove(int index){
        if (size==0 || index > size-1) {
            throw new IndexOutOfBoundsException("越界");
        }
        Node<V> toDelNode = this.get(index);
        toDelNode.pre.next = toDelNode.next;
        toDelNode.next.pre = toDelNode.pre;
        size--;
        return toDelNode;
    }

    // 獲取鏈表長度
    public int getSize() {
        return size;
    }

    // 判斷linkList是否爲空
    public boolean isEmpty() {
        return size == 0;
    }

    public Node getHeader() {
        return header;
    }

    public void setHeader(Node header) {
        this.header = header;
    }

    public void setSize(int size) {
        this.size = size;
    }

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        Node header = this.getHeader();
        Node next = header.getNext();
        stringBuilder.append(header.getPre().getValue()+":"+header.getValue()+":"+header.getNext().getValue());
        while(next!=header){
            stringBuilder.append("   ");
            stringBuilder.append(next.getPre().getValue()+":"+next.getValue()+":"+next.getNext().getValue());
            next = next.next;
        }
        return stringBuilder.toString();
    }

    // 節點類
    class Node<V> {
        private V value;// 值
        private Node pre;// 前一個節點
        private Node next;// 後一個節點

        public Node() {
            super();
        }

        public Node(V value, Node pre, Node next) {
            super();
            this.value = value;
            this.pre = pre;
            this.next = next;
        }

        public Node(V value) {
            super();
            this.value = value;
        }

        public V getValue() {
            return value;
        }

        public void setValue(V value) {
            this.value = value;
        }

        public Node getPre() {
            return pre;
        }

        public void setPre(Node pre) {
            this.pre = pre;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }

        @Override
        public String toString() {
            return "Node [value=" + value + ", pre=" + pre + ", next=" + next + "]";
        }

    }

    // 測試
    public static void main(String[] args) {
        DbLinkedList<String> dbLinkedList = new DbLinkedList<String>();
        System.out.println(dbLinkedList.toString());
        dbLinkedList.insert(0,"a");
        System.out.println(dbLinkedList.toString());
        dbLinkedList.insert(1,"b");
        System.out.println(dbLinkedList.toString());
        dbLinkedList.insert(2,"b");
        System.out.println(dbLinkedList.toString());
        dbLinkedList.insert(1,"c");
        System.out.println(dbLinkedList.toString());
        dbLinkedList.insert(4,"d");
        System.out.println(dbLinkedList.toString());
        dbLinkedList.insert(0,"e");
        System.out.println(dbLinkedList.toString());
        System.out.println(dbLinkedList.get(3).getValue());
//      dbLinkedList.insertFirst("f");
        System.out.println(dbLinkedList.toString());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章