1.3循环单链表之约瑟夫问题
循环单链表
1、与单链表类似,循环单链表也有带头和不带头。循环单链表不为空时,尾结点指针域为头结点。为空时,头指针的指针域指向它本身。
2、带头结点的循环单链表为空的判断条件是head->next==head;
3、有时为了操作方便,循环单链表中只设尾指针。
约瑟夫问题:
有n个人,编号为1----n,围成一个圆圈,顺时针转,从第k个人开始报数1,然后报到m的人出列,他的下一个人开始继续从1报数,重复,直到所有人出列。要求n m k自己输入。
代码实现:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define ListSize 100
typedef int DataType;
typedef struct Node
{
DataType data;
struct Node* next;
}ListNode,*LinkList;
LinkList CreateCycList(int n); //创建一个长度为n的循环单链表
void Josephus(LinkList head,int n,int m,int k); //在长度为n的循环单链表中,找出编号为m的出列
int DisplayCycList(LinkList head); //输出循环单链表
void main()
{
LinkList h;
int n, k, m;
printf("输入环中个数:");
scanf_s("%d",&n);
printf("输入开始报数序号:");
scanf_s("%d", &k);
printf("报数为m的人出列,m为:");
scanf_s("%d", &m);
h = CreateCycList(n);
Josephus(h, n, m, k);
}
LinkList CreateCycList(int n)
{
LinkList head = NULL;
ListNode* p,*q=NULL;
for (int i = 1; i <= n; i++)
{
p = (ListNode*)malloc(sizeof(ListNode)); //在内存中划分空间
p->data = i; //将i赋值给p的数据域
p->next = NULL; //将p的地址域置空
if (head==NULL) //如果循环单链表为空,则将刚分的空间p当做第一个结点
{
head = p;
}
else //如果循环单链中已经有结点,则将p赋值给q的地址域,-----q是p的前一个结点
q->next = p;
q = p; //然后把p赋值给q
}
q->next = head;
return head;
}
void Josephus(LinkList head, int n, int m, int k) //在长度为n的循环单链表中,找出编号为m的出列
{
ListNode* p, * q=NULL;
p = head;
for (int i = 1; i < n; i++)
{
q = p;
p = p->next;
}
while (p->next!=p)
{
for (int i=1;i<=m;i++)
{
q = p;
p = p->next;
}
q->next = p->next;
printf("%4d\n",p->data);
free(p);
p = q->next;
}
printf("%4d\n",p->data);
}
int DisplayCycList(LinkList head) //输出循环单链表
{
ListNode *p=head;
if (head=NULL)
{
printf("链表为空表\n");
return 0;
}
while (p->next!=head)
{
printf("%4d",p->data);
p = p->next;
}
printf("%4d\n",p->data);
}