1、首先我们要知道单链表和双链表是什么:
单链表和双链表是两种常见的数据结构,它们都属于链表的一种。链表是一种物理存储单元上非连续的、非顺序的线性序列,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
1、单链表
1、在单链表中,每个节点只有一个指向下一个节点的指针。这意味着从头节点开始,我们可以遍历整个链表,但是无法从尾节点反向遍历回头节点。
2、单链表的主要操作包括插入、删除和查找。在插入和删除操作中,通常需要在链表中找到特定的节点。查找操作则可能需要从头节点开始遍历整个链表
3、单链表的一个主要优点是它可以在O(1)的时间内完成尾部插入操作,因为尾节点总是有一个指向下一个节点的指针,可以直接修改这个指针来添加新节点。
2、双链表
1、单链表的一个主要优点是它可以在O(1)的时间内完成尾部插入操作,因为尾节点总是有一个指向下一个节点的指针,可以直接修改这个指针来添加新节点。
2、双链表的主要操作与单链表类似,但由于有双向指针,某些操作(如删除节点)可能会更加高效。
3、双链表的一个缺点是它需要更多的内存来存储额外的指针。
总结:
单链表和双链表的主要区别在于它们节点的指针数量以及因此带来的操作复杂性和内存需求。选择使用哪种链表取决于具体的应用场景和需求。
2、一般的单链表和双链表
一般的单链表我我们都是定以一个struct(结构)然后创建一个头节点然后再开辟多给节点,每次开辟一个节点就要使用malloc来开辟一个空间。然后用next指针指向下个节点。这样子循环遍历。
今天我来讲解一下用数组的实行来实现单链表和双链表。
3、单链表
首先我们先来看下题目这是一个经典单链表通过实现数据的插入、删除。
我们直接上代码
#include<stdio.h>
#define N 100010
int e[N],ne[N],total=0,head=-1;//total代表都是每个数的下标
void head_add(int x)//头插法
{
e[total]=x;
ne[total]=head;
head=total++;
}
void add(int k,int x)在下标为k的数插入一个数
{
e[total]=x;
ne[total]=ne[k];//1前1后相当于
ne[k]=total++;
}
void delet(int k)删除节点就是在该个的节点指向下个节点
{
ne[k]=ne[ne[k]];
}
int main()
{
int n;
char m;
scanf("%d",&n);
while(n--)
{
int k=0,x=0;
scanf("\n%c",&m);
if(m=='H')
{
scanf("%d",&x);
head_add(x);
}
else if(m=='D')
{
scanf("%d",&k);
if(k)delet(k-1);
else head=ne[head];
}
else
{
scanf("%d%d",&k,&x);add(k-1,x);
}
}
for(int i=head;i!=-1;i=ne[i])printf("%d ",e[i]);
}
我们这边先定义了2个数组一个是e[N],另一个是ne[N],其中n代表的是将这个数据存入到这个数组里面,而ne则是代表的是下个数的下表而下表我们用的是total来计数。最后我们通过for顺序来遍历因为head=-1我们在头插的时候相当于把-1一直赋值到ne的下个数所以我们用for循环当最后i=-1时结束循环也就是最后一个数。
4、双链表
我们先来看题目本题是为了显示在一个数据中在左边和右边插入一个数据和删除,现在就体现了双链表的定义,我们可以指向前面也可以指向后面,操作也是非常的方便我们这边也是通过数组的方式来实现双链表的定义。首先我们来看下双链表是怎么操纵的。
初始化:这个就相当于一个节点他有一个L数据和R数据存储的是左边和右边的位置。
void init()
{
r[0]=1;l[1]=0;//令刚开始为一个节点初始化指向右边和左边我们可以把这个想象成2个点
head = -1;
idx = 0;
}
每次插入我们都是在这个2数据的中间经行操作
void add(int k,int x)
{
e[idx]=x;
l[idx]=k;
r[idx]=r[k];
l[r[k]]=idx;
r[k]=idx++;
}
删除就更加简单了
我们要改变左边的R就要把当前的这个数取出来也就是L[k]我们再把它指向右边的值改变也就是R[L[k]]=R[k]。同理右边也是一样
void delet(int k)
{
l[r[k]]=l[k];
r[l[k]]=r[k];
}
然后我们来看下整体的代码
#include<stdio.h>
#include<string.h>
#define N 100010
int l[N],r[N],e[N],idx=2;
void add(int k,int x)
{
e[idx]=x;
l[idx]=k;
r[idx]=r[k];
l[r[k]]=idx;
r[k]=idx++;
}
void delet(int k)
{
l[r[k]]=l[k];
r[l[k]]=r[k];
}
int main()
{
r[0]=1;l[1]=0;
int n;
scanf("%d",&n);
while(n--)
{
int x,k;
char op[3];//3个数组实际只能用2个还有一个为/0表示结束语
scanf("\n%s",op);
if(op[0]=='L')
{scanf("%d",&x);
add(0,x);}
if(op[0]=='R')
{scanf("%d",&x),add(l[1],x);}//最右边插入我们要取出前面的那个数也就是
if(op[0]=='D')
{scanf("%d",&k);delet(k+1);}
if(!strcmp(op,"IR"))
{
scanf("%d%d",&k,&x);
add(k+1,x);
}
if(!strcmp(op,"IL"))
{
scanf("%d%d",&k,&x);
add(l[k+1],x);
}
}
for(int i=r[0];i!=1;i=r[i])printf("%d ",e[i]);
return 0;
}
要注意最后的时候R[0]这个点最后再链表的最前面,L[1]而是在最后面,所以我们在插入最左边和最右边的时候要注意k的值。