【数据结构】线性表(链表)

本文详细介绍了链表的定义、存储方法,包括单链表的初始化、取值、查找、插入、删除和清空操作,以及循环链表的特点和链接两个链表的方法。同时涵盖了双向链表的插入和删除。

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

链表的表示和实现

链表的定义

链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域

结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻

链表的存储方法
  1. 单链表
    单链表
  2. 循环链表
    循环链表
  3. 双向链表
    双向链表
优缺点

数据元素的个数可以扩充插入,删除等操作修改效率高;存储密度小;存取效率低,必须采取顺序存取,即按照链表顺序依次访问。

与链式存储相关的术语
  1. 头指针:指向链表中第一个结点的指针

  2. 首元结点:链表中存储第一个数据元素a1的结点

  3. 头结点:在链表的首元结点之前附设的一个结点;数据域内只放空表标志和表长等信息。为了操作一致性而设定。

相关术语

单链表的类型定义
typedef struct {
	ElemType data;//数据域
	struct LNode *next; //指针域
}LNode,*LinkList;//*LinkList为LNode类型的指针

LNode *p 与 LinkList p等价
单链表的重要基本操作
  1. 初始化
//初始化 (构造一个空的链表)
Status InitList(LinkList &L){
	L=new LNode; //生成新结点作为头结点,用头指针L指向头结点
	L->next=NULL;//头结点的指针域置空
	return OK;
} 
  1. 取值
//取值 (取出第i个结点的元素的值,并赋值给e)
Status GetElem(LinkList L,int i,ElemType &e)
{
	p=L->next;
	j=1; //计数器j初赋值为1
	while(p && j<i) //往后遍历,直到p为空或者p指向第i个元素
	{
		p=p->next; //p指向下一个结点
		j++;  //计数器加一
	}
	if(!p || j>i )  return ERROR;  //i>n 或者 i≤0 都不合法
	p=p->next;
	e=p->data; //取出第i个结点的数据域
	return OK;
}

  1. 查找
//查找(查找值为e的元素)
LNode* LocateElem(LinkList L,ElemType e)
{
	p=L->next;
	while(p && p->data!=e)
	{
		p=p->next;
	}
	return p; //查找成功返回值为e的结点地址;查找失败返回NULL
}
  1. 插入
    步骤:
    ①查找结点ai-1并由指针p指向该结点
    ②生成一个新结点 *s
    ③将 *s的数据域设为e,指针域指向结点ai
    ④将结点 *p的指针域指向新结点 *s
//插入  将e插入到表的第i个结点的位置 
Status ListInsert(LinkList &L,int i,ElemType e)
{
	p=L->next;
	j=1;
	while(p && j<i-1) //查找第i-1个结点
	{
		p=p->next; 
		j++;
	} 
	if( !p || j>i-1) return ERROR; //i>n+1 或者 i<1 都不合法
	LNode *s;
	s=new LNode;
	s->data=e;
	s->next=p->next;
	p->next=s;
	return OK;
}
  1. 删除
    步骤:
    ①查找结点ai-1并由指针p指向该结点
    ②临时保存待删除结点ai的地址在q中,已备释放
    ③将结点 *p的指针域指向ai的直接后继结点
    ④释放ai的空间
//删除  删除第i个结点 
Status ListDelete(LinkList &L,int i) 
{
	p=L->next;
	j=1;
	while(p && j<i-1 )
	{
		p=p->next;
		j++;
	}
	if(!(p->next) || j>i-1) return ERROR;//i>n 或者 i<1 都不合法
	//注意此语句与插入的不同点!
	q=p->next;
	p->next=q->next;
	delete q;
	return OK;
}
  1. 清空
//清空 
Status ClearList(LinkList &L){
	LinkList p,q;
	p=L->next;
	while(p)
	{
		q=p->next;
		delete p;
		p=q;
	}
	L->next=NULL;
	return OK;
}

7.销毁

Status Destroy_List(LinkList &L){
	LinkList p;
	while(L)
	{
		p=L;
		L=L->next;
		delete p;
	}
	return OK;
} 
  1. 创建单链表(前插法)
    前插法
//前插法
void CreateList_H(LinkList &L,int n) 
{
	L=new LNode; 
	L->next=NULL;
	for(int i=0;i<n;i++)
	{
		p=new LNode;//生成新结点
		cin>>p->data;
		p->next=L->next;//将新结点*p插入到头节点之后
		L->next=p;//更新头结点的指针域
	}
}
  1. 创建单链表(尾插法)
    尾插法
//尾插法 
void CreateList_R(LinkList &L,int n) 
{
	L=new LNode;
	L->next=NULL;
	r=L;  //尾指针r先指向头结点
	for(int i=0;i<n;i++)
	{
		p=new LNode;//生成新结点
		cin>>p->data;
		p->next=NULL;
		r->next=p;//将新结点*p插入尾节点*r之后
		r=p; //更新尾指针
	}
}
 
循环链表

定义:尾节点的指针域指向L

特点:从循环链表中的任何一个结点的位置都可以找到其他所有结点,而单链表做不到

注意:

  1. 循环链表没有明显的尾端,要避免死循环!

循环条件:

单链表循环链表
p != NULLp != L
p->next != NULLp->next != L
  1. 对循环链表,有时不给出头指针,而给出尾指针,可以更方便的找到第一个和最后一个结点

    首元结点:rear->next->next
    终端节点:rear

  • 两个单循环链表的链接
    循环链表连接
LinkList  Connect(LinkList  Ta,LinkList  Tb)
{//假设Ta、Tb都是非空的单循环链表
    p=Ta->next;              //p存表头结点
    Ta->next=Tb->next->next; //Tb表头连结Ta表尾
    delete Tb->next;         //释放Tb表头结点
    Tb->next=p;              //修改指针
    return  Tb;
}
双向链表
  1. 双向链表的插入
    插入
Status ListInsert_DuL(DuLinkList &L,int i,ElemType e){
   if(!(p=GetElemP_DuL(L,i))) return ERROR;
    s=new DuLNode; 
   s->data=e;
   s->prior=p->prior;  
   p->prior->next=s;
   s->next=p;  
   p->prior=s;
   return OK;
}
  1. 双向链表的删除
    删除
Status ListDelete_DuL(DuLinkList &L,int i,ElemType &e)
{
   if(!(p=GetElemP_DuL(L,i)))     return ERROR;
   e=p->data;
   p->prior->next=p->next;
   p->next->prior=p->prior;
   delete p; 
   return OK;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值