【数据结构和算法分析】循环链表及约瑟夫问题

来源:互联网 发布:淘宝卖家推广方法 编辑:程序博客网 时间:2024/05/24 01:38

循环链表及约瑟夫问题


循环链表:

                循环链表可以为单链表,也可以为双链表,但我不想把问题搞得那么复杂,姑且就做单链表的循环形式吧。

                我们在实现了链表后,必然会提出一个问题:链表能不能首尾相连?怎样实现?

                答案:能。其实实现的方法很简单,就是将表中最后一个结点的指针域指向头结点即可(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;    //选定的数字为 5public 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; } }}




0 0