Java基礎數據結構--鏈表

Java基礎數據結構–鏈表


鏈表

鏈表的定義:

鏈表(Linked list)是一種常見的基礎數據結構,是一種線性表,但是並不會按線性的順序存儲數據,而是在每一個節點裏存到下一個節點的指針(Pointer)。由於不必須按順序存儲,鏈表在插入的時候可以達到O(1)的複雜度,比另一種線性表順序表快得多,但是查找一個節點或者訪問特定編號的節點則需要O(n)的時間,而順序表相應的時間複雜度分別是O(logn)和O(1)。

使用鏈表結構可以克服數組鏈表需要預先知道數據大小的缺點,鏈表結構可以充分利用計算機內存空間,實現靈活的內存動態管理。但是鏈表失去了數組隨機讀取的優點,同時鏈表由於增加了結點的指針域,空間開銷比較大。

在計算機科學中,鏈表作爲一種基礎的數據結構可以用來生成其它類型的數據結構。鏈表通常由一連串節點組成,每個節點包含任意的實例數據(data fields)和一或兩個用來指向上一個/或下一個節點的位置的鏈接

鏈表有很多種不同的類型:單向鏈表雙向鏈表以及循環鏈表

鏈表的作用:

用來存儲邏輯地址連序而物理地址不一定連序的數據存儲結構


單鏈表

如下圖:

在這裏插入圖片描述

鏈表類的寫法思路:

1.寫鏈表類,類裏寫節點類
2.數據域,指針域
3.節點類裏,無參構造函數(爲頭節點準備),有參構造函數(爲增加節點準備)
4.頭引用,鏈表類中,無參構造函數裏面寫生成頭結點對象(main中生成鏈表類對象時,頭結點對象就生成了)

代碼實現:
public class TestLink {
    class Node {
        int data;
        Node next;

        public Node() {
            this.data = data;
            this.next = null;
        }

        public Node(int val) {
            this.data = val;
            this.next = null;
        }
    }

    public Node getHead() {
        return head;
    }

    private Node head;

    public TestLink() {
        this.head = new Node();
    }
    
    //此處寫所有與鏈表有關的方法
    
}
以下爲單鏈表的題:
package pri.qzz.testlink;

import org.junit.Test;
import org.omg.CORBA.PUBLIC_MEMBER;

import java.util.LinkedList;

/**
 * @ClassName TestLink
 * @Description TODO
 * @Author QZZ
 * @Date 2018/11/27 12:31
 * @Title 願上蒼有好生之德
 * @Description:
 *
 * 1.寫鏈表類,類裏寫節點類
 * 2.數據域,指針域
 * 3.節點類裏,無參構造函數(爲頭節點準備),有參構造函數(爲增加節點準備)
 * 4.頭引用,鏈表類中,無參構造函數裏面寫生成頭結點對象(main中生成鏈表類對象時,頭結點對象就生成了)
 *
 *
 * 1.頭插法,插入數據
 * 2.尾插法
 * 3.得到單鏈表長度(數據節點個數)
 * 4.任意的位置插入
 * 5.刪除節點
 * 6.刪除值爲val的節點
 * 7.打印單鏈表數據
 * 8.返回下標
 * 9.刪除單鏈表當中所有值爲val的節點   O(n)
 * 10.對鏈表進行排序(冒泡)
 * 11.找到倒數第K個節點
 * 12.刪除倒數第k個節點
 * 13.創建一個環
 * 14.查找是否有環
 * 15.求環的入口點
 * 16.求環的長度
 * 17.單鏈表的逆置?(使用頭插法逆置)
 * 18.單鏈表的反轉
 * 19.O(1)時間複雜度
 * 20.非遞歸合併兩個有序的遞增的單鏈表
 **/
public class TestLink {
    class Node {
        int data;
        Node next;

        public Node() {
            this.data = data;
            this.next = null;
        }

        public Node(int val) {
            this.data = val;
            this.next = null;
        }
    }

    public Node getHead() {
        return head;
    }

    private Node head;

    public TestLink() {
        this.head = new Node();
    }

    //1.頭插法
    public void insertHead(int val) {
        Node cur = new Node(val);
        cur.next = this.head.next;
        this.head.next = cur;
    }

    //2.尾插法
    public void insertTail(int val) {
        Node cur = this.head;
        while (cur.next != null) {//找到最後一個爲空的節點
            cur = cur.next;
    }
        Node endNode = new Node(val);//生成新節點
        cur.next = endNode;//和之前找到的後面爲空的節點鏈接
    }

    //3.得到單鏈表長度(數據節點個數)
    public int getLength() {
        Node cur = this.head;
        int count = 0;
        while (cur.next != null) {
            cur = cur.next;
            count++;
        }
        return count;
    }

    //4.任意的位置插入
    public void insertPos(int pos, int val) {
        if (pos < 0 || pos > getLength()) {
            return;
        }
        Node cur = this.head;
        for (int i = 0; i < pos; i++) {//找到上一個節點
            cur = cur.next;
        }
        Node newNode = new Node(val);
        newNode.next = cur.next;
        cur.next = newNode;
    }

    //5.刪除節點(多種寫法,也可以有count代表第幾個節點和pos相等進行刪除)
    public void deletePos(int pos) {
        if (pos < 0 || pos > getLength()) {
            return;
        }
        Node cur = this.head;
        Node deleteCur = this.head.next;
        for (int i = 0; i < pos; i++) {
            //當前節點的上一個節點
            cur = cur.next;
            deleteCur = cur.next;
        }
        cur.next = deleteCur.next;
    }

    //6.刪除值爲val的節點
    public void deleteVal(int val) {
        Node cur = this.head.next;
        Node pre = this.head;
        while (cur != null) {
            if (cur.data == val) {
                pre.next = cur.next;
            }
            cur = cur.next;
            pre = pre.next;
        }
    }

    //7.打印單鏈表數據
    public void print() {
        Node cur = this.head;
        while (cur.next != null) {
            System.out.print(cur.next.data + " ");
            cur = cur.next;
        }
    }
    //7.1打印反轉後單鏈表數據  you wen ti  傳入reverHead
    public void contraryPrint(Node reverHead) {
        Node cur = reverHead;
        while (cur.next != null) {
            System.out.println(cur.data);
            cur = cur.next;
        }
    }

    //8.返回下標
    public int findPos(int val) {
        int index = 0;
        Node cur = this.head.next;
        while (cur != null) {
            if (cur.data == val) {
                index++;
                return index;
            }
            cur = cur.next;
        }
        return -1;
    }

    //9.刪除單鏈表當中所有值爲val的節點   O(n)
    public void deleteAllVal(int val) {
        Node cur = this.head.next;
        Node pre = this.head;
        while (cur != null) {
            if (cur.data == val) {
                pre.next = cur.next;
                cur = cur.next;
            } else {
                cur = cur.next;
                pre = pre.next;
            }
        }
    }

    //10.對鏈表進行排序(冒泡)
    public void sortBubble() {
        Node cur;
        Node runByRun;
        int temp;
        for (cur = this.head.next; cur.next != null; cur = cur.next) {
            for (runByRun = this.head.next; runByRun.next != null; runByRun = runByRun.next) {
                if (runByRun.data > runByRun.next.data) {

                    temp = runByRun.data;
                    runByRun.data = runByRun.next.data;
                    runByRun.next.data = temp;
                }
            }
        }
    }

    //11.找到倒數第K個節點
    public int findLastPosVal(int pos) {
        if (pos < 0 || pos > getLength()) {
            throw new UnsupportedOperationException("Pos不合法");
        }
        Node cur = this.head;
        Node pre = this.head;
        while (pos - 1 > 0) {
            cur = cur.next;
            --pos;
        }
        while (cur.next != null) {
            cur = cur.next;
            pre = pre.next;
        }
        return pre.data;
    }

    //12.刪除倒數第k個節點
    public void deleteLastPos(int pos) {
        if (pos < 0 || pos > getLength()) {
            throw new UnsupportedOperationException("Pos不合法");
        }
        Node cur = this.head;
        Node pre = this.head;
        while (pos > 0) {
            cur = cur.next;
            --pos;
        }
        while (cur.next != null) {
            cur = cur.next;
            pre = pre.next;
        }
        pre.next = pre.next.next;
    }

    //13.創建一個環
    public void createLoop() {
        Node cur = this.head;
        while (cur.next != null) {
            cur = cur.next;
        }
        cur.next = this.head.next.next;
    }

