数据结构速学笔记:单链表面试题整理总结

目录

  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 +
                    '}';
        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值