线性数据结构——链表课后讲解(真正意义上的增加/删除)

线性数据结构——链表课后讲解

讲解内容:

  • 链表与数组的区别。
  • 前驱和后继。
  • 代码编写前驱和后继。
  • 课上例题。
性能 数组 链表
查找 a_1=1 for 循环遍历
删除 ^{1} for 循环挨个往前移(覆盖) 连上 a{i-1}a_{i+1}
插入 for 循环挨个往后移(腾出位置) 按顺序互相连接
难度 简单 思路难,程序简单
复杂度 比较高 比较低

1:非归 01-2-(3)-4-5 -> 1-2-4-5

前驱和后继

在链表里有一个非常关键的词语:前驱后继

  • 前驱:在数组 1,2,3,4,5a_{i-1}a_i 的前驱,例 23 的前驱。
  • 后继:在数组 1,2,3,4,5a_{i+1}a_i 的后继,例 43 的后继。

为什么要知道前驱和后继呢?首先,链表就好比一条锁链,它连接着每个数与数的位置关系,我们可以用 - 来代表锁链。

数组 1-2-3-4-5-6-7 中我们要删除 4,如果用 for 循环解决问题就要用到遍历,将 4 以后的每个数向前挪一位,如果数组庞大,那么复杂度就远远地超出了正常范围。如果用链表,就只用切断 435 的锁链,将 35 连起来,那么就要用到非常重要的东西(不是算法):指针

举个例子:有 3 个数 1,2,321 的后继, 32 的后继; 12 的前驱, 23 的前驱。我们利用正向思维(正常人的思维)来看,因为 21 的后面,所以 1 就指向 2 ,这时如果要把 2 删除,就只用将 1 指向 33 变成 1 的后继),然后将 1 成为 3 的后继。

那么怎么设置前驱和后继呢?

后继:我们可以定义数组 a ,将 a_i 定义为 a_{i+1} 的数a_i 指向 a_{i+1} ),例 s_2 = 1 , s_{3} = 4 ,则将 a_2 定义为 4 。所以 4 就是 2 的后继。

前驱:我们可以定义数组 b ,将 b_i 定义为 b_{i-1} 的数b_i 指向 b_{i-1} ),例 s_2=1,s_{3}=4 ,则将 b_3 定义为 2 。所以 2 就是 4 的前驱。

代码编写前驱和后继

我们得到了一个下标 x ,要连上 a_{x-1}a_{x+1} 。那么先设置后继( a_{x-1} 链接 a_{x+1}提示: a 数组代表后继, b 数组代表前驱,其中数组 1-2-3 删除 2

x 的前驱的后继设为 x 的后继:a[b[x]]=a[x]

这样就实现了 1 连接了 3

x 的后继的前驱设为 x 的前驱:b[a[x]]=b[x]

这样就实现了 3 连接了 1

课上例题

P1996 约瑟夫问题

思路:报数为 mm0 ,删除报数为 m 的那个人,将他的前面和后面互相连接。此处还会更新细讲 62 日。具体先看代码。

总体代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int a[101],b[101];
	int n,m,s=0;
	cin>>n>>m;
	for(int i=1;i<=n-1;i++)a[i]=i+1;//设置后继指向。
	for(int i=2;i<=n;i++)b[i]=i-1;//设置前驱指向。
	a[n]=1,b[1]=n;//环形指向。
	int bs=1,xs=1;//报数从1开始,选手从第1个开始报。
	while(s<n){
		while(bs<m){//报到 m-1。
			bs++;//报数。
			xs=a[xs];//下一个选手。
		}
		cout<<xs<<" ";//被淘汰的人。
		s++;//淘汰数量 +1。
		a[b[xs]]=a[xs];//解释过。
		b[a[xs]]=b[xs];//解释过。
		xs=a[xs];继续更新下一个将要报道的人。
		bs=1;//从新从 1 开始报。
	}
	return 0;
}
6 个赞

@密涅瓦的猫头鹰 c++ 大佬徽章可以吗

5 个赞

好像停止发放了吧

1.你的帖不够完善,缺乏题目讲解
2.C++大佬勋章已经绝版了

其实你可以让管理员给你们发一个
虽然你们不认识管理员,且他们估计也不会发(

武汉那批人基本上都不认识杭州的,连管理员都敢骂,上次说骂了老师
只因被禁言了

我马上搞,题目讲解

5 个赞
5 个赞