问题描述:
一、循环链表实现约瑟夫问题
思路:
创建一个循环链表,按顺序依次列入结点。进行遍历,遍历为第 m 个的结点删除,连接该节点的前一个和后一个结点,保持链表的完整性
循环链表实现的关键点:
1、如何搭建循环链表
2、如何查找并且删除指定结点,且不影响整个链表的完整性
实现:
循环链表的搭建(在研究此代码前,建议先了解一下链表的原理图像)
Link headnode = (Link)malloc(sizeof(Monkey));
headnode->next = NULL;
Link tailNode,pNode,qNode;
while(1){
scanf("%d %d",&n,&m);
if(n==0 || m==0){
free(headnode);
break;
}else{
tailNode = headnode; //tailNode指针一定要在这里进行初始化,如果在循环外初始化,那么第一次
//约瑟夫环完成之后尾结点就无法初始化指向头结点,后续就不能重新插入结点
while(i<=n){
//循环,插入结点
pNode = (Link)malloc(sizeof(Monkey))
pNode->data = i;
//尾插法插入结点
tailNode->next = pNode; //将pNode放入链表中
pNode->next = headnode->next; //关键:令最后一个结点的指针域指向第一个结点的位置,构成循环
tailNode = pNode; //令尾指针指向新的结点pNode
i++;
}
}
}
查找并删除结点
Link headnode = (Link)malloc(sizeof(Monkey));
headnode->next = NULL;
Link tailNode,pNode,qNode;
int answer[300];
int count = 0;
int n,m;
int i=1;
while(1){
pNode = headnode->next; //对要进行遍历查找的指针进行初始化
qNode = tailNode; //这个指针指向遍历查找的指针的前一个结点,便于结点的删除操作
while(pNode != qNode){
//循环,如果pNode != qNode,即链表不只含有一个结点时
if(i!=m){
//判断,一个一个数,如果没有数到第 m 个,就都向后移动一位
qNode = pNode;
pNode = pNode->next;
i++;
}else{
qNode->next = qNode->next->next; //数到了,令查找的指针pNode的前一个指针pNode的指针域指向 pNode的
//下一个结点的指针域,即将pNode结点跳过
free(pNode); //删除节点
pNode = qNode->next; //再初始化pNode结点,继续数
i = 1;
}
}
}
}
源码:
#include<stdio.h>
#include<malloc.h>
typedef struct monkey{
int data;
struct monkey* next;
}Monkey,*Link;
int main(){
Link headnode = (Link)malloc(sizeof(Monkey));
headnode->next = NULL;
Link tailNode,pNode,qNode;
int answer[300];
int count = 0;
int n,m;
int i=1;
while(1){
scanf("%d %d",&n,&m);
if(n==0 || m==0){
free(headnode);
break;
}else{
tailNode = headnode; //tailNode尾指针一定要在这里进行初始化,如果在循环外初始化,那么第一次约瑟夫环完成之后尾指针就无法初始化指向头结点,后续就不能重新插入结点
while(i<=n){
//循环,插入结点
pNode = (Link)malloc(sizeof(Monkey));
pNode->data = i; //尾插法插入结点
tailNode->next = pNode;
pNode->next = headnode->next; //令最后一个结点的指针域指向第一个结点的位置,构成循环
tailNode = pNode; //令尾指针指向新的结点pNode
i++;
}
pNode = headnode->next; //对要进行遍历查找的指针进行初始化
i = 1;
qNode = tailNode; //这个指针指向遍历查找的指针的前一个结点,便于结点的删除操作
while(pNode != qNode){
//循环,如果pNode != qNode,即链表不只含有一个结点时
if(i!=m){
//判断,一个一个数,如果没有数到第 m 个,就都向后移动一位
qNode = pNode;
pNode = pNode->next;
i++;
}else{
qNode->next = qNode->next->next; //数到了,令查找的指针pNode的前一个结点pNode的指针域指向 pNode的下一个结点的指针域,即将pNode结点跳过
free(pNode); //删除节点
pNode = qNode->next; //再初始化pNode结点,继续数
i = 1;
}
}
}
headnode->next = qNode; //该语句是保障头结点与最后留下的结点保持链接
answer[count] = pNode->data; //用数组记录此次循环找到的“猴王”
count++;
free(pNode);
headnode->next = NULL; //再初始化头结点
}
for(int j=0;j<count;j++) //遍历每次找到的猴王
printf("%d\n",answer[j]);
return 0;
}
二、数组下标实现约瑟夫问题
思路:定义一个数组,初始化存在猴子的元素。遍历时如果元素为0,则跳过,如果元素不为0,则将该元素变为0,直到数组中只剩下一个数组元素不为0
关键:
在遍历到最后一个元素的时候,如何回到第一个元素再遍历
如何在遍历到最后一个元素后再回到第一个元素
int n,m,Monkey;
int count = 0;
int answer[count];
int i = 1;
int pos;
while(1){
i = 1;
Monkey = n;
pos = 0; //下标标志,重中之重的标志
while(Monkey>1){
//循环条件:如果猴子不止一个
if(monkey[pos]>0){
//判断,数组中这个位置的元素是不是为零,若为零,则这里的猴子被丢出去了;不为零,则有猴子存在
if(i != m){
//再进行判断,如果这个位置不是要数到的第 m 个,则往后 pos 移动一位
i++;
pos = (pos+1)%n; //关键:它使得每次下标都会移动后一位,而且如果下标指向了最后一个猴子,那么他就会移
//动到数组的第一个位置,即第一个猴子的位置
}else{
monkey[pos] = 0; //如果判断成功,是第 m 个,那么将这个位置的猴子丢了,并且数组元素赋值为 0 ,表示没有猴子
i = 1;
Monkey--;
pos = (pos+1)%n;
}
}else{
pos = (pos+1)%n;
}
}
}
源码:
#include<stdio.h>
int main(){
int n,m,Monkey;
int count = 0;
int answer[count];
int i = 1;
int pos;
while(1){
scanf("%d %d",&n,&m);
if(n==0 || m==0)
break;
else{
int monkey[301] = {
0}; //数组初始化
for(int j=0;j<n;j++){
monkey[j] = i;
i++;
}
i = 1;
Monkey = n;
pos = 0; //下标标志,重中之重的标志
while(Monkey>1){
//循环条件:如果猴子不止一个
if(monkey[pos]>0){
//判断,数组中这个位置的元素是不是为零,若为零,则这里的猴子被丢出去了;不为零,则有猴子
if(i != m){
//再进行判断,如果这个位置不是要数到的第 m 个,则往后 pos 移动一位
i++;
pos = (pos+1)%n; //这个语句非常重要,它使得每次下标都会移动后一位,而且如果下标指向了最后一个猴子,那么他就会移动到数组的第一个位置,即第一个猴子的位置
}else{
///如果判断成功,是第 m 个,那么将这个位置的猴子丢了,并且数组元素赋值为 0 ,表示没有猴子
monkey[pos] = 0;
i = 1;
Monkey--;
pos = (pos+1)%n;
}
}else{
pos = (pos+1)%n;
}
}
for(int j=0;j<n;j++){
//遍历猴子数组,将不为 0 的数组元素赋值到answer[]数组中
if(monkey[j]>0){
answer[count] = monkey[j];
count++;
}
}
}
}
for(int j=0;j<count;j++)
printf("%d\n",answer[j]);
return 0;
}
可以复制这个代码在编译软件再研究,如果仍然有问题,推荐一个视频,这个视频讲的非常的清晰
懒猫老师约瑟夫问题