基础数据结构第一期 链表(单链表+双链表)


前言

链表是数据结构中十分重要的一个内容,我们应该熟练掌握他们基本的内容,接下来我将用数组模拟的方式为大家来进行讲解!!!

一、单链表

模拟过程:

我们用e[N]来表示某个点的值是多少,ne[N]来表示某个点的next指针是多少,e跟ne用下标关联起来的,空节点用-1来表示,e[0]==某个值,ne[0]=1(next指针),以此类推...

如图:

例题及代码讲解:

例题:

AC代码及讲解:

//链表

//struct Node{
//	int val;
//	Node *next;
//};

//竞赛中最常用的是邻接表
//邻接表用的最多的是 存储图 和 树

//双链表用来优化某些问题

#include <iostream>
using namespace std;
const int N = 100010;
//head表示头结点的下标
//e[i]表示节点i的值
//ne[i]表示节点i的next指针是多少,或者说下一个节点i的地址是什么
//idx存储当前已经用到了哪个点
int head, e[N], ne[N], idx;

//初始化
void init() {
	head = -1;
	idx = 0;
}

//将x插入到头结点:
//1.将x的next指针指向head节点指向的下一个位置
//2.将head指针删掉,然后指向x节点
void add_to_head(int x) {
	e[idx] = x; //把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 remove(int k) {
	ne[k] = ne[ne[k]];
}

int main() {
	int m;
	cin >> m;

	init();//初始化

	while (m--) {
		int k, x;
		char op;
		cin >> op;
		if (op == 'H') {
			cin >> x;
			add_to_head(x);
		} else if (op == 'D') {
			cin >> k;
			if (!k)
				head = ne[head];
			else
				remove(k - 1);
		} else {
			cin >> k >> x;
			add(k - 1, x);
		}
	}
	for (int i = head; i != -1; i = ne[i])
		cout << e[i] << ' ';
	cout << endl;
	return 0;
}

二、双链表

  模拟过程:

1、用两个数组来代表左单链表和右单链表,即为l[N],r[N]

2、l[N]数组为指向右边的链表,r[N]为指向左边的链表

3、e[N]为当前结点的值

4、设r[0]=1,l[1]=0,因为是相互指向

5、同样用一个idx来储存当前结点用到了哪一点

图例:


例题及代码讲解:

例题:

AC代码及讲解:

#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
//e用来存储数值,
//l[]用来存储前驱(左边数的下标),
//r[]用来存储后继(右边数的下标)
//idx用来记录当前下标
int e[N], l[N], r[N], idx;

//初始化
void init() {
	//0表示左端点,1表示右端点
	r[0] = 1;
	l[0] = 0;
	idx = 2;//因为0和1已经被占用了
}

//在第k点的右边插入x
void add_to_right(int k, int x) {
	e[idx] = x;//将x存入当前下标的数值数组中
	r[idx] = r[k];//当前下标的后继为k的后继
	l[idx] = k;//当前下标的前驱为k
	l[r[k]] = idx;//k的后继节点的前驱为idx
	r[k] = idx++;//k的后继节点为idx,idx++
}

//在k点的左边插入x,等价于在l[k]的右边插入x,也就是add_to_right(l[k],x);
void add_to_left(int k, int x) {
	add_to_right(l[k], x);
}

//删除第k个点
void remove(int k) {
	r[l[k]] = r[k];//k的前驱的后继为k的后继
	l[r[k]] = l[k];//k的后继的前驱为k的前驱
}

//在链表的最左端插入数x
void add_to_head(int x) {
	add_to_right(0, x);//在0后面插入x
}

//在链表的最右端插入数x
void add_to_tail(int x) {
	add_to_right(l[1], x);
}

int main() {
	int m;
	init();
	cin >> m;
	int k, x;
	while (m--) {
		string op;
		cin >> op;
		if (op == "L") {
			cin >> x;
			add_to_head(x);
		} else if (op == "R") {
			cin >> x;
			add_to_tail(x);
		} else if (op == "D") {
			cin >> k;
			remove(k + 1);
		} else if (op == "IL") {
			cin >> k >> x;
			add_to_left(k + 1, x);
		} else  {
			cin >> k >> x;
			add_to_right(k + 1, x);
		}
	}
	for (int i = r[0]; i != 1; i = r[i]) {
		cout << e[i] << ' ';
	}
	cout << endl;

	return 0;
}

总结

以上就是数组模拟链表的基本过程,感谢大家的观看!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值