    //14.查找是否有環()快慢指針
    public boolean isLoop() {
        Node fast = this.head;
        Node slow = this.head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                return true;
            }
        }
        return false;
    }

    //15.求環的入口點
    public int getEnterNode() {
        Node fast = this.head;
        Node slow = this.head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (slow == fast) {
                break;
            }
        }
        slow = this.head;
        while (fast != slow) {
            fast = fast.next;
            slow = slow.next;
        }
        return fast.data;
    }
    //16.求環的長度
    public int getLoopLenth() {
        Node fast = this.head;
        Node slow = this.head;
        boolean flg = false;
        int len = 0;
        while(fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow && flg == true) {
                break;
            }
            if (slow == fast && flg == false) {
                flg = true;
            }
            if (flg == true) {
                len++;
            }
        }
        return len;
    }
    //17.單鏈表的逆置?(使用頭插法逆置)
    public void reverse() {

        Node cur = this.head.next;
        Node curNode = null;
        this.head.next = null;
        while (cur != null) {
            curNode = cur.next;

            cur.next = this.head.next;
            this.head.next = cur;
            cur = curNode;
        }
    }

    //18.單鏈表的反轉
    public Node contrary() {
        Node cur = this.head;
        Node curNext;
        Node pre = null;
        Node reverHead;
        while (cur != null) {
            curNext = cur.next;
         /*   if (curNext == null) {
                reverHead = cur;
            }*/
            cur.next = pre;//後面指針域指向前面地址
            pre = cur;
            cur = curNext;
        }
        reverHead = pre;
        return reverHead;
    }
    //19.O(1)時間複雜度
    public void deleteNode (Node nodeStart, Node nodeDelete) {
        if (nodeDelete.next != null) {//如果刪除的不是尾節點
            Node nodeDeleteNext = nodeDelete.next;
            nodeDelete.data = nodeDeleteNext.data;
            nodeDelete.next = nodeDeleteNext.next;
            nodeDeleteNext = null;
        }else if (nodeStart == nodeDelete) {
            nodeStart = null;
            nodeDelete = null;
        }else {//尾節點
            //尾節點的前驅
            Node cur = nodeStart;
            while (cur.next != nodeDelete) {
                cur = cur.next;
            }
            //cur ==> 尾節點的前驅
            cur.next = null;
            nodeDelete = null;
        }
        return;
    }



    public static boolean isCut(TestLink testLink1,TestLink testLink2) {
        TestLink.Node head1 = testLink1.getHead();//指向長的單鏈表
        TestLink.Node head2 = testLink2.getHead();//指向短的單鏈表
        int len1 = testLink1.getLength();
        int len2 = testLink2.getLength();
        int myLen = len1-len2;
        if(myLen < 0) {
            head1 = testLink2.getHead();
            head2 = testLink1.getHead();
            myLen = len2-len1;
        }
        //head1===>指向長的單鏈表
        for (int i = 0; i < myLen; i++) {
            head1 = head1.next;
        }
        while(head1 != head2 && head1 != null && head2 != null) {
            head1 = head1.next;
            head2 = head2.next;
        }

        if(head1 == head2 && head1 != null && head2 != null) {
            return true;
        }
        return false;
    }

    //20.非遞歸合併兩個有序的遞增的單鏈表
    public static TestLink.Node mergeLink(TestLink link1,TestLink link2){
        TestLink.Node newHead = null;//返回的頭結點
        /*TestLink.Entry p1 = link1.getHead().next;
        TestLink.Entry p2 = link2.getHead().next;*/
        TestLink.Node p1 = link1.getHead();
        TestLink.Node p2 = link2.getHead();
        if(p1.next.data < p2.next.data) {
            //newHead = link1.getHead();
            newHead = p1;
        } else {
            //newHead = link2.getHead();
            newHead = p2;
        }
        p1 = p1.next;
        p2 = p2.next;
        TestLink.Node tmpHead = newHead;
        while(p1 != null && p2 != null) {
            if(p1.data < p2.data) {
                tmpHead.next = p1;
                p1 = p1.next;
            } else {
                tmpHead.next = p2;
                p2 = p2.next;
            }
            tmpHead = tmpHead.next;
        }
        if(p1 == null) {
            tmpHead.next = p2;
        }
        if(p2 == null) {
            tmpHead.next = p1;
        }
        return newHead;
    }

    //打印合並後的單鏈表
    public static void showMerge(TestLink.Node entry){
        TestLink.Node  cur = entry.next;
        while(cur != null){
            System.out.print(cur.data + " ");
            cur = cur.next;
        }
    }
}

單鏈表中一些題的圖解:

1.非遞歸合併兩個有序遞增的單鏈表
在這裏插入圖片描述

2.單鏈表的反轉
在這裏插入圖片描述


