數據結構速學筆記:單鏈表面試題整理總結

目錄

  1. 單鏈表倒數第k個節點
  2. 單鏈表反轉鏈表
  3. 單鏈表反向打印節點

單鏈表倒數第k個節點


    /**
     * 單鏈表倒數第k個節點
     * 思路:1. 遍歷鏈表計算出,有效節點size(頭節點排除在外)
     *      2. 倒數K節點對應的節點: size-k
     *      解釋:例如鏈表:head(頭節點) -> A.next -> B.next ->C.next -> D.next
     *           head不是有效節點,所以head要排除在外
     *           上述鏈表有效節點是4個,取倒數第2節點,即C節點,是我們需要的。
     *           size-k=2  從第一個有效節點,往後位移2位,即:從當前A節點,位移2位,是C節點。 即倒數k節點數據
     * */

    public void getK_Node(int k){

        int size=getSize();

        if (k<=0 || k>size){
            return;
        }
        Node curNode = headNode.next;
        for (int i=0;i<size-k;i++){
            curNode=curNode.next;
        }
        log("倒數K節點數據  "+curNode);
    }

    public int getSize(){
        int size=0;
        Node curNode = headNode.next;
        while (curNode != null) {
            size++;
            curNode = curNode.next;
        }
        return size;
    }


單鏈表反轉鏈表

