数据结构——01-抽奖数人-链表-实验题目与解答

一、实验题目

抽奖游戏:

n个人围成一圈,由第一个人开始,依次报数,数到第m人,便抽出来作为中奖人,然后从他的下一个人数起,数到第m人,再抽出来作为中奖人,如此循环,直到抽出k个为止。问哪些人中奖了。

每个人都有自己的编号,最后给出中奖人编号

完整代码在最后

二、实验环境

Windows 11

Visual Studio Code

三、实验过程

顺序存储结构实现:

思路分析:

创建一个大小为n的数组,用来存储所有人的编号

使用一个变量index来记录当前报数的位置。

使用一个变量k来记录当前还未中奖的人数。

当k>0时,从index开始循环数组,每数到第m个人,就将其编号输出,并从数组中移除该编号。

更新index为下一个未中奖人的位置。

当k=0时,结束循环。

代码:

img

img

在main函数中测试上述代码:

img

测试结果:

img

链式存储结构实现:

思路分析:

初始化链表,编号从1开始

如果首节点就是要找的数,则把首节点的下一个节点设为首节点

如果循环链表只剩一个元素,则删完之后要置为null

该链表需要一个data用于存储数据,一个指针指向下个节点

img

img

代码:

img

在main函数中测试上述代码:

img

测试结果:

img

四、实验心得

在本次实验中,我深入探索了数据结构的魅力,通过实现一个抽奖游戏,我不仅巩固了对顺序存储结构和链式存储结构的理解,还提升了我的编程实践能力。

首先,我根据实验要求,设计了一个抽奖游戏的算法。在这个游戏中,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);
 ​
 }
 ​

  • 24
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

被瞧不起的神

谢谢啦,感谢支持|一起努力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值