【算法基础】单/双链表、栈和队列(用数组模拟)

单链表

每个结点包括数据和next指针,数据用数组e[]存储,指针指向下一个结点的数据对应在数组的下标,用ne[]存除;一开始头指针head设为-1,表示为空或者链表的尾部;维持一个变量idx表示下一个添加的结点的数据存储在数组中的位置,初始化为0。 

const int N=1e5+10;
int e[N],ne[N],idx,head;

void init()
{//初始化
    head=-1;
    idx=0;
}

void insert_head(int x)
{//向链表头插入x
    e[idx]=x;
    ne[idx]=head;
    head=idx++;
}

void insert(int k,int x)
{//在第 k 个插入的数后面插入一个数 x k>0
 //第 k 个插入的数对应的就是数组下标为 k-1 的结点
    e[idx]=x;
    ne[idx]=ne[k-1];
    ne[k-1]=idx++;
}

void delete_k(int k)
{//删除第 k 个插入的数后面的数 
 //当 k为 0 时,表示删除头结点
    if(k==0)
    {
        head=ne[head];
        return;
    }
    ne[k-1]=ne[ne[k-1]];
}

双链表

双链表最主要的是在初始化上,需要把左端点和右端点初始化好,左端点为下标为0的结点,右端点为下标为1的结点,初始化时需要让左端点的右指针指向右端点,右端点的左指针指向左端点。因为左端点和右端点占用了0和1,所以idx从2开始。

const int N=1e5+10;
int e[N],idx,l[N],r[N];

//函数中的所有k统一成下标
void init()
{
    r[0]=1;
    l[1]=0;
    idx=2;
}

void insert_l(int x)
{//在链表的最右端插入数 x
    e[idx]=x;
    r[idx]=r[0];
    l[idx]=0;
    r[0]=idx++;
}

void insert_r(int x)
{//在链表的最左端插入数 x
    e[idx]=x;
    l[idx]=l[1];
    r[idx]=1;
    l[1]=idx++;
}

void delete_k(int k)
{//将第 k 个插入的数删除
    l[r[k]]=l[k];
    r[l[k]]=r[k];
}

void insert_kr(int k,int x)
{//在第 k 个插入的数右侧插入一个数
    e[idx]=x;
    r[idx]=r[k];
    l[idx]=k;
    l[r[idx]]=idx;
    r[k]=idx++;
}

void insert_kl(int k,int x)
{//在第 k 个插入的数左侧插入一个数
    e[idx]=x;
    r[idx]=k;
    l[idx]=l[k];
    l[k]=idx;
    r[l[idx]]=idx;
    idx++;
    //最后两句不能合并成:r[l[idx]]=idx++;!!!
}

其实对于在左/右端点插入不需要特别实现函数:

insert_kr(l[1],x);//在右端点的左边结点后插入就是在左端点插入
insert_kr(0,x);//在左端点插入

栈和队列

对于栈和队列我们只需要明确一点,我们需要维持边界:

栈需要维持栈顶指针tt;队列需要维持队头和队尾指针hhtt;

栈的栈顶指针表示新的元素需要插入的位置,取栈的顶部元素需要使用tt-1的下标,tt最开始初始化为0

队列hh表示队头,tt表示队尾,分别表示第一个元素和最后一个元素的下标。

队列为空则有tt<hh。tt初始化为-1,hh初始化为0。++tt才表示新元素需要插入的位置

int tt=0;
int st[N];//栈
int q[N];//队列
int hh=0,tt=-1;

经典习题

单链表

双链表

模拟栈

模拟队列

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值