基础数据结构——初级——链表

链表的特点是一组位于任意位置的存储单元存储线性表的数据元素。一般分为单向链表和双向链表(如下图所示)。

 

使用链表时,可以用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;
}

 

 

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值