约瑟夫问题


动态链表
#include <bits/stdc++.h>
struct node{                         //定义链表结点
int data;                          //结点的值
node *next;                          //单向链表,只有一个next指针
};
int main(){
int n,m;   scanf("%d %d",&n,&m);
node *head,*p,*now,*prev;            //定义变量
  head = new node; head->data = 1; head->next=NULL; //分配第一个结点,数据置为1       
  now = head;                          //当前指针是头
 for(int i=2;i<=n;i++){
p = new node;  p->data = i; p->next = NULL;  //p是新结点
now->next = p;                   //把申请的新结点连到前面的链表上
now = p;                         //尾指针后移一个
}   
now->next = head;                    //尾指针指向头:循环链表建立完成
//以上是建立链表,下面是本题的逻辑和流程。
now = head, prev = head;             //从第1个开始数
while((n--) >1 ){
for(int i=1;i<m;i++){            //数到m,停下
prev = now;                  //记录上一个位置,用于下面跳过第m个结点
now = now->next; //
}
printf("%d ", now->data);       //输出第m结点,带空格
prev->next = now->next;         //跳过这个结点
delete now;                     //释放结点
now = prev->next;               //新的一轮       
}
printf("%d", now->data);            //打印最后一个,后面不带空格
delete now;                         //释放最后一个结点
return 0;
}

笔记:动态链表的链表节点可以现取现用,不会有多余的内存浪费,但是存储空间不一定连续,而且不用的节点空间要及时释放掉。

单向静态链表
#include <bits/stdc++.h>                 
const int N = 105;                       //定义静态链表的空间大小
struct node{                             //单向链表
int id, nextid;                       //单向指针
//int data;                           //如有必要,定义一个有意义的数据   
}nodes[N];                               //定义在全局的静态分配
int main(){
int n, m;       scanf("%d%d", &n, &m);
nodes[0].nextid = 1;
for(int i=1;i<=n;i++){ nodes[i].id = i; nodes[i].nextid = i + 1;}
nodes[n].nextid = 1;                  //循环链表:尾指向头
int now = 1, prev = 1;                //从第1个开始
while((n--) >1){
for(int i=1;i<m;i++){ prev = now; now = nodes[now].nextid;} //数到m停下           
printf("%d ", nodes[now].id);     //带空格打印
nodes[prev].nextid = nodes[now].nextid;    //跳过结点now,即删除now
now = nodes[prev].nextid;         //新的now
}   
printf("%d", nodes[now].nextid);      //打印最后一个,后面不带空格
return 0;
}

笔记:静态列表的“连续空间”对链表来说无意义,链表的指针可以直接指向下一个节点的地址,链表节点不要超出链表的空间范围

双向静态链表
#include <bits/stdc++.h>
const int N = 105;
struct node{                           //双向链表
int id;                            //结点编号
//int data;                        //如有必要,定义一个有意义的数据
int preid, nextid;                 //前一个结点,后一个结点
}nodes[N];
int main(){
int n, m;    scanf("%d%d", &n, &m);
nodes[0].nextid = 1;
for(int i = 1; i <= n; i++){        //建立链表
nodes[i].id = i;
nodes[i].preid = i-1;           //前结点
nodes[i].nextid = i+1;          //后结点
}
nodes[n].nextid = 1;                //循环链表:尾指向头
nodes[1].preid = n;                 //循环链表:头指向尾
int now = 1;                        //从第1个开始
while((n--) >1){
for(int i=1;i<m;i++)  now = nodes[now].nextid;    //数到m,停下           
printf("%d ", nodes[now].id);   //打印,后面带空格
int prev = nodes[now].preid,  next = nodes[now].nextid;
nodes[prev].nextid = nodes[now].nextid;  //删除now
nodes[next].preid = nodes[now].preid;  
now = next;                     //新的开始
}   
printf("%d", nodes[now].nextid);    //打印最后一个,后面不带空格
return 0;
}

笔记:双向链表有两个指针,一个指向下一个节点,一个指向上一个节点,不仅可以查到下一个节点,还可以“溯源”找到上一个节点,有这两个节点就可以实现“自我删除”

一维数组(单向静态链表)
#include<bits/stdc++.h>
int nodes[150];
int main(){  
int n, m;    scanf("%d%d", &n, &m);
for(int i=1;i<=n-1;i++)  nodes[i]=i+1; //nodes[i]的值就是下一个结点       
nodes[n] = 1;                          //循环链表:尾指向头
int now = 1, prev = 1;                 //从第1个开始
while((n--) >1){
for(int i = 1; i < m; i++){    //数到m,停下
prev = now;   now = nodes[now];    //下一个
}
printf("%d ", now);            //带空格
nodes[prev] = nodes[now];      //跳过结点now,即删除now
now = nodes[prev];             //的now
}   
printf("%d", now);                 //打印最后一个,不带空格
return 0;
}

笔记:数组的每个元素地址是连续的,类似于静态链表,下一个节点的位置也是通过数组的下标就能获得

STL list
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, m;    cin>>n>>m;
list<int>node;
for(int i=1;i<=n;i++) node.push_back(i);    //建立链表            
list<int>::iterator it = node.begin(); //迭代器
while(node.size()>1){                       //list的大小由STL自己管理
for(int i=1;i<m;i++){                   //数到m
it++;
if(it == node.end()) it = node.begin();  //循环:到末尾了再回头                                                             
}
cout << *it <<" ";
list<int>::iterator next = ++it;
if(next==node.end())  next = node.begin(); //循环链表
node.erase(--it);                          //删除这个结点,node.size()自动减1
it = next;
}
cout << *it;
return 0;
 }

笔记:c++里的STL list 是双向的循环链表,使用起来很方便,不需要再自己建立结构体数组写链表,直接放进去数据就能使用,遍历list要记得用迭代器遍历

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注