假设有N个人,决定选出一个领导人,方法如下:
所有人排成一个圆圈, 按顺序数数,每隔第M个人出局,此时,他两边的人靠拢,重新排成一个圆圈,找出哪个人将会是最后一个留下的。 (比如N = 9 , M = 5 . 出局顺序为 5 1 7 4 3 6 9 2 剩下 8)
链表节点结构体
typedef struct node_S
{
int value;
struct node_S *next;
} node_T, *link;
一、创建链表
link create_link(node_T *head)
{
int i;
node_T *p, *q;
p = head;
for (i = 2; i < N + 1; i++)
{
q = (link)malloc(sizeof(node_T));
// 赋值 1 2 .. N
q->value = i;
p->next = q;
p = q;
// 循环
q->next = head;
}
return head;
}
二、释放节点
void free_node(node_T *node)
{
//printf("node: %p\n", node);
free(node);
node->next = NULL;
node = NULL;
}
三、执行约瑟夫逻辑流程
node_T *do_josephus(node_T *head)
{
int i;
link q;
link p = head;
/* 当thd 至少为 2 的情况下 */
//while (p->next) // 此处错误, 最终 p->next = p; 即 p->next != NULL
//while (p->next != p) // 判定条件为不指向自己, thd >= 2; 最后一位 p->next = p;
//while (p->next != p && p->next == NULL) // 兼容 thd = 1; 因为最后一位 p->next = head 而此时head = NULL;
while (p->next != p)
{
if (thd == 1)
{
if (p->next != head) // 检查是否指向最后一位 p->next = head; 即便 head = NULL; p->next == NULL is not
{
q = p;
p = p->next;
}
else
{
break;
}
}
else
{
for (i = 1; i < thd - 1; i++) // 指向出局者前一个
{
p = p->next; // if thd = 3, p point 2;
}
q = p->next;
p->next = q->next;
p = p->next;
}
printf("%d ", q->value);
free_node(q);
}
printf("%d ", p->value);
printf("\n");
return p;
}
四、测试打印 链表数据
void test_print(node_T *head)
{
int i;
link p = head;
for (i = 1; i < N + 1; i++)
{
printf("%d ", p->value);
p = p->next;
}
printf("\n");
}
五、主函数
#include <stdio.h>
#include <stdlib.h>
typedef struct node_S
{
int value;
struct node_S *next;
} node_T, *link;
int thd, N;
int main(int argc, const char *argv[])
{
int i;
node_T *last;
node_T *head, *p, *q;
if (argc != 3)
{
printf("Usage: a.out <total> <thd>\n");
return -1;
}
N = atoi(argv[1]);
thd = atoi(argv[2]);
// 创建头节点
head = (link)malloc(sizeof(node_T));
head->value = 1;
head->next = NULL;
// 创建循环链表
create_link(head);
// 测试打印
test_print(head);
// 执行
last = do_josephus(head);
return 0;
}
附: 标准程序 (算法:C语描述 )
- 由于创建链表采用 最后创建的元素为起点, 因此不用单独处理 N = 1 的情况
#include <stdio.h>
#include <stdlib.h>
typedef struct node *link;
struct node
{
int item;
link next;
};
int N , M;
void test_print(link head)
{
int i;
link p = head;
for (i = 1; i < N + 1; i++)
{
printf("%d ", p->item);
p = p->next;
}
printf("\n");
}
int main(int argc, const char *argv[])
{
int i;
if (argc != 3){
printf("Usage: a.out <N> <M>\n");
return -1;
}
N = atoi(argv[1]);
M = atoi(argv[2]);
// 创建头节点
link t = malloc(sizeof *t), x = t;
t->item = 1;
t->next = t;
// 创建链表
for (i = 2; i <= N; i++)
{
x = (x->next = malloc(sizeof *x));
x->item = i;
x->next = t; // 此时x指向末尾元素 x->next = t;(头)
}
// 测试打印
test_print(t);
// 执行约瑟夫
while (x != x->next)
{
for (i = 1; i < M; i++)
x = x->next;
x->next = x->next->next; // 从末尾开始,因此不用单独 处理 N为1的情况
N--;
}
printf("%d\n", x->item);
return 0;
}