数据结构抽奖数人链表实验题目与解答
一、**实验题目**
抽奖游戏:
n个人围成一圈,由第一个人开始,依次报数,数到第m人,便抽出来作为中奖人,然后从他的下一个人数起,数到第m人,再抽出来作为中奖人,如此循环,直到抽出k个为止。问哪些人中奖了。
每个人都有自己的编号,最后给出中奖人编号
完整代码在最后
二、**实验环境**
Windows 11
Visual Studio Code
三、**实验过程**
*顺序存储结构实现:*
*思路分析:*
创建一个大小为n的数组,用来存储所有人的编号
使用一个变量index来记录当前报数的位置。
使用一个变量k来记录当前还未中奖的人数。
当k>0时,从index开始循环数组,每数到第m个人,就将其编号输出,并从数组中移除该编号。
更新index为下一个未中奖人的位置。
当k=0时,结束循环。
代码:
在main函数中测试上述代码:
测试结果:
*链式存储结构实现:*
*思路分析:*
初始化链表,编号从1开始
如果首节点就是要找的数,则把首节点的下一个节点设为首节点
如果循环链表只剩一个元素,则删完之后要置为null
该链表需要一个data用于存储数据,一个指针指向下个节点
代码:
在main函数中测试上述代码:
测试结果:
四、**实验心得**
在本次实验中,我深入探索了数据结构的魅力,通过实现一个抽奖游戏,我不仅巩固了对顺序存储结构和链式存储结构的理解,还提升了我的编程实践能力。
首先,我根据实验要求,设计了一个抽奖游戏的算法。在这个游戏中,n个人围成一圈,从第一个人开始依次报数,每数到第m个人就将其抽出,直到抽出k个中奖人为止。
这个游戏规则简单,但背后却涉及到了数组和链表这两种基本数据结构的使用。 在实现顺序存储结构的版本时,我使用了一个大小固定的数组来存储参与者的编号。初始化数组时,我将每个人的编号依次赋值给数组的每个元素。在抽奖过程中,我通过循环和条件判断来模拟报数过程,并在每次报数到m时,输出中奖者的编号,并从数组中移除该编号。这个过程需要特别注意数组元素的移动和数组长度的更新。
接着,我尝试使用链式存储结构来实现同样的功能。与数组不同,链表可以动态地插入和删除节点。在抽奖过程中,我遍历链表,每数到第m个人,就删除当前节点并输出其编号。链表的动态特性使得删除操作变得更加直观和方便。
通过这次实验,我体会到了顺序存储结构和链式存储结构各自的优势和局限性。顺序存储结构在随机访问时效率较高,但插入和删除操作需要移动大量元素,而链式存储结构在插入和删除操作上更为高效,但随机访问时需要遍历链表。这两种数据结构的选择取决于具体问题的需求。
LinkCunChu:
#include <iostream>
#include <vector>
using namespace std;
// 链式存储结构
// 定义链表节点
typedef struct Node
{ int data;
struct Node *next;
} Node;
// 初始化链表
Node *InitLinkedList(int n)
{ Node *head = NULL;
Node *prev = NULL;
for (int i = 0; i < n; ++i)
{ Node *node = (Node *)malloc(sizeof(Node));
node->data = i + 1; // 编号从1开始
node->next = NULL;
if (head == NULL)
{ head = node;
}
else
{ prev->next = node;
}
prev = node;
}
prev->next = head; // 形成环形链表,方便循环取数
return head;
}
// 删除链表中指定节点
void DeleteNode(Node **head, Node *target)
{ if (*head == target) //如果首节点就是要找的数,则把首节点的下一个节点设为首节点
{ if ((*head)->next == *head) //如果循环链表只剩一个元素,则删完之后要置为null
{ free(*head);
*head = NULL;
}
else //如果链表不止一个元素
{ Node *temp = *head;
//获得首节点的前置节点
while (temp->next != *head)
{ temp = temp->next;
}
//将头节点的前置节点与后趋节点相连
temp->next = (*head)->next;
free(*head);
*head = temp->next;
}
}
else
{ Node *current = *head;
//获得要找的前驱节点
while (current->next != *head && current->next != target)
{ current = current->next;
}
if (current->next == *head) //遍历完仍未找到目标点
{ return;
}
Node *temp = current->next;
current->next = temp->next;
free(temp);
}
}
// 求解中奖人编号
void resultLianShiList(int n, int m, int k)
{ Node *head = InitLinkedList(n);
Node *current = head;
printf("中奖人编号:");
while (k > 0)
{ //向后m个位置取数
for (int i = 0; i < m - 1; ++i)
{ current = current->next;
}
Node *temp = current;
current = current->next;
printf("%d ", temp->data);
DeleteNode(&head, temp);
k--;
}
printf("\n");
// 释放链表节点
while (head != NULL)
{ Node *temp = head;
head = head->next;
free(temp);
}
}
int main()
{ int n, m, k;
printf("游戏参与数n,报数间隔m,中奖人数k:");
scanf("%d", &n);
scanf("%d", &m);
scanf("%d", &k);
// 使用链式存储结构求解
printf("链式存储结构求解:\n");
resultLianShiList(n, m, k);
}
ShunXuCunChu:
#include <iostream>
#include <vector>
using namespace std;
typedef struct
{ int data[1000];
int length;
} ShunXuList;
// 初始化顺序表
void InitShunXuList(ShunXuList *L, int n)
{ L->length = n;
//为每个元素添加编号
for (int i = 0; i < n; ++i)
{ L->data[i] = i + 1;
}
}
// 删除顺序表中指定位置的元素
void DeleteByIndex(ShunXuList *L, int index)
{
//从index处开始将所有的元素 向前覆盖一位
for (int i = index; i < L->length - 1; ++i)
{ L->data[i] = L->data[i + 1];
}
//长度减一
L->length--;
}
// 求解中奖人编号
void resultShunXuList(int n, int m, int k)
{ ShunXuList L;
InitShunXuList(&L, n);
int index = 0;
printf("中奖人编号:");
while (k > 0)
{
//向后数m个,因为自己也要算在内,所以要减一
index = (index + m - 1) % L.length;
printf("%d ", L.data[index]);
//删除已取
DeleteByIndex(&L, index);
k--;
}
printf("\n");
}
int main()
{ int n, m, k;
printf("游戏参与数n,报数间隔m,中奖人数k:");
scanf("%d", &n);
scanf("%d", &m);
scanf("%d", &k);
// 使用顺序存储结构求解
printf("顺序存储结构求解:\n");
resultShunXuList(n, m, k);
}