手把手带你用Java实现单向环形链表

一、单项环形链表介绍

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
在这里插入图片描述
链表分为带头节点的链表和没有头节点的链表,根据实际的需求确定
本文将使用没有头节点的链表

二、链表的应用实例

解决约瑟夫(Josephus)问题
问题:N个人围成一圈,从第一个开始报数,第M个将被带走,最后剩下一个为幸运儿。例如N=6,M=5,被带走的顺序是:5,4,6,2,3,1。
提示:用一个不带头结点的循环链表来处理Josephus问题:
1.先构建一个有N个节点的单向链表。
2.从第一个节点开始计数,数M个节点,第M个节点被移除。
3.从第M+1个节点处开始从1计数,直到最后一个节点被移除。

三、代码实现

具体解释再代码注释里

public class CircleSingleLinkedListDemo {
    public static void main(String[] args) {
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        //添加20个节点
        circleSingleLinkedList.add(6);
        //显示节点
        circleSingleLinkedList.show();
        //进行排除操作  传入数几个数
        circleSingleLinkedList.tackOut(5);
    }
}

class CircleSingleLinkedList{
    //创建第一个节点first
    JosephusNode first = null;
    //总节点数
    int nodeCount = 0;

    //创建指针(辅助变量)
    JosephusNode temp = null;

    // 添加节点,构成一个环形链表
    public void add(int numbers){
        //对numbers进行校验
        if(numbers<1){
            System.out.println("请输入正确节点数");
            return;
        }
        nodeCount = numbers;

        //使用for循环创建节点
        for (int i = 1;i <= numbers;i++){
            //根据编号创建节点
            JosephusNode node = new JosephusNode(i);
            //判断是否是第一个节点,若是第一个节点则next指向自己,否则正常添加节点
            if(i == 1){
                //添加节点--头节点
                //将初始化链表的第一个节点指向刚创建的节点
                first = node;
                //将第一个节点的next指向自己
                first.next = first;
                //将指针(辅助变量)指向第一个节点
                temp = first;
            }else{
                //添加节点--非头节点
                //将指针(辅助变量)的next指向当前节点
                temp.next = node;
                //将当前节点的next指向第一个节点
                node.next = first;
                //将指针(辅助变量)指向当前节点
                temp = node;
            }
        }
    }

    /**
     * 显示当前链表中的所有节点
     */
    public void show(){
        if(first == null){
            System.out.println("该链表暂无节点");
            return;
        }
        temp = first;
        //遍历节点
        while (true){
            //将节点信息进行输出
            System.out.println("当前节点的编号为"+temp.id);
            //遍历完成
            if(temp.next==first){
                break;
            }
            temp = temp.next;
        }
    }

    /**
     *
     * @param count 每次数几个数
     */
    public void tackOut(int count){
        //校验,只能输入比0大的数
        if(count<0){
            System.out.println("请输入正确数字!");
            return;
        }
        //让temp指针指向第一个节点
        temp = first;
        //临时指针,用于记录要排除节点的前一个节点
        JosephusNode lastNode = null;
        //进行输出节点
        while(true){
            //temp为要删除的节点的指针
            //  说明:当temp.next 指向 自己的时候说明只剩下最后一个节点,直接退出
            if(temp.next == temp){
                break;
            }
            //用于计数,由于是从第一个节点开始数,所以要用count-1,避免第一个节点数两次
            for(int i = 0; i < count-1; i++){
                //lastNode用于记录要排除节点的前一个节点
                lastNode = temp;
                //temp为要删除的节点
                temp = temp.next;
            }
            System.out.println("排除节点的编号为:"+temp.id);
            //进行节点排除
            lastNode.next = temp.next;

            //要删除的节点 指向 删除后的节点的下一个节点
            temp = lastNode.next;
        }
        System.out.println("最后一个节点编号为:"+temp.id);
    }
}

/**
 * 节点
 */
class JosephusNode{
    public int id;
    public JosephusNode next;

    public JosephusNode(int id){
        this.id = id;
    }

}
发布了27 篇原创文章 · 获赞 11 · 访问量 4394

猜你喜欢

转载自blog.csdn.net/qq_26020387/article/details/105407470