0.简介(在以下环境下运行通过):
运行环境:Linux(ubuntu12.10);
编译器:gcc;
语言:C语言;
作者:Catcher24。
1.问题描述:
用循环链表解决约瑟夫问题。
约瑟夫问题:(Josephus problem)
据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
2.数据结构描述与设计:
循环链表(空表为只有一个空节点的表,其link指针指向自身)很容易模拟一个环,其数据域可以用来储存编号,加上链表的删除操作,可以很简单的解决约瑟夫问题。
循环链表的实现以及约瑟夫问题的解决代码如下:
CircLinkedList.h:该头文件定义了一些需要实现的循环链表的基本函数以及Josephus函数:
1 /*Author:catcher qyjiang24@gmail.com 2 * ------------------- 3 * | node | link |---- 4 * ------------------ | 5 * ^ | 6 * |________________| 7 */ 8 #include <stdio.h> 9 #include <stdlib.h> 10 11 #ifndef _List_H 12 typedef int type; 13 typedef int bool; 14 typedef struct node{ 15 type data; 16 struct node* link; 17 }node; 18 typedef struct node* p_node; 19 20 #define false 0 21 #define true 1 22 23 p_node init(p_node l); //初始化函数 24 p_node get_head(p_node l); 25 void make_empty(p_node l); //将链表置空的函数 26 bool is_empty(p_node l); //判断链表是否为空 27 p_node find(type x,p_node l); //查找函数 28 p_node find_pre(type x,p_node l); //查找前驱节点 29 bool insert_node(type x,p_node l); //Insert a node 30 bool delete_node(type x,p_node l); //Delete a node 31 void delete_list(p_node l); //Delete list 32 void print_list(p_node l); //Print list 33 34 void Josephus(p_node l,int n,int m); //Handle Josephus question 35 #endif
上面的头文件给出各个函数的定义,下面给出函数实现:CircLinkedList.c文件:
1 #include "CircLinkedList.h" 2 3 p_node init(p_node l) 4 { 5 l = malloc(sizeof(node)); 6 l->link = l; 7 } 8 9 p_node get_head(p_node l) 10 { 11 return l; 12 } 13 void make_empty(p_node l) 14 { 15 p_node first = get_head(l); 16 if(first->link == first){//It's empty list now; 17 return; 18 } 19 p_node ptr = first->link; 20 while(ptr != first){ 21 p_node p = ptr; 22 ptr = ptr->link; 23 free(p); 24 } 25 first->link = first; 26 return; 27 } 28 29 bool is_empty(p_node l) 30 { 31 return (l->link == l)? true:false; 32 } 33 34 p_node find(type x,p_node l) 35 { 36 p_node ptr = find_pre(x,l); 37 if(ptr != NULL) 38 ptr = ptr->link; 39 return ptr; 40 } 41 42 p_node find_pre(type x,p_node l) 43 { 44 p_node first = get_head(l); 45 if(l->link == first) 46 return NULL; 47 p_node ptr = first->link; 48 p_node p = NULL; 49 while(ptr->link != NULL){ 50 p = ptr; 51 ptr = ptr->link; 52 if(ptr->data == x) 53 return p; 54 } 55 return NULL; 56 } 57 58 bool insert_node(type x,p_node l) 59 { 60 p_node first = get_head(l); 61 if(is_empty(l)){ 62 p_node p = malloc(sizeof(node)); 63 p->link = first; 64 p->data = x; 65 first->link = p; 66 return true; 67 } 68 p_node ptr = first->link; 69 while(ptr->link != first){ 70 ptr = ptr->link; 71 } 72 p_node p = malloc(sizeof(node)); 73 p->link = first; 74 p->data = x; 75 ptr->link = p; 76 return true; 77 } 78 79 bool delete_node(type x,p_node l) 80 { 81 p_node pptr = find_pre(x,l); 82 p_node ptr = pptr->link; 83 pptr->link = ptr->link; 84 free(ptr); 85 return true; 86 } 87 88 void delete_list(p_node l) 89 { 90 p_node first = get_head(l); 91 p_node ptr = first->link; 92 while(ptr != first){ 93 p_node p = ptr; 94 ptr = ptr->link; 95 free(p); 96 } 97 free(first); 98 } 99 100 void print_list(p_node l) 101 { 102 p_node first = get_head(l); 103 p_node ptr = first->link; 104 while(ptr != first){ 105 printf("%d\t",ptr->data); 106 ptr = ptr->link; 107 } 108 printf("\n"); 109 } 110 111 void Josephus(p_node l,int n,int m) 112 { 113 //Initialization 114 int i,j; 115 for(i = 0;i < n;i++){ 116 insert_node(i+1,l); 117 } 118 p_node ptr = l->link; 119 p_node pre = NULL; 120 for(i = 0;i < n-1;i++){ 121 for(j = 0;j < m-1;j++){ 122 pre = ptr; 123 ptr = ptr->link; 124 if(ptr == get_head(l)){ 125 ptr = ptr->link; 126 } 127 } 128 printf("Number %d is dead\n",ptr->data); 129 delete_node(ptr->data,ptr); 130 ptr = ptr->link; 131 } 132 ptr = l->link; 133 printf("The winner is: %d\n",ptr->data); 134 }
下面给出测试文件main.c:
1 #include "CircLinkedList.h" 2 3 int main() 4 { 5 int m; 6 int n; 7 printf("Enter n:\n"); 8 scanf("%d",&n); 9 printf("Enter m:\n"); 10 scanf("%d",&m); 11 p_node p = NULL; 12 p = init(p); 13 Josephus(p,n,m); 14 return 0; 15 }
3.问题的解答:
测试与运行:
将三个文件放在一个目录下并使用命令:
gcc main.c CircLinkedList.h CircLinkedList.c -o main
编译,然后使用如下命令运行:
./main
结果如下图:
当然,也可以选择使用makefile来处理。