前言:
不知道单链表的可以先看看我之前的文章 我还是个初学者 所以不懂的地方还很多 望谅解。c ++c语言单链表头插法尾插法以及删除结点的操作(简化版) 学习笔记
一.问题
设有n个人围坐一圈并按顺时针方向从1到n编号,从第1个人开始进行1到m的报数,报数到第个m人,此人出圈,再从他的下一个人重新开始1到m的报数,如此进行下去直到所剩下一人为止。
输入
输入多行,每行2个数,分别表示n和m.
输出
计算每一行中最后剩下这个人的编号.
样例输入
10 3
样例输出
4
二.解题思路
因为题目涉及循环以及删除元素操作 可以运用单链表循环 可快速查找删除结点. 因为最终只剩一人时结束,所以当单链表循环里 单链表里只剩一个结点循环(即 结点指向本身)时,宣告结束。
三.解决问题步骤
1.创建一个单链表
#include<iostream>
using namespace std;
//创建单链表
typedef struct Node
{
int data;
struct Node* next;
}Node;
2.定义n,m,输入n,m
3.将数据传入链表之中
首先 仍是以单链表的形式 运用for循环 进行尾插数据操作 再 使最后一个元素指向第一个元素 完成链表循环
int n, m;
cin >> n>>m;
Node * head = new Node; //定义首结点head 并分配空间 将head data域 指向1
head->data = 1;
Node* p = new Node; //定义 p结点 = head结点 作为head结点的分身
p = head;
for (int i = 2; i <= n; i++) //将从2到n 分别被指向每一个结点的data域
{
Node* node = new Node; //定义新结点node 并为其分配空间
node->data = i; //node data域 指向 i
p->next = node; //首结点 p 指向 node
p = node; //最后再将 node地址 给p 作为node的分身 下一轮p为node的值
head->data++; //更新链表的长度(不写问题也不大)
}
//循环结束 将单链表成为单链表循环
p->next = head; //最后一个元素连接第一个元素
4.定义 i = 1; Node * q = new Node;
定义一个i值,每次i +1= m时,进行结点删除,然后直到仅剩一个结点,即为所求值。
int i = 1;
Node* q = head; //q在下层循环使用 先声明定义
5.while死循环为大框架
whlie(true)
{
}
6.在while大框架里进行操作
继续内层while循环 来进行不断删减 循环条件 为 head->next != head head的值是不断更新的 意为当最后一个结点指向本身时 打破该while循环 先看一遍代码
首先 默认从2开始,因为最少2人才能进行这个游戏,即若m = 2 时,通过if语句判断条件,1 指向 3 删除2 再将 3 的地址赋予 1 ;继续进行操作 此时依然满足判断条件 1 指向 5 删除 4 将 5 的地址 赋予 1 以此类推...
若 m != 2,则 if语句最后 i=1; 的用途就出来了,听我分析: 若是 m = 4 ,则刚开始 i = 1,进行if判断 无法通过,进行else语句 head进行地址++,即从 1 变成了 2,i++ => i =2; 继续进行循环 if判断 无法通过 进行else语句 head进行地址++ ,即从 2 变成了 3,i++ => i = 3; 继续进行循环 if判断成功, 进行删除操作 ,将 3 指向 5 删除4 ,再将 5 的地址赋予 3 , i 又 变回了 1 ,此时 3继续进行else语句 地址++ 5 变成=> 6 再一次进行else语句 地址++ 6 变成=> 7,此时进行了两次i++ i=3又满足了 i + 1 = m 继续进行删除 以此类推...若没有if语句中的i = 1;第一次正常删除 但在进行第二次删除时 仅仅只是相邻数的删除操作 5 指向 7 删除 6
while (head->next != head)//当第一个元素独自循环
{
if (i + 1 == m) // 满足此条件 进行结点删除操作
{
q = head->next; 删除head 指向下一个结点
head->next = q->next;
delete(q);
head = head->next; 并将 head 下一个的下一个结点 赋予给 head
i = 1;
}
else
{
head = head->next; //head = 下一个结点的地址
i++;
}
}
7.若只剩最后一个人 结束while死循环
当内层while循环不再执行时,head此时的data域的值 为 最终值 此时再break 外层while死循环 即 满足head-> next = head break
while(true)
{
while (head->next != head)//当第一个元素独自循环
{
if (i + 1 == m) // 满足此条件 进行结点删除操作
{
q = head->next; 删除head 指向下一个结点
head->next = q->next;
delete(q);
head = head->next; 并将 head 下一个的下一个结点 赋予给 head
i = 1;
}
else
{
head = head->next; //head = 下一个结点的地址
i++;
}
}
if (head->next = head)
{
break;
}
}
8.在外层while循环外输出最终值head->data
cout << head->data << endl;
四.完整代码
#include<iostream>
using namespace std;
//创建单链表
typedef struct Node
{
int data;
struct Node* next;
}Node;
int main()
{
int n, m;
cin >> n>>m;
Node * head = new Node;
head->data = 1;
Node* p = new Node;
p = head;
for (int i = 2; i <= n; i++)
{
Node* node = new Node;
node->data = i;
p->next = node;
p = node;
head->data++;
}
p->next = head; //最后一个元素连接第一个元素
//定义一个i值,每次 i + 1 = m时,此结点删除,然后直到仅剩一个结点,即为所求值。
int i = 1;
Node* q = new Node;
while (true)
{
while (head->next != head)//当第一个元素独自循环
{
if (i + 1 == m)
{
q = head->next; // 不加 i = 1 加 i = 1
head->next = q->next; // m = 3 i = 1 m = 3 i = 1
delete(q); // head = 2 i = 2 head = 2 i = 1
head = head->next; // head = 4 i = 2 head = 5 i = 2
i = 1; // head = 6 i = 2 head = 7 i = 1
}
else
{
head = head->next;
i++;
}
}
if (head->next = head)
{
break;
}
}
cout << head->data << endl;
return 0;
}
五.代码运行结果
六.c语言格式
注意:(我使用的是vs2022 scanf的写法为scanf_s)
完整代码:
#include<stdio.h>
#include<stdlib.h>
//创建单链表
typedef struct Node
{
int data;
struct Node* next;
}Node;
int main()
{
int n, m;
scanf_s("%d%d", &n, &m);
Node* head = (Node*)malloc(sizeof(Node));
head->data = 1;
Node* p = new Node;
p = head;
for (int i = 2; i <= n; i++)
{
Node* node = new Node;
node->data = i;
p->next = node;
p = node;
head->data++;
}
p->next = head; //最后一个元素连接第一个元素
//定义一个i值,每次 i + 1 = m时,此结点删除,然后直到仅剩一个结点,即为所求值。
int i = 1;
Node* q = (Node*)malloc(sizeof(Node));
while (true)
{
while (head->next != head)//当第一个元素独自循环
{
if (i + 1 == m)
{
q = head->next; // 不加 i = 1 加 i = 1
head->next = q->next; // m = 3 i = 1 m = 3 i = 1
free (q); // head = 2 i = 2 head = 2 i = 1
head = head->next; // head = 4 i = 2 head = 5 i = 2
i = 1; // head = 6 i = 2 head = 7 i = 1
}
else
{
head = head->next;
i++;
}
}
if (head->next = head)
{
break;
}
}
printf("%d", head->data);
return 0;
}