神机百炼1.22-静态双链表

静态双链表导图

食用指南:

对该算法程序编写以及踩坑点很熟悉的同学可以直接跳转到代码模板查看完整代码
只有基础算法的题目会有关于该算法的原理,实现步骤,代码注意点,代码模板,代码误区的讲解
非基础算法的题目侧重题目分析,代码实现,以及必要的代码理解误区

题目描述:

  • 实现一个双链表,双链表初始为空,支持 5 种操作:

    在最左侧插入一个数;
    在最右侧插入一个数;
    将第 k 个插入的数删除;
    在第 k 个插入的数左侧插入一个数;
    在第 k 个插入的数右侧插入一个数
    现在要对该链表进行 M 次操作,进行完所有操作后,从左到右输出整个链表。

    注意:题目中第 k 个插入的数并不是指当前链表的第 k 个数。例如操作过程中一共插入了 n 个数,则按照插入的时间顺序,这 n 个数依次为:第 1 个插入的数,第 2 个插入的数,…第 n 个插入的数。

    输入格式
    第一行包含整数 M,表示操作次数。

    接下来 M 行,每行包含一个操作命令,操作命令可能为以下几种:

    L x,表示在链表的最左端插入数 x。
    R x,表示在链表的最右端插入数 x。
    D k,表示将第 k 个插入的数删除。
    IL k x,表示在第 k 个插入的数左侧插入一个 数。
    IR k x,表示在第 k 个插入的数右侧插入一个 数。
    输出格式
    共一行,将整个链表从左到右输出。

    数据范围
    1≤M≤100000
    所有操作保证合法。

    输入样例:
    10
    R 7
    D 1
    L 3
    IL 2 10
    D 3
    IL 2 7
    L 8
    R 9
    IL 4 7
    IR 2 2
    输出样例:
    8 7 7 3 2 9

  • 题目来源:https://www.acwing.com/problem/content/829/

题目分析:

  • 暴力:struct数组两个指针,一个next,一个prior
  • 静态:三个数组,数值域arr[],前指针域L[],后指针域r[]
    头指针head,尾指针tail,节点序号idx

算法原理:

模板算法:

静态双链表:

  • 双链表其实就是双向的单链表,每次操作一个方向
    所以不用过度解释了吧,有问题的同学评论区留言,欢迎欢迎
1. 初始化:
const int N = 100010;
int arr[N], l[N], r[N];
int idx = 0, head = -1, tail = -1;
void init(){
	r[0] = 1;
    r[1] = 0;
    idx = 2;
} 
2. 头插:
void head_insert(int x){
	arr[idx] = x;
	l[idx] = -1;
	r[idx] = head; 
	head = idx++;
}
3. 尾插:
void tail_insert(int x){
	arr[idx] = x;
	l[idx] = tail;
	r[idx] = -1;
	tail = idx++;
}
4. 指定右插:
  • 向第k个插入的节点右侧插入节点:注意顺序
    指定右插
void r_insert(int x, int k){
	arr[idx] = x;
	l[idx] = k-1;
	r[idx] = r[k-1];
	l[r[k-1]] = idx;
	r[k-1] = idx;
	if(k-1 == tail){
		head = idx; 
	}
	idx++;
}
5. 指定左插:
  • 向第k个插入的节点左侧插入节点:注意顺序
    指定左插
void l_insert(int x, int k){
	arr[idx] = x;
	l[idx] = l[k-1];
	r[idx] = r[k-1];
	r[l[k-1]] = idx;
	l[k-1] = idx;
	if(k-1 == head){
		head = idx;
	}
	idx++;
}
6. 删除:
  • 删除第k个插入节点的后一个节点:
    还是分两部分:尾巴 & 非尾巴
    删后
void r_remove(int k){
	if(r[k-1] == tail){
		//第k个插入的节点后是尾节点
		tail = k-1;
	}else{
		//顺序不可颠倒
		l[r[[r[k-1]]]] = k-1;
		r[k-1] = r[r[k-1]]; 
	}
}
  • 删除第k个插入节点的前一个节点:
    还是分两部分:删头 & 非头
    删前
void l_remove(int k){
	if(l[k-1] == head){
		head = k-1;
	}else{
		r[l[l[k-1]]] = k-1;
		l[k-1] = l[l[k-1]];
	}
}

####7. 遍历:

  • 从前向后:
int t = head;
while(t != -1){
	cout<<arr[t]<<" ";
	t = r[t];
}
  • 从后向前:
int t = tail;
while(t != -1){
	cout <<arr[t]<<" ";
	t = l[t];
}

代码误区:

1. 删除节点的分情况讨论:

  • 删除第k个插入节点的前一个节点:前一个是头节点 / 普通节点
  • 删除第k个插入节点的后一个节点:后一个是尾节点 / 普通节点

2. 删除的顺序:

  • 顺序不可以颠倒:先连接,后断开。

本篇感想:

  • 学会静态单链表之后,静态双链表应该很容易掌握,毕竟就算是双链表,每次操作的时候也只针对一个方向
  • 静态链表篇结束,按理说应该是栈 & 队列,但是我迫不及待手撸哈希了,下一篇写拉链哈希,别慌,静态链表够用了
  • 看完本篇博客,恭喜已登《练气境-初期》
    练气期初阶
    距离登仙境不远了,加油 登仙境初期
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starnight531

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值