带你手撕静态链表【数组】

前言

众所周知,其实在企业做项目中,对于链表的使用,更多是偏向于用结构体和指针的动态链表,那为什么在算法竞赛中我们还要学会用数组来模拟链表呢,因为用结构体和指针的话,在oj题时会很慢,很容易TLE,相比之下数组的静态链表就快多了。

单链表

1.原理

首先,我们先来看看链表应该是个什么样子.

在这里插入图片描述

很明显,链表要具备两个基本要素,第一个结点,第二个链子
黑色的表示每个结点储存的值,而红色的表示每个结点的下标。
接下来我们来想想怎么连接每一个结点呢
对,就是用ne数组来储存下一个结点的下标
那么很显然,我们既需要一个数组来储存结点的值,也需要一个结点来储存该结点的下一个结点的下标。

int e[N];//用来储存结点的值
int ne[N];//用来储存该结点的下一个的下标

接下来,我们可以用代码模拟一下第一张图。

e[0] = 3, ne[0] = 1;
e[1] = 1, ne[1] = 2;
e[2] = 2,ne[2] = 3;
e[3] = 5, ne[3] = -1;//-1规定为空指针

当然,我们还需要一个头指针head和一个指向待插入位置的指针idx

int head = -1,idx = 0;

初始化时,链表为空,头指针为空指针,则head = -1,因为链表中什么都没有,待有位置插入,所以idx=0

case 1 :在链表头部插入元素

在这里插入图片描述

想要讲元素插入只需要进行如上的操作即可,接下来展示代码

void headinsert(int x)
{
    e[idx] = x;//先赋值给要插入的元素
    nec[idx] = head;//第一步操作,使该元素的ne数组指向下一个元素的下标
    head = idx ++;//第二步操作,使head指向该元素的下标,finally,将idx++
}
case 2 : 在第k个插入的数中后面插入一个数x

note:第k个插入的数可不是链表里的第k个数,是按时间顺序的第k个数
和上一种情况一样就行了

在这里插入图片描述

void insert(int k,int x)
{
    e[idx] = x, ne[idx] = ne[k - 1], ne[k - 1] = idx ++; 
}
case 3 : 删除k后面的那个元素

删除的话,就很简单的,就让该元素的ne数组指向下下个元素的下标就行了

在这里插入图片描述

void de(int k)
{
    ne[k] = ne[ne[k]];
}
case 4 : 输出整个链表
for(int i = head; i != -1; i = ne[i])//i == -1时即i为空指针时停下
{
    cout << e[i]; 
}

2.模版题

在这里插入图片描述

这是acwing上的一道模版题,接下来展示AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e5+10;
int e[N], ne[N], idx = 0, head = -1;

void headinsert(int x)
{
    e[idx] = x, ne[idx] = head, head = idx ++;  
}

void insert(int k,int x)
{
    e[idx] = x, ne[idx] = ne[k], ne[k] = idx ++; 
}

void de(int k)
{
    ne[k] = ne[ne[k]];
}

int main()
{
    int n;
    cin >> n;
    while(n--)
    {
        char op;
        int x, k;
        cin >> op;
        if(op == 'H')
        {
            cin >> x;
            headinsert(x);
        }
        else if (op == 'D')
        {
            cin >> k;
            if (!k) head = ne[head];
            else de(k - 1);
        }
        else if(op == 'I')
        {
            cin >> k >> x;
            insert(k - 1, x);
        }
    }
    for(int i = head; i != -1; i = ne[i])
    {
        cout << e[i] << ' ';
    }
    return 0;
}

双链表

1.原理

双链表即是双向而已,与单链表其实差不多

在这里插入图片描述

由于是双向,所以每个结点既有左边,又有右边,所以相对于单链表,我们要加一个l[N] (left),r[N] (right)

int e[N], ne[N], l[N], r[N];
int idx = 0;

初始化 :单链表的初始化是head,而双链表是这样的

在这里插入图片描述

void unit()
{
    l[0] = 1,r[1] = 0;//note:这两个并不属于链表里面
    idx = 2;
}
case 1 :在k后面插入一个数x

由于只要掌握了单链表,这个应该就很好理解,所以我们直接上图解和代码。
在这里插入图片描述

void insert(int k, int x)
{
    e[idx] = x;
    l[idx] = k, r[idx] = r[k];
    l[r[k]] = idx, r[k] = idx ++ ;
}
case 2 :删除k结点

在这里插入图片描述

void de(int k)
{
    l[r[k]] = l[k];
    r[l[k]] = r[k];
}

2.模版题

在这里插入图片描述

这也是acwing上的一道模版题,直接上ac代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;

int m;
int e[N], l[N], r[N];
int idx = 0;

void unit()
{
    r[0] = 1,l[1] = 0;
    idx = 2;
}

void insert(int k, int x)
{
    e[idx] = x;
    l[idx] = k, r[idx] = r[k];
    l[r[k]] = idx, r[k] = idx ++ ;
}

void de(int k)
{
    l[r[k]] = l[k];
    r[l[k]] = r[k];
}

int main()
{
    cin >> m;
    unit();
    while(m --)
    {
        string op;
        cin >> op;
        int k, x;
        if (op == "L")
        {
            cin >> x;
            insert(0, x);
        }
        else if (op == "R")
        {
            cin >> x;
            insert(l[1], x);
        }
        else if (op == "D")
        {
            cin >> k;
            de(k + 1);
        }
        else if (op == "IL")
        {
            cin >> k >> x;
            insert(l[k + 1], x);
        }
        else
        {
            cin >> k >> x;
            insert(k + 1, x);
        }
    }
    for(int i = r[0]; i != 1;i = r[i])
    {
        cout << e[i] <<" ";
    }
    return 0;
}
  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值