数组模拟链表与邻接表(用C/C++实现)

文章介绍了如何使用数组模拟单链表和双链表,以解决效率问题,包括在头结点后插入、在特定结点后插入和删除结点的操作。同时,通过邻接表的应用,展示了数组模拟在图和树结构中的优势。
摘要由CSDN通过智能技术生成

数组模拟的理由:

效率问题

struct Node//动态链表

{

   int val;

   Node *next;

};

new Node(); //此操作非常慢

一、 使用数组模拟单链表(用的最多的是邻接表,邻接表多用来存储树与图)

head->[结点0,值为3] ->[结点1,值为5] ->[结点2,值为7] ->[结点3,值为9] ->[空结点-1]

每个结点拥有两个属性,分别是结点值和下一个结点地址(这里就是下一个结点的结点号),用数组表示即为e[N]与ne[N].

上图的各结点即可写作:

e[0] = 3             e[1] = 5         e[2] = 7         e[3] = 9

ne[0]= 1            ne[1] = 2       ne[2] = 3       ne[3] = -1

1. 在头结点后插入新结点

让head指向新结点,新结点指向原来head指向的结点。

2. 将新结点插入k结点之后

让k结点指向新结点,新结点指向原来k指向的结点。

3. 将k结点之后的结点删除

让k结点指向要删除结点之后的结点即可

//单链表
#include<iostream>

using namespace std;

const int N = 100010;

//head表示头结点的下标
//e[i]表示结点i的值 
//ne[i]表示结点i的next指针下标是多少 
//idx存储我们当前用到的下标 
int head, e[N], ne[N], idx;

//初始化
 void init()
 {
 	head = -1;
 	idx  = 0;
 }
 
 //将x插到头结点 
 void add_to_head(int x)
 {
 	e[idx] = 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]];//ne[k]是要删除的结点的下标,ne[ne[k]]是要删除结点所指向的结点 
}

 int main()
 {
 	int m;
	cin >> m;
	
	init();
	
	while(m --)
	{
		int k, x;
		char op;
		
		cin >> op;
		if(op == 'H')//在头结点插入新结点x 
		{
			cin >> x;
			add_to_head(x);
		}
		else if(op == 'D')//删除k结点之后的结点
		{
			cin >> k;
			if(!k) head = ne[head];
			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;
 }

二、 使用数组模拟双链表(用于优化某些问题)

和单链表比较类似,但它的每个结点有两个指向,所以会形成一个闭环,故不存在头尾结点之说。

将结点号为0的结点作为头结点,结点号为1的点作为尾结点。

由左端点指向右的箭头数组为r,由右端点指向左的箭头数组为l。

1. 在k结点之后插入新结点

首先让新结点的左箭头指向k结点,右箭头指向k之后的结点;接着让k结点的右箭头指向新结点,k之后的结点的左箭头指向新结点。

如果要在k之前插入新结点,就调用add[ l[k], x ].

2. 删除k结点

让k结点前面的结点的右箭头指向k之后的结点,k之后的结点的左箭头指向k之前的结点。

//双链表
#include<iostream>

using namespace std;

const int N = 100010;

int m;
int e[N], l[N], r[N], idx;
 
//初始化
void init()
{
	//0表示左端点,1表示右端点 
	r[0] = 1;
	l[1] = 0;
	idx = 2;
} 
//在结点k之后插入x 
void add(int k, int x)
{
	e[idx] = x;
	r[idx] = r[k];//k结点原来的右箭头指向新结点
	l[idx] = k;
	r[k] = idx;
	l[r[k]] = idx; 
}

//删除第k个点 
void remove(int k)
{
	r[l[k]] = r[k];
	l[r[k]] = l[k];
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值