约瑟夫问题:输入一个数n,表述人数,再输入一个目标值target,从第一个人开始每数到target就将数到的人踢出去,直到剩余最后一个,用循环链表解决。
谈到链表,那么就一定有结构体及结构体指针,我们先声明一个结构体:
typedef struct Node{
int num; //人数序号
struct Node *next;//结构体指针
}node;
结构体中包含了两个元素:序号和指针。这里的指针,是指向下一个结构体指针,后面还会更多讲解。
结构体声明完毕,完成了链表创建的前置步骤,接下来我们创建链表:
node *CreatlistNode(int n){
node *head=NULL; //头指针
node *prev=NULL; //前置指针
for(int i=1;i<=n;i++){
node *new_node=(node*)malloc(sizeof(node)); //新链表节点创建
new_node->num=i; //该节点中序号赋值
if(head==NULL){ //创建第一个节点
head=new_node;
}else{ //链接下一个节点
prev->next=new_node;
}
prev=new_node; //更新前置指针
}
prev->next=head; //尾节点指向头节点
return head;
}
头指针:一个链表开始的地方,丢失头指针意味着丢失整个链表。
前置指针:指向当前指针的上一个指针
新链表节点创建:链表创建核心,采用malloc函数赋予每个节点各自的内存
创建第一个节点/链接下一个节点:创建第一个节点时,头指针一定是指向NULL,随后前置指针指头指针(更新前置指针),下一次创建节点时,前置指针便可以链接当前的new_node指针(指向new_node地址),实现节点之间的链接。当循环完后,完成了从头指针到尾指针的链接,还需要将尾指针与头指针链接起来,形成闭合环。链表创建完毕。返回头指针。
这里也许有些同学会有疑问,为什么new_node能重新创建?不是同一个名字吗?链表如何实现的?这里需要注意,new_node是一个指针,它指向一个地址,当new_node被创建时,实际上是一段新内存被创建,new_node指向这段地址没错,当prev指向head时,实际上指的是这段地址,此后再重新创建new_node,实际上就是new_node指向另一个地址,有独立的内存,这种方法有赖于malloc函数的特性,然后由于prev还未更新,指向的是上一个地址,就可以以prev->next=new_node的方式链接上一个节点和当前节点,此后prev更新,指向当前地址,由此完成链表节点的链接。
链表创建完毕,接下来就是运用。
void ysf(int n,int target){
node *current=CreatlistNode(n); //创建头指针(也是当前节点),同时创建链表,
node *prev=NULL; //前置指针
while(current->next!=current){ //若当前节点的下一个节点不为本身
for(int i=1;i<target;i++){ //遍历target-1个节点,找出第target个节点
prev=current; //更新前置指针,指向当前节点
current=current->next; //更新当前节点
}
printf("%d -> ",current->num);
prev->next=current->next; //将前置指针与当前节点指向的下一个节点链接
free(current); //释放当前节点内存
current=prev->next; //更新当前节点
}
printf("%d\n",current->num); //最后一个节点
printf("赢家是%d",current->num);
free(current); //释放当前节点内存
}
函数有两个形参,n是用于链表的创建,表示节点个数,target用于循环查找,每到第target个节点就删除该节点。
第一步,创建头指针,更合理的说法应该是当前节点,因为它总是指向当前的节点,最先指向头节点,因此也可以说是头指针。
然后创建前置指针。
随后进入链表循环,结束条件为还剩最后一个节点时跳出,意味着当前指针指向自己,用for循环进行循环查找,遍历target-1个节点(在循环中,prev前置指针总是指向当前指针的上一个节点),此时当前指针指向的是第target节点,于是可以将前置节点与当前节点指向的下一个节点链接,然后释放当前节点内存,更新当前指针,指向当前节点指向的下一个节点,实现节点的删除。
此外,千万注意内存的释放,有malloc函数就一定要有free函数,防止内存泄漏,要养成良好习惯。
#include "stdio.h"
#include "stdlib.h"
typedef struct Node{
int num;
struct Node *next;
}node;
node *CreatlistNode(int n){
node *head=NULL;
node *prev=NULL;
for(int i=1;i<=n;i++){
node *new_node=(node*)malloc(sizeof(node));
new_node->num=i;
if(head==NULL){
head=new_node;
}else{
prev->next=new_node;
}
prev=new_node;
}
prev->next=head;
return head;
}
void ysf(int n,int target){
node *current=CreatlistNode(n);
node *prev=NULL;
while(current->next!=current){
for(int i=1;i<target;i++){
prev=current;
current=current->next;
}
printf("%d -> ",current->num);
prev->next=current->next;
free(current);
current=prev->next;
}
printf("%d\n",current->num);
printf("赢家是%d",current->num);
free(current);
}
int main(){
int n,target;
printf("请输入人数:");
scanf("%d",&n);
printf("\n请输入目标值: ");
scanf("%d",&target);
ysf(n,target);
return 0;
}