题目:已知head指向一个不带头结点的环链表,链表中每个结点包含数据域(num)和指针域(link)。数据域存放整数,第i个结点的数据域值为i。编写函数,利用环形链表模拟猴子选大王的过程:从第一个结点开始循环“报数”,每遇到k的整数倍,就将相应的结点删除。如此循环直到链表中剩下一个结点,就是猴王。
实现方法及要求:
声明如下结构体
struct list
{ int num;
List *link;
};
思路:
-
定义结构体
list
:- 用于表示环链表中的每个节点,包含猴子的编号
num
和指向下一个节点的指针link
。
- 用于表示环链表中的每个节点,包含猴子的编号
-
创建环链表:
- 使用
creat
函数创建一个包含n
个节点的环链表,每个节点表示一个猴子。 - 每个节点的编号从1到n,最后一个节点的
link
指向头节点,形成环状链表。
- 使用
-
输出环链表:
- 使用
printList
函数输出环链表的内容,以验证链表的正确性。
- 使用
-
选猴王:
- 使用
choice
函数实现猴子出局的逻辑。 - 根据报数基数
k
,循环遍历环链表,删除报数为k
的猴子。 - 最终输出剩下的猴子,即为猴王。
- 使用
-
主函数:
- 通过用户输入获取猴子个数
n
和出局基数k
。 - 调用
creat
创建环链表,输出初始环链表。 - 调用
choice
选出猴王,输出结果。
- 通过用户输入获取猴子个数
代码:
#include <stdio.h>
#include <malloc.h> //函数malloc(),free()的头文件
#include <stdlib.h> //函数exit()的头文件
/*声明结构体*/
struct list
{
int num;
list* link;
};
/* 建立环链表*/
list* creat(int n) //参数n是结点个数,参数k是删除结点的基数
{
int i = 1; //为结点数据赋值
list* head; //定义指向链表起始地址的指针,作用是将第一个结点和最后一个结点连接起来
list* pSet; //开辟存储空间,建立结点
list* pEnd; //连接前后结点
head = NULL;
pEnd = head;
do
{
pSet = (list*)malloc(sizeof(list)); //开辟存储空间
if (pSet == NULL)
{
printf("没有足够空间,申请失败!");
exit(0);
}
if (head == NULL) head = pSet; //如果是头结点,由head指向头结点
else pEnd->link = pSet; //如果不是头结点,建立前一结点和新建结点的连接
pSet->num = i; //为结点的数据赋值
if (pSet->num > n)
{
pEnd->link = head;
free(pSet);
break; //结束循环
}
else
pEnd = pSet;//pEnd建立连接后,指向新建结点
++i;
} while (1);
return head;
}
/*输出环链的值*/
void printList(list* head)
{
list* pSet = head;
if (pSet == NULL)
{
printf("链表为空");
return; // 退出函数,返回到主函数
}
while (1)
{
printf("%4d", pSet->num);
pSet = pSet->link;
if (pSet->link == head)
{
printf("%4d", pSet->num);
pSet = pSet->link;
if (pSet->link == head)
{
printf("%4d", pSet->num);
break;
}
}
printf("\n");
}
/*选猴王*/
void choice(list* head, int k)
{
int i = 1; //记录报数
list* pEnd = head;
while (pEnd->link != pEnd)
{
if (i % k == 0) //整数倍时删除结点
{
pEnd->link = pEnd->link->link;
printList(pEnd->link);
}
if (++i % k != 0) pEnd = pEnd->link;
}
printf("\n猴王是编号%d的猴子!\n", pEnd->num);
}
int main()
{
list* head;
int n; //n是结点个数
int k; //出局猴子数字的基数
printf("请输入猴子个数n>0:");
scanf("%d", &n);
if (n <= 0)
{
printf("数据有误!");
exit(0);
}
head = creat(n); //调用建立环链表函数
printList(head); //输出环链表
printf("请输入出局猴子数字的基数k:");
scanf("%d", &k);
printList(head); //输出环链表
printf("请输入出局猴子数字的基数k:");
scanf("%d", &k);
choice(head, k); //调用选猴王函数
}
- 程序通过链表的形式模拟了猴子围成一圈的情景,利用环链表的特性实现了猴子出局的循环过程。
- 使用结构体表示节点,便于管理每个猴子的信息。
- 注意在删除节点时,需要调整前一个节点的
link
指向,以维持环链表的结构。 - 程序通过输出中间过程,包括环链表的建立和猴子的出局情况,使得执行过程更加清晰。