链表的特点是一组位于任意位置的存储单元存储线性表的数据元素。一般分为单向链表和双向链表(如下图所示)。
使用链表时,可以用STL的list,也可以自己写链表。如果自己写代码实现链表,有两种编码实现方法:动态链表和静态链表。在算法竞赛中为加快编码速度,一般用静态链表或者STL的list。所以接下来只为大家讲解这两种。
https://www.luogu.com.cn/problem/P1996 以经典的约瑟夫问题讲解
第一种方法:用结构体数组实现双向静态链表
#include<bits/stdc++.h>
using namespace std;
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].nextid=i+1;//后节点
nodes[i].preid=i-1;//前节点
}
nodes[n].nextid=1;//循环链表:尾指向头
nodes[1].preid=n;//头指向尾
int now=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>
using namespace std;
const int N=150;
int nodes[N];
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;//从第一个节点开始
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=nodes[prev];//新的now节点
}
printf("%d",now);//打印最后一个节点不带空格
}
第三种方法:STL list。 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)
{
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);//删除这个节点
it=next;
}
cout<<*it<<endl;
return 0;
}
练习题:https://www.luogu.com.cn/problem/P1160
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<list> //底层实现是双向链表
using namespace std;
const int N=100010;
int mc[N];
list<int>::iterator p[N];//定义一个迭代器
int main()
{
list<int>grn;
grn.push_front(1);//把1插入链表头
p[1]=grn.begin();//list是用指针访问的
int n;
cin>>n;
int k,a;
for(int i=2;i<=n;i++)
{
cin>>k>>a;
if(a==0)
{
p[i]=grn.insert(p[k],i);//insert函数是(指针,数)将这个数插入指针之前的一个位置
} // insert(x,2) x为1的指针 2 3 1 4 就会变成 2 3 2 1 4
else
{
list<int>::iterator it=p[k];
it++;//指针后移
p[i]=grn.insert(it,i);
}
}
int m;
cin>>m;
for(int i=0;i<m;i++)
cin>>mc[i];
sort(mc,mc+m);
int t=unique(mc,mc+m)-mc;
for(int i=0;i<t;i++)
{
grn.erase(p[mc[i]]);
}
for(list<int>::iterator iter=grn.begin();iter!=grn.end();iter++)//用指针访问
cout<<*iter<<" ";
return 0;
}
标签:include,mc,int,list,链表,初级,grn,数据结构 From: https://blog.csdn.net/2301_79967286/article/details/140513108