目录
1.用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。
1.用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。
(1)数组形式
//1.数组方式
/*
* 约瑟夫环思路:
* 1.假设有n个人,数到m的人出列,因为是循环数数,没有必要m要小,比如5个数,那m也可以是6.
* 2.从1开始给n个人编号
* 2.定义Num,从1开始,数到m,num==m时,此时这个数据输出并从数组中删除,之后又从1开始数
* 3.每次检验到的数据要先保存,再拿出数组,检验过后,可选择是否放回数组,如果不是该退出的数据,就要补在当前数组的最后边,比如数组1 2 3 4 5 ,先拿出1,发现不是该放出去的数据,再次放回时,数组就变成了2 3 4 5 1
4.由3可知每次移出数组的数同时,后面的数要通通前移,被检验的数可选择放在最后,或者出数组。
5.关于循环,每次退出数据的数据那数组长度就要--,当数组长度为0时,便结束循环,输出最后留下的数。
*/
int JosephRing(int* arr, int m, int n)//n是总人数,m是数到m的人出列
{
for (int i = 1; i <= n; i++)//给n个人编号,从1开始
{
arr[i] = i;
}
int num = 0;
int index = 1;//被检验数据的下标
int temp = 0;
while (n)
{
num++;//从1开始数到m,叫到m的数出数组
temp = arr[index];//临时变量保存被检验的数
arr[index] = 0;//待检验的数移出数组
for (int i = index + 1; i <= n; i++)
{
arr[i-1] = arr[i];
//arr[i]=arr[i+1];//如果是这样往前移动的话,i第一趟是从2开始的,那下标是1的位置就没有数,而且会吧2下标原来元素覆盖掉
}
if (num == m)//数到要退出的数
{
num = 0;
n--;
// printf("%5d", temp);
continue;//如果数到要退出的数,那不必执行 arr[n] = temp,continue关键字会结束此时的循环,开始下一轮循环,不需要往下执行。
}
arr[n] = temp;//被移出的数放在最后边
}
return temp;
}
int main()
{
int arr[256];
int m, n;
scanf_s("%d %d", &n,&m);
int res = JosephRing(arr, m, n);
printf("留下的人是:%d\n", res);
}
截图:
(2)循环链表
struct node
{
int data;//数据域
struct node* next;// 指针域
};
int main()
{
int m, n;//n个人,报到m的人出列
int answer[100];//存储答案的数组
int i;//从1到m循环数数
int count=0;//控制答案的下标
struct node * head, * tail, * p, * q;//p指向当前节点,q是p的下一节点
//初始化链表
//1.申请节点空间
head = (struct node*)malloc(sizeof(struct node));//注意malloc的用法
//指针域不使用,但为了调式方便,值定为-1
//head->data = -1;
head->next = NULL;//只申请一个节点,指针域指向空
//循环处理多组数据
while (1)
{
scanf_s("%d %d", &n, &m);
if (m == 0 || n == 0)//输入0 0 时,代表结束输出
{
free(head);//释放节点的空间,
break;
}
else
{
//从1开始给n个人编号
tail = head;//最初只有一个节点
for (i = 0; i < n; i++)
{
//尾插法编号,tail指向最后的节点
//1.申请节点
p = (struct node*)malloc(sizeof(struct node));
//2.填数据
p->data = i + 1;
//3.插到尾部
tail->next = p;
//4.前后链接
p->next = head->next;
tail = p;//tail移动到最后一个节点,
}
p = head->next;//p是第一个节点
q = tail;//p在最前面,最后一个节点是第一个节点的前继节点
i = 1;//准备开始报数
//删除操作
while (p != q)//q一直在p的后面,一旦相等时,说明只剩一个节点
{
if (i == m)
{
//跨越式删除
q->next = q->next->next;
free(p);
//p移向下一个有效节点
p = q->next;
i = 1;//重新开始下一轮报数
}
else//正常通过的数据
{
q = p;
p = p->next;
//继续数下一个数
i++;
}
}
head->next = q;//当只剩下两个节点的时候,再次删除会造成链表不完整,在这个程序中,不是必要的
answer[count] = p->data;//保存余下的数
count++;
free(p);
head->next = NULL;//链表清空
}
}
for (i = 0; i < count; i++)
{
printf("%2d", answer[i]);
}
free(head);
return 0;
}
截图:
要常常写代码呀,不然真的会忘,加油吧!