单链表的实现

本文介绍了单链表的基本操作,包括取值、按值查找、插入和删除,以及时间复杂度分析。同时讨论了循环链表和双向链表的概念,强调了它们在查找和操作上的优势与特点,并给出了相应的插入和删除算法。
摘要由CSDN通过智能技术生成

带头结点的单链表

类型定义
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
变量定义
LinkList L;
LNode *p,*s;
重要操作:
p=L;//P指向头结点
s=L->next;//S指向首元结点
P=P->next;//p指向下一个结点

算法:取值-----取单链表中第i个元素的内容

思考:顺序表里如何找到第i个元素?L->elem[i-1]

思考:链表怎么取出第3个元素和第15个元素?

从链表的头指针出发,顺着链域next逐个结点往下搜索,直到搜索到第i个结点为止。因此,链表不是随机存取结构。链表第一个指向1,因此没有0,-1;

算法步骤:

1.从第1个结点(L->next)顺链扫描,用指针p指向当前扫描到的结点,p初值p=L->next.

2.j做计数器,累计当前扫描过的节点数,j初值为1.

3.当p指向扫描到的下一结点时,计时器j加1.

4.当j==i时,p所指的结点就是要找的第i个结点。

status GetElem_L(LinkList L,int i,ElemType &e){
p=L->next;j=1;//初始化
while(p&&j<1){
p=p->next;++j;//向后扫描,直到p指向第i个元素或p为空
}
if(!p||j>i)return ERROR;//第i个元素不存在
e=p->data;//取第i个元素
return OK;
}//GetElem_L

单链表的查找

1.按值查找:根据指定数据获取该数据所在的位置(地址)

如:分别查找值为30和值为15的元素

查找地址  和值查找

Lnode *LocateELem_L(LinkList L,Elemtype e)
{
p=L->next;
while(p&&p->data!=e)
p=p->next;
return p;
}
int LocateElem_L(LinkList L,Elemtype e)
{
p=L->next;j=1;
while(p&&p->data!=e)
{
p=p->next;j++;
}
if(p)return j;
else return 0;
}

链式表的插入:在第i个结点前插入新结点

status ListInsert_L(LinkList &L,int i,ElemType e){
p=L;j=0;
while(p&&j<i-1){p=p->next;++j;}//寻找第i-1个结点,p指向i-1结点
if(!p||j>i-1)return ERROR;
s=new LNode;s->data=e;
s->next=p->next;
p->next=s;
return OK;
}//ListInsert_L

链表的删除:删除第i个结点

status ListDelete_L (LinkList &L,int i,ElemType &e){
p=L;j=0;
while(p->next&&j<i-1){p=p->next;++j;}
if(!p->next||j>i-1)return ERROR;
q=p->next;
p->next=q->next;
e=q->data;
delete q;
return OK;
}//ListDelete_L

单链表的查找,插入,删除算法时间效率分析

1.查找:线性链表只能顺序查找,从头指针开始,O(n)

2.插入和删除:链表不需要移动元素,只需要修改指针,一般情况下啊,时间复杂度为O(1)

但是,如果要在单链表中进行前插或者删除操作,由于要从头查找前驱结点,所消耗时间复杂度为O(n).

单链表的建立

1.头插法:元素插入在链表头部,也叫做前插法

从一个空表开始,重复读入数据;

生成新结点,将读入数据存放到新结点的数据域中。

从最后一个结点开始,依次将各结点插入到链表的前端。

例子:建立链表L(A,B,C,D,E)

1.E。2.E,D。3.E,D,C。4.E,D,C,B。5.E,D,C,B,A。

void CreateList_H(LinkList &L,int n){
L=new LNode;//建立一个带头结点的单链表
L->next=NULL;
for(i=n;i>0;--i){
p=new LNode;
cin>>p->data;
p->next=L->next;
L->next=p;
}
}//CreateList_H

2.尾插法:元素插入在链表尾部,也叫做后插法

从一个空表L开始,将新结点逐个插入到链表的尾部,尾指针R指向链表的尾结点。

初始时,R同L均指向头结点。每读入一个数据元素则申请一个新的结点,将新结点插入到尾结点后,R指向新结点。

算法描述:正位序输入n个元素的值,建立带表头结点的单链表L

void CreateList_R(LinkList &L,int n){
L=new LNode; L->next=NULL;
r=L;//尾指针R指向头结点
for(i=0;i<n;++i)
{
p=new LNode;
cin>>p->data;
p->next=NULL;
r->next=p;
r=p;
}
}//CreateList_R

循环链表:是一种头尾相接的链表(既:表中最后一个结点的指针域指向头结点,整个链表形成一个环)。

优点:从表中任意一个结点出发均可以找到表中其他结点。

注意:由于循环链表中没有NULL指针,故涉及到遍历操作时,其终止条件就不再像非循环链表那样判断p或者p->next是否为空,而是判断题目是否等于头指针。

头指针表示单循环链表(找到a1的时间复杂度:O(1)找到an的时间复杂度为O(n).)

注意:表的操作常常是在表的首尾位置上进行。

尾指针表示单循环链表(a1的存储位置是:R->next->next.an的存储位置是:R,时间复杂度为O(1)。)

如何将带尾指针循环链表进行合并(Tb合并在Ta之后)

1.p存放表头结点

2.Tb表头连接到Ta表尾

3.释放Tb表头结点

4.修改指针

算法描述:

LinkList Connect(LinkList Ta,LinkList Tb){
//假设Ta,Tb都是非空的单循环链表
p=Ta->next;
Ta->next=Tb->next->next;
delete Tb->next;
Tb->next=p;
return Tb;
}

双向链表

单链表的结点-》有指示后继的指针域-》找后继结点方便。

既:查找某一个结点的后继结点的执行时间为O(1);

无指示前驱的指针域-》找前驱结点难:从表头出发寻找。

既:查找某个结点的前驱结点的执行时间为O(n).

双向链表:在单链表的每个结点里面再增加一个指向其直接前驱的指针域prior,这样链表中就形成了有2个方向不同的链,故称为双向链表。

双向链表的结构可定义如下:
typedef struct DuLNode{
Elemtype data;
struct DuLNode *prior,*next;
}DuLNode,*DuLinkList;

双向循环链表和单链表类似,双向链表也可以有循环表

1.让头结点的前驱指针指向链表的最后一个结点。

2.让最后一个结点的后继指针指向头结点。

双向链表结构的对称性(设指针p指向某一结点):

p->prior->next=p=p->next->prior;

在双向链表中有些操作(如:ListLength,GetElem等)因为仅仅涉及一个方向的指针,故它们的算法与线性链表的相同。但在插入,删除时,则需要同时修改两个方向上的指针,两者的操作的时间复杂度均为O(n).

算法:双向链表的插入

void ListInsert_DuL(DuLinkList &L,int i;ElemType e){
//在带头结点的双向循环链表L中第i个位置之前插入元素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;
}//ListInsert_DuL

算法:双向链表的删除

void listdetele_dul(dulink &L,int i,ElemType &e)
{
//删除带头结点的双向链表的第i个元素,并用e返回。
if(!(p=grtelemp_dul(L,i)))return EROR;
e=p->data;
p->prior->next=p->next;
p->next->prior=p->prior;
free(p);
return OK;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值