线性表的链式存储结构
实验目的:
通过本次实验,掌握较复杂线性表的顺序存储结构、基本操作及应用。
实验原理:
数据结构的选择:选择链式存储结构是因为它可以动态地插入和删除节点,适合处理约瑟夫问题中的动态变化。
动态操作的实现:链式存储结构允许在不移动其他元素的情况下,通过改变指针来实现节点的插入和删除,这在约瑟夫问题中是必要的。
循环链表的特性:循环链表使得问题更加简洁,因为排除操作可以在一个环中完成,不需要特殊处理边界条件。
算法的效率:通过优化算法,例如使用两个指针(一个快指针和一个慢指针),可以提高解决约瑟夫问题的效率。
实验内容:
初始化链表:创建一个包含 n 个节点的循环链表,每个节点代表一个人,节点中存储编号信息。
报数和排除:从头节点开始,进行循环遍历,每次遍历到第 m 个节点时,将其从链表中删除(即断开该节点的前一个节点和后一个节点的连接),同时将头节点移动到下一个节点,继续进行报数和排除操作。
循环直至结束:重复上述步骤,直到链表中只剩下一个节点,该节点即为最终剩下的人,记录其编号。
输出结果:输出最后剩下的人的编号,即为约瑟夫问题的解。
实验步骤及结果:
#include<stdio.h>
#include<stdlib.h>
// 定义链表节点的结构体
typedef struct Node{
int data; // 存储节点的数据
struct Node* next; // 指向下一个节点的指针
} Node;
// 创建一个新节点的函数
Node* Create(){
Node* head; // 定义头指针
head = (Node*)malloc(sizeof(Node)); // 动态分配内存给新节点
if (head == NULL) { // 检查内存分配是否成功
exit(1); // 如果失败,则退出程序
}
head->next = NULL; // 新节点的下一个节点初始化为NULL
return head; // 返回新节点的指针
}
int main()
{
int n, m, i; // 定义变量n和m,分别代表人数和报数
Node * tail, * p, * q; // 定义尾指针、遍历指针p和q
Node* head = Create(); // 创建链表的头节点
// 提示用户输入人数和报数
printf("请输入围成一圈的人数: ");
scanf("%d", &n); // 读取用户输入的人数
printf("请输入报数出局的数字: ");
scanf("%d", &m); // 读取用户输入的报数
// 判断输入是否有效
if (n == 0 || m == 0) { // 如果人数或报数为0,则直接结束程序
return 0;
} else {
tail = head; // 初始时,尾指针指向头节点
// 循环创建新节点并插入到链表中
for (i = 0; i < n; i++) {
p = (Node*)malloc(sizeof(Node)); // 动态分配新节点
if (p == NULL) { // 检查内存分配是否成功
printf("申请失败!\n");
exit(1);
}
p->data = i + 1; // 设置新节点的数据
tail->next = p; // 将新节点插入到链表的尾部
p->next = head->next; // 新节点的下一个节点指向头节点的下一个节点
tail = p; // 更新尾指针为新节点
}
}
p = head->next; // 遍历指针p从第一个节点开始
q = tail; // 遍历指针q从最后一个节点开始
i = 1; // 报数从1开始
// 进行报数出局操作,直到链表中只剩下一个节点
while (p != q) {
if (i == m) { // 如果报数达到m,则当前节点p出局
q->next = p->next; // 将p的下一个节点连接到q的后面
printf("%d ", p->data); // 打印出局节点的数据
free(p); // 释放内存,防止内存泄漏
p = q->next; // 更新遍历指针p到下一个节点
i = 1; // 重新开始报数
} else { // 如果未达到报数m,遍历指针p和q都向后移动一位
q = p; // q先移动到p的位置
p = q->next; // 然后p移动到q的下一个位置
i++; // 报数加1
}
}
// 打印最后一个出局的节点的数据
printf("%d\n", p->data);
return 0; // 程序结束
}
结语
实验中通过C语言实现了约瑟夫问题,观察到链表的动态变化和算法执行过程,但存在效率和内存管理的问题。通过实验,我们可以观察到链表在每一步操作中的动态变化,包括节点的添加、删除和指针的更新。这有助于我们理解链表数据结构的特点和操作过程。
![](https://i-blog.csdnimg.cn/direct/9afbb1c5d9c049dbac864348414d0c6b.jpeg)