目录
1.知识回顾
2.静态实现演示图
3.静态实现代码
1.初始双向链表
2.头插
3.遍历链表
4.查找某个值
4.任意位置之后插入元素
5.任意位置之前插入元素
6.删除任意位置的元素
4.STL库的list
1.知识回顾
96.【C语言】数据结构之双向链表的初始化,尾插,打印和尾删
97.【C语言】数据结构之双向链表的头插,头删,查找,中间插入,中间删除和销毁函数
上述文章均为动态实现双向链表,由于竞赛中追求运行速度快,因此不会动态实现双向链表,本文介绍静态实现双向链表
2.静态实现演示图
由于每一个结点要存储三个信息,因此静态实现使用三个数组:数值数组val,前驱数组prev,后继数组next,三个数组中同一个下标位置的元素打包成一个节点,如下图所框的(head指向头节点)
注:这里实现的双向链表为不循环的
将上方图改成逻辑结构再画图
3.静态实现代码
1.初始双向链表
const int N=1e5+10;
//一开始prev数组和next数组元素值都为-1(无效下标),为空链表
int prev[N]=-1;
int val[N];
int next[N]=-1;
//初始情况head和id都指向哨兵位结点
int head=0;
int id=0;
2.头插
先保存新数据的值,再修改next和prev数组
只要①指针最后修改即可
void push_front(int data)
{
val[++id]=data;
next[id]=next[head];
prev[next[head]]=id;
prev[id]=head;
next[head]=id;//确保next[head]最后被修改
}
3.遍历链表
只需要看next数组即可遍历
void print()
{
for (int i=next[head];i!=-1;i=next[i])
{
cout<<val[i]<<" ";
}
}
4.查找某个值
和打印逻辑一样,按链表的方式遍历,注意不能只查val数组,有些元素被"删除"了(即按链表的方式查不到),但仍然存在于val数组中
只需要看next数组,查找到data在链表中第一次出现的位置 ,此方法时间复杂度为
void find(int data)
{
for (int i=next[head];i!=-1;i=next[i])
{
if (val[i]==data)
{
cout<<data<<"的下标为"<<i;
return;
}
}
cout<<"未找到";
}
如果使用标记数组mp优化(哈希表),直接return mp[x],时间复杂度,但此方法有局限
4.任意位置之后插入元素
设在任意位置pos之后插入元素data,本质上和头插操作一样.,只要最后修改pos的后继指针即可
void insert_after(int pos,int data)
{
val[++id]=data;
next[id]=next[pos];
prev[next[pos]]=id;
prev[id]=pos;
next[pos]=id;//确保next[pos]最后被修改
}
5.任意位置之前插入元素
设在任意位置pos之前插入元素data,本质上和头插操作一样.,只要最后修改pos的前驱指针即可
void insert_before(int pos,int data)
{
val[++id]=data;
next[prev[pos]]=id;
prev[id]=prev[pos];
next[id]]=pos;
prev[pos]=id;//确保prev[pos]最后被修改
}
6.删除任意位置的元素
修改两个指针即可
void erase(int pos)
{
prev[next[pos]]=prev[pos];
next[prev[pos]]=next[pos];
}
4.STL库的list
提醒:list 的底层就是动态实现的双向循环链表,增删会涉及new和delete,执行速度慢,竞赛中不建议使用
初始化list: list<任意数据类型> 名称
list<int> l;
头插: l.push_front 尾插: l.push_back 头删: l.pop_front 尾删: l.pop_back