双链表
开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情
前面介绍了 为什么要用静态数组模拟链表,那么有单链表就会有双链表,而双链表的构造仅增加一个左边指针
1.模板介绍
// e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点
int e[N], l[N], r[N], idx;
// 初始化
void init()
{
//0是左端点,1是右端点
r[0] = 1, l[1] = 0;
idx = 2;
}
// 在节点a的右边插入一个数x
void insert(int a, int x)
{
e[idx] = x;
l[idx] = a, r[idx] = r[a];
l[r[a]] = idx, r[a] = idx ++ ;
}
// 删除节点a
void remove(int a)
{
l[r[a]] = l[a];
r[l[a]] = r[a];
}
2.模板解析
1)初始化
让我们想一下结构体构造双链表的方法
typedef struct DNode{
ElemType data; // 数据域
struct DNode *pre,*next; // 前驱和后继指针
}DNode,*DLinklist;
所以静态数组构造就需要三个数组
1.数据域数组
2.前驱指针数组
3.后继指针数组
int e[N],l[N],r[N],idx; //我们需要知道此时节点的位置,就用idx变量进行节点的统计
接下来就是初始化链表,数组与结构体链表不同的就是构造方法,前者是在固定的数组中,后者地址可以是不连续的。
所以我们需要确定好头指针和尾指针,并以此基础进行构造链表
void init()
{
//1 为尾部,0为头
//头-->尾
//0-->1
l[1]=0,r[0]=1,idx=2;
}
2)插入操作
链表版
bool add(DNode *p,DNode *s){
if(p==NULL || s==NULL) // 非法参数
return false;
s->next = p->next;
if(p->next!=NULL) // 如果p结点有后继结点
p->next->prior=s; // 将后继结点的前驱指针指向新结点
s->prior = p;
p->next = s;
return true;
}
在a节点右边插入一个x,尾插法和头插法就包括在内
void add(int a,int x)
{
//首先存入数据域
e[idx]=x;
//l[idx]=a 新增节点的左指针指向a
l[idx]=a;
//新增节点的右指针指向原本a右指针指向的节点
r[idx]=r[a];
//那么a右指针指向的节点的左指针就不指向a了,而是指向当前节点
l[r[a]]=idx;
//那么a节点的右指针就指向当前节点了
r[a]=idx;
//最后++ 进入下一个节点
idx++;
}
3)删除操作
链表版
bool remove(DNode *p){
if(p==NULL) return false; // 判断p结点是否存在
DNode *q = p->next; // 找到p结点的后继结点
if(q==NULL) return false; // 判断p的后继节点是否存在(q为要删除的结点)
p->next = q->next;
if(q->next!=NULL) // 判断q结点是否是链表中的最后一个结点
q->next->pre = p;
free(q)
return true;
}
void remove(int a)
{
//a的下一个节点的左指针不指向a了,指向a的上一个节点
l[r[a]]=l[a];
//同上
r[l[a]]=r[a];
}
3.实操演练
- 在最左侧插入一个数;(在头节点右边插个数,头节点位置为0,
add(0,x))
- 在最右侧插入一个数(在尾节点左边插个数,尾节点位置为1,左边一个节点的右边插个数
add(l[1],x);- 将第 k 个插入的数删除;
- 在第 k 个插入的数左侧插入一个数;
- 在第 k 个插入的数右侧插入一个数
#include<iostream>
using namespace std;
const int N=1e6+10;
int e[N],l[N],r[N],idx;
void init()
{
...
}
//节点a右边插入一个x
void add(int a,int x)
{
...
}
//删除a节点
void remove(int a)
{
...
}
int main()
{
int M;
cin>>M;
init();
while(M--)
{
string temp;
cin>>temp;
int x,k;
//右侧插入数
if(temp=="R")
{
cin>>x;
add(l[1],x);
//最左侧添加数
}else if(temp=="L")
{
cin>>x;
add(0,x);
}else if(temp=="D")
{
cin>>k;
//因为有个头部所以+1
remove(k+1);
}else if(temp=="IL")
{
cin>>k>>x;
add(l[k+1],x);
}else
{
cin>>k>>x;
add(k+1,x);
}
}
for(int i=r[0];i!=1;i=r[i])
{
cout<<e[i]<<" ";
}
return 0;
}