代碼實現


    /**
     * 單鏈表反轉
     */
    public void reverse() {
        // 分析1-->
        if (headNode == null || headNode.next == null || headNode.next.next == null) {
            // 空鏈表、鏈表只有一個元素 不用反轉
            return;
        }
        Node temp = headNode;
        Node reverseHead = new Node(0, "");
        Node curNode = temp.next; // 當前鏈表
        Node nextNode; // 臨時存儲當前鏈表的下一個鏈表元素
        while (curNode != null) {
            // 先保存當前鏈表位置的下一個元素
            nextNode = curNode.next;
            // 分析 2-->
            /** 原鏈表:temp -> A.next -> B.next -> C.next ->D.next
             * 核心思路:遍歷原鏈表時,每遍歷一個元素
             *     1. next指針向後位移1位
             *     2. 同時把鏈表當前位置的元素給插入到 頭節點是reverseHead的鏈表中,插在reverseHead最前端
             *         2.1 把拿到的元素的next指向原本reverseHead.next指向的數據
             *         2.2 然後把拿到當前的元素,都要插在新鏈表最前端:即:reverseHead.next指向的位置(頭節點後的第一個節點)
             *         解釋:  例如當前是 reverseHead.next -> A.next
             *                繼續遍歷拿到B時: 讓B.next ->A.next
             *                               在讓reverseHead.next ->B.next
             *                               這樣形成 reverseHead.next ->B.next -> A.next
             * */
            curNode.next = reverseHead.next;
            reverseHead.next = curNode;
            // 分析3 --> 把原鏈表中下一個節點元素,賦值給當前curNode。(就是鏈表向後位移一位)
            curNode = nextNode;
        }
        //分析4 --> 原鏈表的頭節點指向新鏈表頭節點後的第一個元素(原表頭節點替換掉新表頭節點)
        // 解釋 --> 新表頭節點,於後面的節點斷開,讓原表頭節點指向
        temp.next = reverseHead.next;

        // 最終完成單鏈表的反轉
        try {
            showNode();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

圖文解釋:

在這裏插入圖片描述


單鏈表反向打印節點

  /**
     * 單鏈表,反向打印節點
     * 遍歷鏈表,逐個壓入棧中(棧的數據結構先進後),在遍歷棧,打印出來。結果符合反向打印鏈表
     */
    public void reversePrint() {

        Stack<Node> stack = new Stack<>();
        Node curNode = headNode.next;
        while (curNode != null) {
            stack.push(curNode);
            curNode = curNode.next;
        }

        while (stack.size() > 0) {
            System.out.println("反向打印鏈表節點: " + stack.pop());
        }

    }


完整代碼


/**
 * 帶頭節點的單鏈表
 */
public class LinkList {
    Node headNode = new Node(0, "");

    /**
     * 不考慮客觀條件,直接插在鏈尾
     */
    public void addNode(Node addNode) {
        Node temp = headNode;
        while (true) {
            if (temp.next == null) { //找到最後一個節點
                break;
            }
            temp = temp.next;
        }
        temp.next = addNode;
    }

    /**
     * 按照順序節點插入  例:1 、2 、3、4、5
     */
    public void addNodeByOrder(Node addNode) {
        Node temp = headNode;
        while (true) {
            if (temp.next == null) {
                break;
            }
            if (temp.next.num > addNode.num) { // A、B、C、D

                break;
            }
            temp = temp.next;
        }
        addNode.next = temp.next;
        temp.next = addNode;
    }


    /**
     * 根據num 修改名字
     */
    public void upNode(int num, String name) {
        Node temp = headNode;
        while (true) {
            if (temp.next == null) {
                System.out.println("upNode  break 未找到可修改的數據");
                break;
            }
            if (temp.next.num == num) {
                temp.next.name = name;
                System.out.println("upNode = " + temp.next.name);
                break;
            }
            temp = temp.next;
        }
    }

    /**
     * delete
     * 根據num刪除
     */
    public void delete(int num) {
        Node temp = headNode;
        while (true) {
            if (temp.next == null) {
                System.out.println("delete  break ");
                break;
            }
            if (temp.next.num == num) {
                // A、B、C  B是刪除元素  A.next=C 即: A.next=A.next.next
                System.out.println("delete的元素 " + temp.next);
                temp.next = temp.next.next;
                break;
            }
            temp = temp.next;
        }
    }

    /**
     * 根據num 查處 對應的Node
     */
    public Node query(int num) {
        Node temp = headNode;
        Node tempNode = null;
        while (true) {
            if (temp.next == null) {
                System.out.println("query  break ");
                break;
            }
            if (temp.next.num == num) {
                tempNode = temp.next;
                System.out.println("query =  " + tempNode);
                break;
            }
            temp = temp.next;
        }

        return tempNode;

    }


    /**
     * 單鏈表反轉
     */
    public void reverse() {
        // 分析1-->
        if (headNode == null || headNode.next == null || headNode.next.next == null) {
            // 空鏈表、鏈表只有一個元素 不用反轉
            return;
        }
        Node temp = headNode;
        Node reverseHead = new Node(0, "");
        Node curNode = temp.next; // 當前鏈表
        Node nextNode; // 臨時存儲當前鏈表的下一個鏈表元素
        while (curNode != null) {
            // 先保存當前鏈表位置的下一個元素
            nextNode = curNode.next;
            // 分析 2-->
            /** 原鏈表:temp -> A.next -> B.next -> C.next ->D.next
             * 核心思路:遍歷原鏈表時,每遍歷一個元素
             *     1. next指針向後位移1位
             *     2. 同時把鏈表當前位置的元素給插入到 頭節點是reverseHead的鏈表中,插在reverseHead最前端
             *         2.1 把拿到的元素的next指向原本reverseHead.next指向的數據
             *         2.2 然後把拿到當前的元素,都要插在新鏈表最前端:即:reverseHead.next指向的位置(頭節點後的第一個節點)
             *         解釋:  例如當前是 reverseHead.next -> A.next
             *                繼續遍歷拿到B時: 讓B.next ->A.next
             *                               在讓reverseHead.next ->B.next
             *                               這樣形成 reverseHead.next ->B.next -> A.next
             * */
            curNode.next = reverseHead.next;
            reverseHead.next = curNode;
            // 分析3 --> 把原鏈表中下一個節點元素,賦值給當前curNode。(就是鏈表向後位移一位)
            curNode = nextNode;
        }
        //分析4 --> 原鏈表的頭節點指向新鏈表頭節點後的第一個元素(原表頭節點替換掉新表頭節點)
        // 解釋 --> 新表頭節點,於後面的節點斷開,讓原表頭節點指向
        temp.next = reverseHead.next;

        // 最終完成單鏈表的反轉
        try {
            showNode();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 單鏈表,反向打印節點
     * 遍歷鏈表,逐個壓入棧中(棧的數據結構先進後),在遍歷棧,打印出來。結果符合反向打印鏈表
     */
    public void reversePrint() {

        Stack<Node> stack = new Stack<>();
        Node curNode = headNode.next;
        while (curNode != null) {
            stack.push(curNode);
            curNode = curNode.next;
        }

        while (stack.size() > 0) {
            System.out.println("反向打印鏈表節點: " + stack.pop());
        }

    }

    /**
     * 單鏈表倒數第k個節點
     * 思路:1. 遍歷鏈表計算出,有效節點size(頭節點排除在外)
     *      2. 倒數K節點對應的節點: size-k
     *      解釋:例如鏈表:head(頭節點) -> A.next -> B.next ->C.next -> D.next
     *           head不是有效節點,所以head要排除在外
     *           上述鏈表有效節點是4個,取倒數第2節點,即C節點,是我們需要的。
     *           size-k=2  從第一個有效節點,往後位移2位,即:從當前A節點,位移2位,是C節點。 即倒數k節點數據
     * */

    public void getK_Node(int k){

        int size=getSize();

        if (k<=0 || k>size){
            return;
        }
        Node curNode = headNode.next;
        for (int i=0;i<size-k;i++){
            curNode=curNode.next;
        }
        log("倒數K節點數據  "+curNode);
    }

    public int getSize(){
        int size=0;
        Node curNode = headNode.next;
        while (curNode != null) {
            size++;
            curNode = curNode.next;
        }
        return size;
    }


    /**
     * 打印出當前鏈表的所有元素
     */
    public void showNode() throws InterruptedException {
        if (headNode.next == null) { // 空
            return;
        }
        Node temp = headNode.next; // 第一個元素
        while (true) {
            Thread.sleep(500);
            System.out.println("showNode " + temp);
            if (temp.next == null) {
                System.out.println("showNode  break ");
                break;
            }
            temp = temp.next;
        }
    }


    public static class Node {
        int num;
        String name;
        Node next;

        public Node(int num, String name) {
            this.num = num;
            this.name = name;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "num=" + num +
                    ", name='" + name +
                    '}';
        }
    }

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