2022(winter) shybee的算法历练:数组构建链表

在一般的链表创建中,我们习惯使用以下结构体的形式

struct Node{
int val;
Node* next;
}

虽然这种形式看起来直观清楚,但是在创建链表过程中使用到的new操作符,在数据范围过大时,会很慢,因此算法竞赛中我们使用单数组来创建链表。

单链表:

#include<iostream>
using namespace std;
const int N = 10010;
int e[N], r[N], head, cur;
//这里的cur代替了new用来为新的节点分配空间
void init()//初始化
{
	head =0;
	r[0] = -1;
	cur = 1;
}
int find(int k)//返回第k个节点的下标
{
	int dest =0;
	while (k--)
	{
		dest = r[dest];
	}
	return dest;
}
void add_to_head(int x)//表头插入元素
{
	e[cur] = x;
	r[cur] = r[0];
	r[0] = cur;
	cur++;
}
void insert(int k,int x)//第k个节点的后面插入一个元素
{
	k = find(k);
	e[cur] = x;
	r[cur] = r[k];
	r[k] = cur;
	cur++;
}
void remove(int t)//删除第k个节点
{
	int k = find(t);
	if (r[k] == -1)//当删除的节点为尾结点时要考虑特殊情况
	{
		k = find(t - 1);
		r[k] = -1;
		return;
	}
	//对于特定的删除某个节点
	//一般思路来看我们需要知道他的前驱节点,
	//然后让前驱结点指向该节点的后置节点。
	//但是即使在不知前驱节点的情况下,我们可以将被删节点的信息全部拷贝成后置节点的信息,
	//这就是一种伪删除的方式来实现未知前驱节点情况下的删除节点
	e[k] = e[r[k]];
	r[k] = r[r[k]];

}
int main()
{
	init();
	int m;
	cin >> m;
	while (m--)
	{
		printf("请输入你的选择:\n");
		printf("1.表头插入一个元素x\n"
			"2.第k个节点的后面插入一个元素x\n"
			"3.第k个节点的前面插入一个元素x\n"
			"4.删除第k个节点\n");
		int flag;
		scanf("%d", &flag);
		switch (flag)
		{
		case 1:{int x; cin >> x; add_to_head(x); break; }
		case 2:{int k, x; cin >> k >> x; insert(k, x); break; }
		case 3:{int k, x; cin >> k >> x; insert(k - 1, x); break; }
		case 4:{int k; cin >> k; remove(k); break; }
		}
	}
	for (int i = r[0]; i != -1; i = r[i])
	{
		printf("%d->", e[i]);
	}
	puts("");
	return 0;
}

输入5
1 5
21 4
31 6
43
17
输出7->6->5->

 

双链表:

#include<iostream>
using namespace std;
const int N = 100010;
int l[N], r[N], e[N], cur;
//默认0为头节点,1为尾节点
void init()
{
	l[1] = 0;
	r[0] = 1;
	cur = 2;
}
void add_to_head(int x)//链表处插入一个点
{
	e[cur] = x;
	l[cur] = 0;
	r[cur] = r[0];
	l[r[0]] = cur;
	r[0] = cur;
	cur++;
}
int find(int k)
{
	int dest = 0;
	while (k--)
	{
		dest = r[dest];
	}
	return dest;
}
void insert(int k, int x)//第k个点的后面插入一个元素
{
	e[cur] = x;
	k = find(k);
	l[cur] = k;
	r[cur] = r[k];
	l[r[k]] = cur;
	r[k] = cur;
	cur++;
}
void remove(int k)//删除第k个点
{
	k = find(k);
	r[l[k]] = r[k];
	l[r[k]] = l[k];
}

int main()
{
	init();
	int m;
	cin >> m;
	while (m--)
	{
		printf("请输入你的选择:\n");
		printf("1.表头插入一个元素x\n"
			"2.第k个节点的后面插入一个元素x\n"
			"3.第k个节点的前面插入一个元素x\n"
			"4.删除第k个节点\n");
		int flag = 0;
		scanf("%d", &flag);
		switch (flag)
		{
		case 1:{int x; cin >> x; add_to_head(x); break; }
		case 2:{int k, x; cin >> k >> x; insert(k, x); break; }
		case 3:{int k, x; cin >> k >> x; insert(k-1, x); break; }
		case 4:{int k; cin >> k; remove(k); break;}
		}
	}
	//打印链表
	for (int i = r[0]; i != 1; i = r[i])//自左向右
	{
		printf("%d->", e[i]);
	}
	puts("");
	for (int i = l[1]; i != 0; i = l[i])//自右向左
	{
		printf("%d->", e[i]);
	}
	puts("");
	return 0;
}
输入5
15
21 4
31 6
43
17
输出

7->6->5->

5->6->7->

                                                                                                                           2023/1/8 by shybee

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值