数据结构和算法(双向链表和单向环型链表-Josephu问题)

为什么会有双向链表?
单链表的缺点分析:

单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找
单向链表不能自我删除,需要考辅助节点,而双向链表,则可以自我删除

双向链表的结构:

每个节点都有next和pre指针,next指向后,pre指向前

分析双向链表的添加、遍历、删除
遍历方式和单链表一样,只是可以向前遍历,或者是向后遍历
添加(默认添加到链表的最后):
先找到双向链表的最后一个节点
temp.next = newNode
newNode.pre = temp
修改和单链表一样
删除:
因为是双向链表,所以可以实现自我删除(不使用临时变量)
直接找到有删除的节点,比如temp
temp.pre.next = temp.next;
temp.next.pre = temp.pre;

Josephu问题:

Josephu问题为,设编号为1,2 …n的n个小孩围坐一圈,约定编号为 k (1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个小孩又出列,以此类推,直到所有小孩出列,产生一个出队编号的序列。

提示:

用一个不带头节点的循环链表来处理Josephu问题,先构成一个有n个节点的单循环链表,然后由k节点起开始计数,计数到m时,对应节点从链表中删除,然后再从被删除的节点的下一个节点又从1开始计数,直到最后一个节点从链表中删除算法结束。

环型链表的创建:

先创建第一个节点,让first指向该节点,并形成环状
后面当我们每创建一个新的节点,就把该节点,加入到

遍历环型链表:

1.先让一个辅助指针(变量)temp,指向first节点
2.然后通过一个while循环遍历该环型链表即可 temp.next == first 结束

Josephu问题解析:

根据用户的输入m,生成一个出圈的顺序
1.需求创建一个辅助指针(变量)helper,事先应该指向环型链表的最后这个节点,跟在first后面
2.但小孩报数时,让first和helper指针同时移动m - 1次
3.这时就可以将first指向的小孩节点出圈
first = first.next
helper.next = frist
原来first指向的节点就没有任何引用,就会被回收。

Josephu问题出圈示例代码:
//参数说明:startNo为起始节点,count为出列数字,nums为总人数
	public void count(int startNo, int count, int nums) {
		// 先对数据进行校验
		if (first == null || startNo < 0 || startNo > nums) {
			System.out.println("输入参数有误,请重新输入");
			return;
		}

		// 创建辅助指针,帮助完成小孩出圈
		Node3 helper = first;

		// 事先应该指向环形链表的最后一个节点(就是first的前一个)
		while (true) {
			if (helper.next == first) {
				break;
			}
			helper = helper.next;
		}

		// 小孩报数前,先让first和 helper移动 k-1次(表示从第k个开始报数,k为1时不用移动)
		for (int j = 0; j < startNo - 1; j++) {
			first = first.next;
			helper = helper.next;
		}

		//开始报数
		// 当小孩报数时,让first和helper指针同时的移动m-1次,然后出圈
		// 直到圈中只有一个节点
		while (true) {
			if (first == helper) {
				break;
			}
			for (int i = 0; i < count - 1; i++) {
				first = first.next;
				helper = helper.next;
			}
			System.out.println(first);
			first = first.next;
			helper.next = first;
		}
		System.out.println(first);

	}
Josephu问题出圈步骤图解:

在这里插入图片描述

发布了68 篇原创文章 · 获赞 12 · 访问量 5202

猜你喜欢

转载自blog.csdn.net/qq_40963076/article/details/104852095