数据结构速学笔记:环形链表的构建以及约瑟夫问题

有不足指出,欢迎大佬指出!共同进步。

目录

如何构建环形链表?
约瑟夫问题
完整代码
  • 准备

    static class RingNode {
        private int num;
        private RingNode next;
        // .....
}


如何构建环形链表?


    RingNode firstNode = null; // 环形链表第一个元素(固定不变)

    /**
     * 构建一个环形链表
     * <p>
     * 思路:(无头节点)
     * 1. 存储的第一个元素,一定要先实现自我环形
     * 2. 需要2个指针,2.1:firstNode(即第一个元素)固定不动
     *               2.2:curNode => 表示当前元素(每添加一个元素,curNode后移一位),保证 curNode是当前最新
     * 3. 新数据插入时,让curNode的next指向,当前插入的元素。再让当前插入的元素指向firstNode,从而首尾相连形成环形
     * 4. 插入数据后curNode后移一位,保证指针是最新位置
     */
    public void addNode(int list) {
        if (list < 1) {
            log("链表为空");
            return;
        }

        RingNode curNode = null; // 记录当前位置的元素,每添加一个元素,curNoded就往后移一位
        for (int i = 1; i < list; i++) {
            RingNode ringNode = new RingNode(i);
            if (i == 1) { // 分析1--> 第一个元素,需要特殊处理,先让其自身形成一个环形(自己指向自己)
                firstNode = ringNode;
                firstNode.setNext(firstNode);
                curNode = ringNode;
            } else {//分析2--> 先指向要插入的ringNode,在让 ringNode指向firstNode,形成环形
                curNode.setNext(ringNode);
                ringNode.setNext(firstNode);
                curNode = curNode.next; //后移
            }
        }

        // 打印出来
        if (firstNode == null) {
            log("链表没有add");
            return;
        }
        curNode = firstNode;//curNode用于记录当前位置的curNode,每遍历一位,后移一位
        while (true) {
            log(curNode.num);
            if (curNode.next == firstNode) {//  当前位置的next指向的数据,如果和firstNode 相等,说明已经是最后一位 结束循环
                log("链表遍历结束");
                break;
            }
            curNode = curNode.next;
        }
    }


约瑟夫问题

直接百度具体描述 -->
人们站在一个等待被处决的圈子里。 计数从圆圈中的指定点开始,并沿指定方向围绕圆圈进行。 在跳过指定数量的人之后,执行下一个人。 对剩下的人重复该过程,从下一个人开始,朝同一方向跳过相同数量的人,直到只剩下一个人,并被释放。

如何实现上述的问题?

数组环形链表都可以实现

环形链表实现代码:
请结合图文理解:


    /**
     * 约瑟夫问题
     *
     * 场景:环形链表中,每隔几个数取出一个数据,打印出对应的取出顺序
     *
     * @param startOut 起始位置
     * @param outNum   每数几下移除一个数据
     * @param allNode  环形链表初始数据是多少
     *
     * 思路:
     *     1.首先考虑,如何让删除元素的前一个元素和后一个元素通过next相连? =》 A B C  B是删除元素,要让A.next=C
     *     2.准备2个指针:
     *                 firstNode => 记录起始位置的元素也是要删除位置的元素
     *                 helper => 时刻,让helper在first的前一个位置
     *     3. 删除元素:
     *                 firstNode = firstNode.next  -> 让firstNode后位移一位
     *                 helper.next = firstNode   ->  让helper指向位移后的firstNode    (时刻保持helper 在firstNode的前一个位置)
     *     4. helper = first 时,说明只剩一个元素
     */
    public void takeOutNode(int startOut, int outNum, int allNode) {

        // 分析1--> 链表不可为null  起点位置不能小于1   起点位置不能大于原有链表的长度
        if (firstNode == null || startOut < 1 || startOut > allNode) {
            log("takeOutNode  return");
            return;
        }

        // 分析2--> 指向指定起点位置的前一个数据
        RingNode helper = firstNode;
        // 分析2.1 --> 首先要找到环形链表的最后一个元素
        while (true) {
            if (helper.getNext() == firstNode) {
                break;
            }
            helper = helper.getNext(); // 指针后移
        }


        // 分析3--> 将firstNode指针指向,用户指定起始位置 helper在firstNode的前一位
        for (int i = 0; i < startOut - 1; i++) {
            firstNode = firstNode.getNext();
            helper = helper.getNext();
        }

        // 分析4 -->
        while (true) {
            // 分析4.1 --> 相等说明环形链表中只剩一个数据
            if (helper == firstNode) {
                log("最后一个元素 " + helper.num);
                break;
            }
            //分析 4.2 --> 根据指定的outNum,移动数据 (outNum-1)=》链表当前位置本身算1下。所以只需后移一位就得到要移除位置的元素
            for (int x = 0; x < outNum - 1; x++) {
                firstNode = firstNode.getNext();
                helper = helper.getNext();
            }
            log("This is  cur Node: " + firstNode.num);
            // 分析 4.3 --> 更新当前的firstNode ,helper(移除元素)
            //  当前A、B、C    B是当前要移除的元素, 让指针A直接指向C
            firstNode = firstNode.getNext(); // 将firstNode的指向的下一个数据,赋值给firstNode
            helper.next = firstNode; // helper指向最新的firstNode
        }
    }

