单链表和双链表的区别:
单链表的每一个节点只有指向后面的一个指针
双链表每一个节点有两个指针,一个指向前,一个指向后
一.单链表
单链表:可以用来实现邻接表,邻接表可用来存储树和图(最短路问题,最小生成树问题)
1.单链表概念
单链表的缺点:只向后看,不向前看
即可以以O(1)的时间得到下一个节点的地址,向后插入数据,但是如果想知道前一个节点的地址,只能从头遍历
每一个节点都有两个数组:一个是记录当前节点值的数组e[N],一个是记录下一个节点位置的next[N]
用数组来实现单链表
2.单链表的两个基本操作
1.插入:
->向头节点(head)插入x
->将x插到下标是k的点后面
2.删除:
->将下标是k的点后面的点删掉
3.单链表基本操作的代码实现
#include<iostream>
using namespace std;
const int N = 10010;
//head 表示头结点的下标
//e[i] 表示节点i的值
//ne[i] 指向节点i的next指针是多少(下一个节点的索引)
//idx 存储当前已经用到了哪一个点
int head,e[N],ne[N],idx;
void init(){
head = -1;
idx = 0;
}
//将x插到头结点
void add_to_head(int x){
e[idx] = x;
ne[idx] = head;
head = idx;
idx++;
}
//将x插到下标是k的点后面
void add(int k,int x){
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx ;
idx++;
}
//将下标是k的点后面的点删掉
void delect(int k){
ne[k] = ne[ne[k]];
}
int main(){
}
4.实现一个完整单链表代码实现
例题:acwing826 单链表
代码实现:
#include<iostream>
using namespace std;
const int N = 10010;
int head,e[N],ne[N],idx;
//初始化
void init(){
head = -1;
idx = 0;
}
void add_to_head(int x){//头结点插入
e[idx] = x ,ne[idx] = head, head = idx++;
}
void add(int k,int x){//插入
e[idx] = x, ne[idx] = ne[k], ne[k] = idx++;
}
void remove(int k){//删除
ne[k] = ne[ne[k]];
}
int main(){
int m;
cin>>m;
init();
while (m--){
char op;
cin >> op;
int k,x;
if(op == 'H'){
cin >> x;
add_to_head(x);
}
else if(op == 'D')
{
cin >> k;
if(!k) head = ne[head]; //特判,当k==0,删掉头结点
remove(k - 1);
}
else
{
cin>> k >> x;
add(k - 1,x); //第k个输入的数,下标为k-1
}
}
for(int i = head;i != -1;i = ne[i] ) cout<<e[i]<<' '; //遍历链表
cout<<endl;
return 0;
}
二.双链表
双链表:可以优化某些问题
1.双链表的基本操作
1.插入:在下标为k的右边插入一个点
代码实现
#l[N] 表示某个节点的左节点
#r[N] 表示某个节点的右节点
// 在下标是k的右边,插入x
void add(int k,int x){
e[idx] = x;
r[idx] = r[k]; //当前点idx右边指向k的右边
l[idx] = k;
l[r[k]] = idx; //r[k]的左边指向idx
r[k] = idx;
}
注意必须先调用l[r[k]],再修改r[k]
2. 倘若要在下标为k的左边插入x ,相当于在 l[k] (k左边的一个点)的右边插入一个点 ,将k改成l[k]即可
void add(int l[k],int x){}
得出结论,双链表的插入只用实现一个即可
3. 删除:删掉下标为k的点
//删除第k个点
void remove(int k){
r[l[k]] = r[k]; //k左边的右边指向k的右边
l[r[k]] = l[k]; //k右边的左边指向k的左边
}
yxc大佬YYDS!!!!!!!!!!!!!!!!!!!!!!!