循環鏈表

(上面有循環鏈表圖)

代碼以及思想:
package pri.qzz.testlink;

/**
 * @ClassName TestClinkDemo
 * @Description TODO
 * @Author QZZ
 * @Date 2018/12/5 17:08
 * @Title 願上蒼有好生之德
 * @Description: 
 * 循環鏈表(主要關鍵在
 *
 * 1、public Clink() {}  中生成了頭結點,頭結點的next和自己鏈在一起)
 * 2、以前while() 中不等於null,null換成this.next
 * 3、尾插最後的節點要和頭結點鏈接起來(頭插法無所謂和一般鏈表寫法一樣)
 **/
class Clink {
    class Node {
        private int data;
        private Node next;
        public Node() {
            this.data = -1;
            this.next = null;
        }
        public Node(int val) {
            this.data = val;
            this.next = null;
        }
    }
    public Node head;

    public Clink() {
        this.head = new Node();
        this.head.next = this.head;
    }

    //頭插法
    public void insertHead(int val) {
        Node cur = new Node(val);
        cur.next = this.head.next;
        this.head.next = cur;
    }
    //尾插法
    public void insertTail(int val) {
        Node cur = this.head;
        while (cur.next != this.head) {
            cur = cur.next;
        }
        Node newCur = new Node(val);
        cur.next = newCur;
        newCur.next = this.head;
    }
    //刪除所有值爲val的節點
    public void deleteAllVal(int val) {
        Node cur = this.head.next;
        Node pre = this.head;
        while (cur != this.head) {
            if (cur.data == val) {
                pre.next = cur.next;
                cur = pre.next;
            }else {
                pre = cur;
                cur = cur.next;
            }
        }
    }
    public void show() {
        Node cur = this.head.next;
        while (cur != this.head) {
            System.out.println(cur.data + " ");
            cur = cur.next;
        }
        System.out.println();
    }
}
public class TestClinkDemo {
    public static void main(String[] args) {
        Clink Node = new Clink();
        //entry.insertHead(12);
        Node.insertTail(1);
        Node.insertTail(1);
        Node.insertTail(2);
        Node.insertTail(1);
        Node.insertTail(3);

        Node.show();
        Node.deleteAllVal(1);
        Node.show();
    }
}


雙向鏈表

如下圖:

在這裏插入圖片描述


代碼以及思想:
class Dlink {
    class Node {
        private int data;
        private Node next;
        private Node pre;
        public Node () {
            this.data = -1;
            this.pre = null;
            this.next = null;
        }
        public Node (int val) {
            this.data = val;
            this.pre = null;
            this.next = null;
        }
    }
    private Node head;

    public Dlink () {
        this.head = new Node();
    }

    //頭插法
    public void insertHead (int val) {
        Node cur = new Node(val);
        cur.next = this.head.next;
        cur.pre = this.head;
        this.head.next = cur;
        if (cur.next != null) {
            cur.next.pre = cur;
        }
    }
    //尾插法
    public void insertTail (int val) {
        Node cur = this.head;
        while (cur.next != null) {
            cur = cur.next;
        }
        Node newCur = new Node(val);
        cur.next = newCur;
        newCur.pre = cur;
    }
    //刪除所有值爲val的節點
    public void deleteAllVal (int val) {
        Node cur = this.head.next;
        while (cur != null) {
            if (cur.data == val) {
                cur.pre.next = cur.next;
                if(cur.next != null) {
                    cur.next.pre = cur.pre;
                }
            }
            cur = cur.next;
        }
    }
    //打印
    public void show () {
        Node cur = this.head.next;
        while (cur != null) {
            System.out.println(cur.data + " ");
            cur = cur.next;
        }
        System.out.println();
    }
}
public class TestDlinkDemo {
    public static void main(String[] args) {
        Dlink dlink = new Dlink();

        /*dlink.insertHead(1);
        dlink.insertHead(2);
        dlink.insertHead(3);
        dlink.insertHead(4);
        dlink.insertHead(5);*/

        dlink.insertTail(1);
        dlink.insertTail(1);
        dlink.insertTail(3);
        dlink.insertTail(4);
        dlink.insertTail(1);

        dlink.show();
        dlink.deleteAllVal(1);
        dlink.show();
    }
}

Github 代碼鏈接:

https://github.com/QzzBL/Qzz_Java/tree/master/Java基礎數據結構/鏈表

                     2018.12.08/週六
                     by 922
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章