【数据结构和算法分析】循环链表及约瑟夫问题
2014-07-26 10:53
357 查看
循环链表及约瑟夫问题
循环链表:
循环链表可以为单链表,也可以为双链表,但我不想把问题搞得那么复杂,姑且就做单链表的循环形式吧。我们在实现了链表后,必然会提出一个问题:链表能不能首尾相连?怎样实现?
答案:能。其实实现的方法很简单,就是将表中最后一个结点的指针域指向头结点即可(P->next = head;)。这种形成环路的链表称为循环链表。
代码如下:
public class MyCircleList { Node headNode; Node tailNode; int length; public MyCircleList(Node node){ this.headNode = node; this.tailNode = node; length = 1; } /* * 默认在尾结点插入 */ public void insert(Node node){ insert(node, length); } /* * @param Node node 插入的结点 , int index 结点插入的位置 */ public void insert(Node node,int index){ if (index < 0 || index > length) { throw new IndexOutOfBoundsException(); } if (index == 0) { this.tailNode.next = node; node.next = this.headNode; headNode = node; }else if (index == length) { tailNode.next = node; tailNode = node; node.next = this.headNode; }else { Node otherNode = this.headNode; while (index > 1) { otherNode = otherNode.next; index--; } node.next = otherNode.next; otherNode.next = node; } length++; } /* * @param int index 删除结点的位置 */ public void delete(int index){ if (index < 0 || index >= length) { throw new IndexOutOfBoundsException(); } if (index == 0 && length == 1) { tailNode = headNode = null; }else if (index == 0 && length != 1) { tailNode.next = headNode.next; headNode = headNode.next; }else { Node otherNode = this.headNode; while (index > 1) { otherNode = otherNode.next; index--; } otherNode.next = otherNode.next.next; } length--; } /* * @param int index 查看 index 处的 data */ public Object getData(int index){ if (index < 0 || index >= length) { throw new IndexOutOfBoundsException(); } Node otherNode = headNode; for (int i = 0; i < index; i++) { otherNode = otherNode.next; } return otherNode.data; } /* * @param int index 修改的 data 的位置 ,Object data 所需修改的 data */ public void setData(int index,Object data){ if (index < 0 || index >= length) { throw new IndexOutOfBoundsException(); } Node otherNode = headNode; for (int i = 0; i < index; i++) { otherNode = otherNode.next; } otherNode.data = data; } public void print(){ Node otherNode = this.headNode; for (int i = 0; i < length; i++) { System.out.print(otherNode.data+" "); otherNode = otherNode.next; } System.out.println(); } } class Node{ /* * 节点类,包括结点的值 data 和指向下一结点的指针 next,单链表适用 */ Object data; Node next; public Node(){ data = null; next = null; } public Node(Object data){ this.data = data; this.next = null; } public Node(Object data,Node nextnode){ this.data = data; this.next = nextnode; } /* * 判断有无下一结点 * @return boolean 若true,则该结点有下一结点 */ public boolean hasnext(){ return this.next != null; } }
约瑟夫问题:
约瑟夫问题几乎是最经典的用来讲解循环链表的案例了。为什么呢?我们来看看这个问题的描述就会明白了:有一队由n个冒险家组成的探险队深入到热带雨林中,但他们遭遇到了食人族,食人族的游戏规则是让他们围成一圈,然后选定一个数字m,从第1个人开始报数,报到m时,这个人就要被吃掉了,然后从下一个人开始又重新从1报数,重复这个过程,直到剩下最后一个人,这个人是幸运者,可以离开而不被吃掉。那么问题是,谁是这个幸运者呢?
我们来举个例子:
假设这个探险队有6个探险家,食人族选定的数字m是5,那么在第一轮中,5号会被吃掉,剩下的就是:1, 2, 3, 4, 6总共5个人,然后从6号开始,重新从1开始报5个数:6, 1, 2, 3, 4,所以在第二轮里面被吃掉的就是4号……一直重复这个过程,按顺序应该是:5, 4, 6, 2, 3被吃掉,剩下1号活下来。
解决这个问题并不是只能用循环链表的,但使用循环链表应该是最方便的。我写的代码如下:
public class Josephus {
public static final int N = 6; //代表 6 位人数
public static final int M = 5; //选定的数字为 5
public static void main(String[] args){
//初始化循环链表,构造出来为 1,2,3,4,5,6的链表分别代表六个人
MyCircleList myCircleList = new MyCircleList(new Node(1));
for (int i = 2; i <= N; i++) {
myCircleList.insert(new Node(i));
}
Node pre = null;
Node p = myCircleList.headNode;
for (int i = 0; i < N-1; i++) { //需要遍历的轮次,执行 N-1 次
for (int j = 1; j < M; j++) { //每次遍历的报数,数 M-1 人
pre = p;
p = p.next;
}
System.out.println("出局的是:" + p.data); //输出
pre.next = p.next; //删除一个结点
p = pre.next;
}
}
}
相关文章推荐
- 约瑟夫问题的数学角度分析 C 数组实现 循环链表实现 递归实现时间复杂度O(logN)
- 算法与数据结构基础系列(一): 链表的常见问题分析及实现
- 【数据结构和算法分析】最大子序列求和问题及联机算法
- 算法: 约瑟夫问题(Joseph Problem)的分析
- 算法-循环链表[约瑟夫问题之进阶]
- 线性表13|约瑟夫问题 - 数据结构和算法18
- 线性表13|约瑟夫问题 – 数据结构和算法18
- 数据结构学习笔记(二) 链表之用循环链表解决约瑟夫问题
- 企业级数据结构-循环链表(约瑟夫问题)
- 线性表13|约瑟夫问题 - 数据结构和算法18
- 数据结构学习中的简单问题(二):用循环链表求解简单约瑟夫问题
- 算法-循环链表[约瑟夫问题]
- 国际象棋“皇后”问题的回溯算法[C#源码分析]
- 常用算法的递归实现问题分析(针对《数据结构与程序设计》by Robert.L.Kruse)
- 一类螺旋方阵问题的算法分析与实现
- Trie树的应用,一道算法问题求解 问题分析
- 恶补算法与数据结构(一)——排列问题
- 数据结构学习足迹:绪论Triplet碰到的问题及分析解答
- 统计数字问题[算法设计与分析]
- 用循环链表求解约瑟夫问题