基础数据结构-链表

链表

数组模拟法

单链表

ITCX7121寒假第二周-A单链表
在这里插入图片描述

模拟题分析

  1. 单链表需要用到的数组:head存储链表头,e[]存储节点的值,ne[]存储节点的next指针,idx表示当前用到了哪个节点
  2. 初始化
void init(){
    head = -1;
    idx = 0;
}
  1. 将x点插到下表是k点后面:
void insert(int k,int x){
    e[idx] = x;
	ne[idx] = ne[k];
	ne[k] = idx++;
}
  1. 将头结点删除,需要保证头结点存在
void remove(){
    head = ne[head];
}

模板题代码

//P30单链表

//链表
/*
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
		} else {
			cin >> k >> x;
			add(k - 1, x);
		}
	}
	for (int i = head; i != -1; i = ne[i])
		cout << e[i] << ' ';
	cout << endl;
	return 0;
}

双链表

ITCX7121寒假第二周-B双链表
在这里插入图片描述

模板题分析

  1. 双链表需要用到的数组:e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点
  2. 双链表初始化:
void init() {
	//0表示左端点,1表示右端点
	r[0] = 1;
	l[0] = 0;
	idx = 2;//因为0和1已经被占用了
}
  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)

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

模板题代码

//P31双链表

#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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值