图文解释:

分析2--> 分析3--> ``分析4--> 分析4.1--> 分析4.2--> 删除前对应的链表结构

在这里插入图片描述
实现删除操作:分析4.3--> 删除后的链表结构
在这里插入图片描述

完整代码

public class RingLinkList {

    public static void main(String[] args) {
        RingLinkList r = new RingLinkList();
        r.addNode(16);
        log("--------------");
        r.takeOutNode(3, 3, 16);
    }

    RingNode firstNode = null; // 环形链表第一个元素(固定不变)

    /**
     * 构建一个环形链表
     * <p>
     * 思路:(无头节点)
     * 1. 存储的第一个元素,一定要先实现自我环形
     * 2. 需要2个指针,2.1:firstNode(即第一个元素)固定不动
     *               2.2:curNode => 表示当前元素(每添加一个元素,curNode后移一位),保证 curNode是当前最新
     * 3. 新数据插入时,让curNode的next指向,当前插入的元素。再让当前插入的元素指向firstNode,从而首尾相连形成环形
     * 4. 插入数据后curNode后移一位,保证指针是最新位置
     */
    public void addNode(int list) {
        if (list < 1) {
            log("链表为空");
            return;
        }

        RingNode curNode = null; // 记录当前位置的元素,每添加一个元素,curNoded就往后移一位
        for (int i = 1; i < list; i++) {
            RingNode ringNode = new RingNode(i);
            if (i == 1) { // 分析1--> 第一个元素,需要特殊处理,先让其自身形成一个环形(自己指向自己)
                firstNode = ringNode;
                firstNode.setNext(firstNode);
                curNode = ringNode;
            } else {//分析2--> 先指向要插入的ringNode,在让 ringNode指向firstNode,形成环形
                curNode.setNext(ringNode);
                ringNode.setNext(firstNode);
                curNode = curNode.next; //后移
            }
        }

        // 打印出来
        if (firstNode == null) {
            log("链表没有add");
            return;
        }
        curNode = firstNode;//curNode用于记录当前位置的curNode,每遍历一位,后移一位
        while (true) {
            log(curNode.num);
            if (curNode.next == firstNode) {//  当前位置的next指向的数据,如果和firstNode 相等,说明已经是最后一位 结束循环
                log("链表遍历结束");
                break;
            }
            curNode = curNode.next;
        }
    }

    /**
     * 约瑟夫问题
     *
     * 场景:环形链表中,每隔几个数取出一个数据,打印出对应的取出顺序
     *
     * @param startOut 起始位置
     * @param outNum   每数几下移除一个数据
     * @param allNode  环形链表初始数据是多少
     *
     * 思路:
     *     1.首先考虑,如何让删除元素的前一个元素和后一个元素通过next相连? =》 A B C  B是删除元素,要让A.next=C
     *     2.准备2个指针:
     *                 firstNode => 记录起始位置的元素也是要删除位置的元素
     *                 helper => 时刻,让helper在first的前一个位置
     *     3. 删除元素:
     *                 firstNode = firstNode.next  -> 让firstNode后位移一位
     *                 helper.next = firstNode   ->  让helper指向位移后的firstNode    (时刻保持helper 在firstNode的前一个位置)
     *     4. helper = first 时,说明只剩一个元素
     */
    public void takeOutNode(int startOut, int outNum, int allNode) {

        // 分析1--> 链表不可为null  起点位置不能小于1   起点位置不能大于原有链表的长度
        if (firstNode == null || startOut < 1 || startOut > allNode) {
            log("takeOutNode  return");
            return;
        }

        // 分析2--> 指向指定起点位置的前一个数据
        RingNode helper = firstNode;
        // 分析2.1 --> 首先要找到环形链表的最后一个元素
        while (true) {
            if (helper.getNext() == firstNode) {
                break;
            }
            helper = helper.getNext(); // 指针后移
        }


        // 分析3--> 将firstNode指针指向,用户指定起始位置 helper在firstNode的前一位
        for (int i = 0; i < startOut - 1; i++) {
            firstNode = firstNode.getNext();
            helper = helper.getNext();
        }

        // 分析4 -->
        while (true) {
            // 分析4.1 --> 相等说明环形链表中只剩一个数据
            if (helper == firstNode) {
                log("最后一个元素 " + helper.num);
                break;
            }
            //分析 4.2 --> 根据指定的outNum,移动数据 (outNum-1)=》链表当前位置本身算1下。所以只需后移一位就得到要移除位置的元素
            for (int x = 0; x < outNum - 1; x++) {
                firstNode = firstNode.getNext();
                helper = helper.getNext();
            }
            log("This is  cur Node: " + firstNode.num);
            // 分析 4.3 --> 更新当前的firstNode ,helper(移除元素)
            //  当前A、B、C    B是当前要移除的元素, 让指针A直接指向C
            firstNode = firstNode.getNext(); // 将firstNode的指向的下一个数据,赋值给firstNode
            helper.next = firstNode; // helper指向最新的firstNode
        }
    }


    static class RingNode {
        private int num;

        public RingNode(int num) {
            this.num = num;
        }

        private RingNode next;

        public int getNum() {
            return num;
        }

        public void setNum(int num) {
            this.num = num;
        }

        public RingNode getNext() {
            return next;
        }

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

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值