算法竞赛——链表
目录
前言
基础数据结构——链表
一、链表是什么?
链表的特点是用一组位于任意位置的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以不连续。使用链表时可以直接用STL list,也可以手写链表。
二、STL-list使用
代码如下(示例):
#include<iostream>
#include<list>
using namespace std;
void printList(list<int> &l) {
list<int>::iterator it = l.begin();
//也可以是 auto it = l.begin();
for (; it != l.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
void test1() {
list<int> l1;
l1.push_back(10);//尾插
l1.push_back(20);
l1.push_back(30);
l1.push_front(40);//头插
l1.push_front(50);
l1.push_front(60);
printList(l1);//遍历 /*60 50 40 10 20 30*/
cout << l1.front() << " " << l1.back() << endl;//首元素,尾元素 /*60 30*/
list<int>::iterator it = l1.begin();
it++;//只支持++
it++;
l1.insert(it, 3, 100);//插入3个100 /*60 50 100 100 100 40 10 20 30*/
printList(l1);
l1.sort();//排序 /*10 20 30 40 50 60 100 100 100*/
printList(l1);
l1.reverse();//反转链表 /*100 100 100 60 50 40 30 20 10*/
printList(l1);
l1.remove(100);//删掉所有值为100的元素 /*60 50 40 30 20 10*/
printList(l1);
}
int main()
{
test1();
return 0;
}
输出示例:
三、手写链表
1.单链表
代码如下(示例):
#include<iostream>
using namespace std;
const int N=100010;
//此链表是带头结点的单链表
int head,e[N],ne[N],idx;//head是头结点,e[]数组中存储节点的值域,ne[]指向下一个节点,idx表示节点
void init()//链表初始化
{
head=-1;//初始时头结点指向-1代表NULL值
idx=1;//节点从1开始
}
void frontinsert(int x) //头插
{
e[idx]=x;
ne[idx]=head;
head=idx++;
}
void insert(int i,int x) //插入
{
int j=0;
for(int k=head;k!=-1;k=ne[k])
{
if(j+1==i){
e[idx]=x;
ne[idx]=ne[k];
ne[k]=idx++;
break;
}
j++;
}
}
void del(int i) //删除
{
int j=0;
for(int k=head;k!=-1;k=ne[k]){
if(j+1==i)
{
ne[k]=ne[ne[k]];
break;
}
j++;
}
}
void printlist() //打印链表
{
for(int i=head;i!=-1;i=ne[i]) cout<<e[i]<<" ";
puts("");
}
int main()
{
init();//初始化
frontinsert(10);
frontinsert(20);
frontinsert(30);
frontinsert(40);
printlist();//打印链表 /*40 30 20 10*/
insert(3,50);//在下标为3的位置插入元素50 /*40 30 20 50 10*/
printlist();
del(1); //删除下标为1的元素 /*40 20 50 10*/
printlist();
return 0;
}
输出示例:
可以根据自己的需求定义链表的函数,此处只举例了几种常用增删改查的函数。
2.双链表
代码如下(示例):
#include<iostream>
using namespace std;
const int N=100010;
int e[N],l[N],r[N],idx;// e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点
void init()// 初始化
{
r[0]=1, l[1]=0;//0是左端点,1是右端点
idx=2;
}
void frontinsert(int x)//头插
{
e[idx]=x;
l[idx]=0;
r[idx]=r[0];
l[r[0]]=idx;
r[0]=idx++;
}
void backinsert(int x)//尾插
{
e[idx]=x;
r[idx]=1;
l[idx]=l[1];
r[l[1]]=idx;
l[1]=idx++;
}
void insert(int j, int x)//插入一个数x
{
int k=0;
for(int i=r[0];i!=1;i=r[i])
{
if(k+1==j)
{
e[idx]=x;
l[idx]=i;
r[idx]=r[i];
l[r[i]]=idx;
r[i]=idx++;
}
k++;
}
}
void del(int j)//删除
{
int k=0;
for(int i=r[0];i!=1;i=r[i])
{
if(k==j)
{
l[r[i]]=l[i];
r[l[i]]=r[i];
}
k++;
}
}
void printlist()//打印链表
{
for(int i=r[0];i!=1;i=r[i]) cout<<e[i]<<" ";
puts("");
}
int main()
{
init();//初始化
frontinsert(10);
frontinsert(20);
frontinsert(40);
backinsert(50);
backinsert(60);
backinsert(70);
printlist();//打印链表 /*40 20 10 50 60 70*/
insert(3,100);//在下标为3的位置插入元素100 /*40 20 10 100 50 60 70*/
printlist();
del(2); //删除下标为2的元素 /*40 20 100 50 60 70*/
printlist();
return 0;
}
输出示例:
可以根据自己的需求定义链表的函数,此处只举例了几种常用增删改查的函数。
总结
本文只是小小的记录一下曾经学过的链表实现(实在觉得结构体太麻烦了[哭]),链表并不是只有此类实现方法。其中STL list是双向链表,通过指针访问结点数据,高效率地删除和插入。手写链表比较适合竞赛,邻接表等也常用到单链表结构。