记录复习自用。。
约瑟夫环问题描述:约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1,最后 结果+1即为原问题的解。
解题时参考了小甲鱼数据结构视频。
下面贴代码:
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef int Elemtype;
typedef struct Node {
Elemtype data;
Node *next;
}List,*NodeList;
//构建循环链表//
NodeList Create_List(int n) {
//创建一个循环链表,由1-n逐一给结点编号
//值就是编号
int i = 1;
NodeList P, PHead;
PHead = (Node *)malloc(sizeof(Node));
PHead->next = NULL;
P = PHead;
NodeList S; //S用来进行空间分配
if (n != 0) {
while (i <= n) {
S = (Node *)malloc(sizeof(Node));
S->data = i;
S->next = NULL;
P->next = S;
P = S;
i++;
}
//当退出循环的时候P指向了最后一个结点
//我们要让最后一个结点指向第一个结点,并且free掉头结点
P->next = PHead->next;
free(PHead);
return P->next; //返回的是第一个结点
}
else {
printf("输入不合法\n");
return NULL;
}
}
//遍历循环链表//
void Traverse(NodeList P) {
NodeList P1;
P1 = P;
printf("循环链表为:\n");
while (P1->next != P) {
//如果是最后一个结点就跳出
printf("->%d\n", P1->data);
P1 = P1->next;
}
printf("->%d", P1->data);
}
//打印约瑟夫环的出列顺序//
void Joseph_circle(NodeList P, int n, int m) {
//有n个结点,并且对m求余,返回0 - m-1的数
//设定一个指针指向链表,并且跟着计数器走
//当返回的是m-1时,应该删除这个结点
int count = 1;//计数器
NodeList P1;
for(int i = 1; i < m-1; i++)
P = P->next; //刚刚开始由于指向第一个结点,所以要少一次循环
P1 = P->next; //P1即为要删去的结点
printf("NO.%d->%d\t", count, P1->data);
count++;
P->next = P1->next;
free(P1);
while (P != P->next) {
//当P不是最后的一个结点时
for (int i = 1; i <= m - 1; i++)
P = P->next;//循环结束时P指向要删除的结点的前一个结点
P1 = P->next; //同上,P1为要删除的结点
P->next = P1->next;
printf("NO.%d->%d\t", count, P1->data);
count++;
if (count % 3 == 0)
printf("\n");
free(P1);
}
printf("NO.%d->%d\n", count, P->data);
}
int main()
{
int n = 41; //一共有32个人
int m = 3; //对3求余,返回0-2 3个数
NodeList P;
P = Create_List(n);
//Traverse(P);
printf("移出列表的顺序是:\n");
Joseph_circle(P, n, m);
return 0;
}
输出结果: