链表小结

本文主要探讨了链表的不同类型,包括单链表、双链表、循环链表和静态链表。阐述了它们的数据域、指针域、存储特点以及相关操作,如插入、删除节点等。此外,还提到了优化链表操作的时间复杂度,如使用尾指针对表尾操作的效率提升。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 单链表
    也就是线性表的链式存储,它是指通过一组任意的存储单元来存储线性表中的数据元素,每个链表结点包含存放数据元素的数据域(data域)和存放后继结点的指针域
    单结点的结点类型描述
typedef struct LNode
{
	Elemtype data;
	struct LNode *next;
}LNode,*Linklist;
//或
typedef struct LNode
{
	int data;
	struct LNode *next;
}LNode;

在这里插入图片描述
利用单链表可以解决顺序表需要大量连续存储空间的特点,但是单链表附加了指针域,也存在浪费存储空间的缺点。因为单链表的元素是离散地分布在存储空间中,所以单链表是非随机存储的存储结构
双链表结点定义

typedef struct DLNode
{
	int data;
	struct DLNode *prior;
	struct DLNode *next;
}DLNode;
//另一种定义方式如上类推

单链表基本操作

  • 头插法
LinkList List_headInsert(Linklist &L)
{
	LNode *s;
	int x;
	L=(Linklist)malloc(sizeof(LNode));//malloc函数创建头结点
	L->next=NULL;//初始为空链表
	scanf("%d",&x);
	while(x!=500)
	{
		s=(LNode*)malloc(sizeof(LNode));
		s->data=x;
		s->next=L->next;
		L->next=s;
		scanf("%d",&x);
		}
	return L:
}
//或
void createlistD(LNode *&c,int a[],int n)
{
	LNode *s;
	int i;
	c=(LNode*)malloc(sizeof(LNode));
	c->next=NULL;
	for(int i=0;i<n;i++)
	{ 
		s=(LNode*)malloc(sizeof(LNode));
		s->data=a[i];
		s->next=c->next;
		c->next=s;
	}
}

在这里插入图片描述

  • 尾插法
void createlistw(LNode *&C,int a[],int n)
{
	LNode *s,*r;//r始终指向c的终端结点
	int i;
	c=(LNode*)malloc(sizeof(LNode));
	c->next=NULL;
	r=c;//r指向头结点,此时头结点就是终端结点
	for(i=0;i<n;i++)
	{
		s=(LNode*)malloc(sizeof(LNode));
		s->data=a[i];//用新申请的结点接收数组a中的元素
		r->next=s;//用r来接纳新结点
		r=r->next;//r指向终端结点以便接收下一个到来的结点
	}
	r->next=NULL;//c建立完成
}
		
		
  • 按序号查找结点值
LNode *GetElem(LinkList L,int i)
{
	int j=1;
	LNode *p=L->next;
	if(i=0)
		return L;
	if(i<1)
		return NULL;
	while(p&&j<i)
	{
		p=p->next;
		j++;
	}
	return p;
}
  • 按值查找表结点
LNode *LocateElem(linklist L,ElemType e)
{
	LNode *p=L->next;
	while(p!=NULL&&p->data!=e)
		p=p->next;
	return p;
}
  • 插入结点操作
p=GetElem(L,i-1);//查找插入位置的前驱结点
s->next=p->next;
p->next;
  • 删除结点
p=GetElem(L,i-1);//查找删除位置的前驱结点
q->next;
p-next=q->next;
free(q);
  • 双链表尾插法
void createDlistW(DLNode *&L,int a[],int n)
{
	DLNode *s,*r;
	int i;
	L=(DLNode*malloc(sizeof(DLNode));
	L->prior=NULL;
	L->next=NULL;
	r=L;//r始终指向终端结点
	for(i=0;i<n;i++)
	{
		s=(DLNode*)malloc(sizeof(DLNode));
		s->data=a[i];
		//以下3句将s插入L的尾部
		r->next=s;
		s->prior=r;
		r=s;
		}
	r->next=NULL;
}//尾插法很好理解,就不画图了
  • 插入结点
s->next=p->next;
s->prior=p;
p->next=s;
s->next->prior=s;
  • 删除结点
q=p->next;
p->next=q.>next;
q->next->prior=p;
free(q);

循环链表

  • 循环单链表
    循环单链表和单链表的区别就是表中最后一个结点的指针不是NULL,而改为指向头结点,从而整个链表形成一个环
    在循环单链表中,表尾结点*r的next域指向L,故表中没有指针域为NULL的结点,所以循环单链表的判空条件不是头结点的指针是否为空,而是它是否等于头指针
    若设置头指针,对表尾进行操作时需要O(n)的时间复杂度,设置尾指针r,r->next即为头指针,对于表头与表尾进行操作都只需要O(1)的时间复杂度
    在这里插入图片描述
  • 循环双链表
    在循环双链表中,头结点的prior指针还要指向表尾结点
    在这里插入图片描述
  • 静态链表
    静态链表是借助数组来描述线性表的链式存储结构,结点同样也有数据域data和指针域next,但这里的指针是结点的相对地址,也就是数组下标,又称为游标
#define maxsize 50
typedef struct
{
	ElemType data;
	int next;
Slist[maxsize];
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值