问题描述:
已知n个人(编号为1,2,3,…,n)围坐在圆桌旁,编号为1的人开始数数,数到m的人出去; 下一个人从1开始数,数到m的人再出去,依次重复,直到圆桌周围的人都出去
多组输入;
输入:9 5
输出:5 1 7 4 3 6 9 2 8
优点:相比用结构体实现单链表,用数组模拟链表要快很多,而且很多数据结构都可以用数组实现
核心思想:用一个数组存储数字,另一个数组存储数字的下标。 一个节点由当前下标编号和下一个人编号组成; 代码中的ne[k]=ne[ne[[k]]将下一个节点中存储的下一个人的编号下标赋值给当前节点,所以删除节点实际上是伪删除,即将下一个人的编号下标赋值给当前节点。 1人的人数下标为第m-1人,然后计数器res清零,一直循环直到i=ne[i],即整个队列只剩下最后一个人时,循环结束,单独输出最后一个人的编号
容易出现的问题是:数组下标容易混淆。 建议先用笔在纸上模拟一下。 熟悉了之后,确实比结构体实现的单链表快很多。
#include
using namespace std;
const int N=1e5+10;
int e[N],ne[N];//e[N]存储数值;ne[N]存储下标
int n,m,idx;//n:人数 ; m:间隔数;idx:已插入元素的下一个位置下标
//插入
void push(int x){
e[idx]=x; //
ne[idx-1]=idx;
ne[idx]=0;
idx++;
}
//删除节点
void pop(int k){
ne[k]=ne[ne[k]];
}
int main(){
while(cin>>n>>m){
idx=0;
for(int i=1;i<=n;i++)push(i);//创建循环链表
int i=0,res=0;//res:计数器
while(i!=ne[i]){
if(res==m-2){ //m-2是因为res从0开始计数,并且要在出列前一个人将后面那个节点删掉
cout<