链表(数组模拟)

链表(数组模拟)

为什么要模拟?

效率问题,第一种实现方式是指针+结构体的方式,面试题多,笔试题不多,因为每一次创建一个新的链表就要调用一下new函数来new一个新的节点,new一个新节点这个操作是非常慢的,一般在笔试题中,链表大小在10w~100w级别,但是new出这些节点基本就超时了,因此在平时笔试时基本不会采用动态链表方式,当然如果改进一下是可以用的,比如可以先初始化n各节点,不过本质跟我们模拟链表差不多了。

模拟两种链表:

  1. 单链表:单链表在算法或笔试题中用的最多的是邻接表(邻接表其实是n个链表,最主要应用是存储图和树)
  2. 双链表:用的比较多的情况是优化某些问题

单链表

每个节点有两个值,value和指向下一个节点的指针next,模拟时用e[N]和ne[N]表示,用下标进行关联

image-20220222004908580

image-20220222020936924

image-20220222020904161

#include <iostream>

using namespace std;

const int N = 100010;

//head表示头结点下标
//idx存储当前用到了哪个地址 
int head, e[N], ne[N], idx;

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

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++;
}
//可以在任意位置插入,但是如果要在O(1)时间复杂度内插入,只能在某个点后面插入 

//将下标是k的点后面的点删掉 
void remove(int k)
{
	ne[k] = ne[ne[k]];
}
//删一个点这个题idx不用变,一般来说算法题是不用管的 

int main()
{
	int m;
	cin >> m;
	init();
	while(m--)
	{
		char op;
		int k, x;
		
		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;
}


双链表

之所以单链表要用head指向第一个点,是因为后面用的时候总会用一个变量存第一个点,双链表往往不需要,只需要用两个数来表示左右端点。

image-20220222233133577

image-20220222233151688

image-20220222233159130

image-20220222235237037

这题是循环双链表,五个操作只需要实现两个就可以,一个是在k节点右边插入一个点,一个是删除。left和right不是链表中的点,表示的是端点。

#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];
	l[idx] = k;
	l[r[k]] = idx;
	r[k] = idx;
	idx++;
}
//在k节点左边插入
//直接调用add(l[k], x);
//在k节点左边节点的右边插入即可 


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

int main()
{
    init();
	int m;
	cin >> m;
	while(m--)
	{
	    int k, x;
	    string op;
	    cin >> op;
	    if(op == "L")
	    {
	        cin >> x;
	        add(0, x);
	    }
	    else if(op == "R")
	    {
	        cin >> x;
	        add(l[1], x);
	    }
	    else if(op == "D")
	    {
	        cin >> k;
	        remove(k + 1);
	        //第k个插入点的下标是k+1,因为idx是从下标2开始的
	    }
	    else if(op == "IL")
	    {
	        cin >> k >> x;
	        add(l[k + 1], x);
	    }
	    else
	    {
	        cin >> k >> x;
	        add(k + 1, x);
	    }
	}
	for(int i = r[0]; i != 1; i = r[i]) cout << e[i] << ' ';
	cout << endl;
	return 0;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值