第十四届蓝桥杯省赛C++B组题目及解析之链表

此篇接续上一篇第六题中的手搓双链表的内容,上一篇博客链接:第十四届蓝桥杯省赛C++B组题目及解析(二)-CSDN博客

这里通过acwing中的模板题进行讲解

首先可以看一下模拟单链表的实现方法

一.数组模拟单链表

        一般用于邻接表(n个链表),用于存储图和树

数据结构由值和下一个结点的指针两部分构成

        1.值value:用e[N]表示某个点的值

        2.指针next:用ne[N]表示某个点的next指针的值

        3.头指针head:用head表示指向链表第一个元素的头指针

第十四届蓝桥杯省赛C++B组题目及解析之链表_第1张图片

int head, idx;
int e[N], ne[N];

在实际使用过程中还需要加入一个idx,用来计算当前存入的元素的个数,idx用于给新加入的元素分配新的位置。

链表的函数:

1.初始化

void init()
{
	head = -1;
	idx = 0;
}

表示头结点指向空(-1),当前元素个数是0个,还没有放入元素。

2.插入(头插,将结点插入到head指针和第一个元素中间)

void add_to_head(int x)
{
	e[idx] = x;
	ne[idx] = head;
	head = idx;
	idx ++;
}

先将值存入e数组中,然后将该结点的指针指向head指向的节点,将head指向这个新的结点的位置,该位置被新元素使用过了因此最后++。

3.删除(删除位置为k后的节点)

void remove(int k)
{
	ne[k] = ne[ne[k]];
}

指针跳过k后面的那个节点,指向k的后继的后继的那个节点

看个题目:

第十四届蓝桥杯省赛C++B组题目及解析之链表_第2张图片

第十四届蓝桥杯省赛C++B组题目及解析之链表_第3张图片

在该题目中需要加入一个在结点k之后插入一个新的值为x的结点的操作,代码如下:

#include 
using namespace std;
typedef long long LL;

int n;
const int N = 100010;
int head, idx;
int e[N], ne[N];

void init() {
	head = -1;
	idx = 1;
}

void add_to_head(int x) {
	e[idx] = x;
	ne[idx] = head;
	head = idx;
	idx ++;
}

void remove(int k) {
	ne[k] = ne[ne[k]];
}

void add1(int k, int x) {
	e[idx] = x;
	ne[idx] = ne[k];
	ne[k] = idx;
	idx ++;
}

int main() {
	ios::sync_with_stdio(false);
	init();
	cin >> n;

	while (n --) {
		char c;
		cin >> c;

		if (c == 'H') {
			int x;
			cin >> x;
			add_to_head(x);
		}

		if (c == 'D') {
			int k;
			cin >> k;
			if(!k)
			{
			    head = ne[head];
			    continue;
			}
			remove(k);
		}

		if (c == 'I') {
			int k, x;
			cin >> k >> x;
			add1(k, x);
		}
	}
	for(int i = head; i != -1; i = ne[i])
	    cout << e[i] << " ";

	return 0;
}

由于题目说明中存在k=0的删除情况,因此需要特判一下k是否等于0,如果等于0则需要直接将head跳过第一个元素指向第二个元素。运行后通过所有测试用例

二.数组模拟双链表

        一般用于优化问题

数据结构由值,前驱指针和后继指针三部分构成

        1.值value

        2.前驱指针l[N]

        3.后继指针r[N]

函数:

1.初始化

void init()
{
	r[0] = 1;
	l[1] = 0;
	idx = 2;
}

这里初始化采用一种比较简洁的写法,用0表示双链表的第一个元素的下标(head),用1表示双链表的最后一个元素的下标(tail),由于0和1已经被占用,因此idx下标需要从2开始 

2.插入(下标为k的右边插入值为x的点)

void add(int k, int x)
{
	e[idx] = x;
	r[idx] = r[k];
	l[idx] = k;
	l[r[k]] = idx;
	r[k] = idx;
	idx ++;
}

画图更方便理解,由于涉及到很多的指针操作图片涂涂改改不容易看,就不放图片演示

3.删除(删除下标为k的节点)

void remove(int k)
{
	r[l[k]] = r[k];
	l[r[k]] = l[k];
}

让左边的右边等于右边,右边的左边等于左边就可以了(不是

题目如下:

第十四届蓝桥杯省赛C++B组题目及解析之链表_第4张图片

第十四届蓝桥杯省赛C++B组题目及解析之链表_第5张图片

敲一下主函数,完整代码如下:

#include 
using namespace std;
typedef long long LL;

const int N = 100010;
int m;
int e[N], l[N], r[N];
int idx;

void init() {
	r[0] = 1;
	l[1] = 0;
	idx = 2;
}

void add(int k, int x) {
	e[idx] = x;
	r[idx] = r[k];
	l[idx] = k;
	l[r[k]] = idx;
	r[k] = idx;
	idx ++;
}

void remove(int k) {
	r[l[k]] = r[k];
	l[r[k]] = l[k];
}

int main() {
	ios::sync_with_stdio(false);
	cin >> m;
	init();

	while (m --) {
		string c;
		int x, k;
		cin >> c;

		if (c == "L") {
			cin >> x;
			add(0, x);
		}

		if (c == "R") {
			cin >> x;
			add(l[1], x);
		}

		if (c == "D") {
			cin >> k;
			remove(k + 1);
		}

		if (c == "IL") {
			cin >> k >> x;
			add(l[k + 1], x);
		}

		if (c == "IR") {
			cin >> k >> x;
			add(k + 1, x);
		}
	}

	for (int i = r[0]; i != 1; i = r[i])

		cout << e[i] << " ";

	return 0;
}

由于0和1结点下标用于双链表的头和尾,因此对于输入的k需要加一后才是函数进行操作的元素的下标。通过所有的测试用例

你可能感兴趣的:(蓝桥杯,c++,算法,链表)