数据结构之线性表3

我们的目标:

1、了解线性结构的特点 掌握顺序表的定义、查找、插入和删除。

2、掌握链表的定义、创建、查找、插入和删除。

3、能够从时间和空间复杂度的角度比较两种存储结构的不同特点及其适用场合。(持续更新)


前言

本章节内容主要介绍线性表的链式表示和实现,即链表的使用。


继续上一篇内容:http://t.csdn.cn/KwKsg

三、链表

我们都知道,线性表的链式存储结构的特点是在逻辑上相邻的数据元素在物理上不一定相邻。

上一篇我们讲到了单链表,所以接下来来介绍循环链表。

1.1  循环链表

循环链表是另一种形式的链式存储结构。和单链表不同的是,它最后不是NULL,而是L(通俗来讲因为循环没有尽头)。

类似地,还有非空单循环链表和空表。如图所示:

12d9dda3e7774160925bf0a44342b813.png

5399b0cbb5a14278ac3f7f01f24c8c96.png

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

并且循环链表中没有明显的尾端——>如何避免死循环?

我们知道循环条件是

//单链表
p!=NULL
p->next!=NULL
//循环链表
p!=L
p->next!=L

进而说明对循环链表,有时不给出头指针,而给出尾指针可以更方便的找到第一个和最后一个结点。

e73e3ca9981b479b86e0bca28c104560.png

那么如何查找开始结点和终端结点?

答:开始结点:rear->next->next                  

        终端结点:rear 


1.1.2  循环链表的合并——单循环链表

下面是一个单循环链表:

978ebe97d5b241d296354a0d4af49c83.png

 代码实现:

LinkList  Connect(LinkList  Ta,LinkList  Tb)
{//假设Ta、Tb都是非空的单循环链表
          p=Ta->next;                                   //①p存表头结点
          Ta->next =Tb->next->next;                     //②Tb表头连结Ta表尾
          deleteTb->next;                               //③释放Tb表头结点
          Tb->next=p;                                   //④修改指针
          return  Tb;
}

总结:上述操作的时间复杂度为O(1)。


1.2 双向链表

如图所示:

62b2986e2ab04c97931124076d6eb7ad.png

28597552022b4c7c98e1d50a6ea4b268.png

 代码实现:

//---双向链表的存储结构---
typedef struct DuLNode{
    ElemType   data;              //数据域
    struct DuLNode  *prior;       //指向直接前驱
    struct DuLNode  *next;        //指向直接后继
}DuLNode, *DuLinkList;

双向链表分为两种,如图所示,图b中有两个环,而图a中只有一个表头结点的空表。

3b3586eec8b4427b81a16fe5818f4ca4.png

5ddbabdb197942c6b886920ac36bd13e.png

在双向链表中,若d为指向表中某一节点的指针:

 d->next->prior = d->prior->next = d


1.2.1 双向链表的插入

8e4e37d79a4e4b0eafe56068865029e6.png

代码实现: 

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.2.2 双向链表的删除

d41bc25472ac4ab8a3ade4f09d0bfb49.png

1. p->prior->next=p->next;                2. p->next->prior=p->prior; 

代码实现:

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;
}

四、顺序表和链表的比较

在实际应用中,我们不能说哪种的存储结构更好,由于它们各有优缺点,选用哪种存储结构,则应根据具体问题具体分析,通常从空间性能和时间性能两个方面作比较分析。

f527cd13f43e447abd87be4a333ae1d6.png

五、线性表的应用

5.1 线性表的合并 

求解一般集合的并集问题:

问题:假设利用两个线性表La和Lb分别表示两个集合A和B,现要求一个新的集合:                                  A=A    B。例如, La=(7, 5, 3, 11)      Lb=(2, 6, 3)      设合并后La=(7, 5, 3, 11, 2, 6)

步骤:

依次取出Lb 中的每个元素,执行以下操作:

1.在La中查找该元素;

2.如果找不到,则将其插入La的最后。

代码实现:

void union(List &La, List Lb){
  La_len=ListLength(La);
  Lb_len=ListLength(Lb); 
  for(i=1;i<=Lb_len;i++){
      GetElem(Lb,i,e);
      if(!LocateElem(La,e)) 
           ListInsert(&La,++La_len,e);                     
  }
}

时间复杂度为:

7d496a02a53c456cb3c0e01d4fd66761.png

5.2 有序表的合并

有序表:线性表中的数据元素相互之间可以比较,且数据元素在线性表中依值非递减或非递增有序排列。

求解有序集合的并集问题:

问题:已知线性表La 和Lb中的数据元素按值非递减有序排列,现要求将La和Lb归并为一个新的线性表Lc,且Lc中的数据元素仍按值非递减有序排列。例如,

La=(1 ,7, 8) Lb=(2, 4, 6, 8, 10, 11)   则Lc=(1, 2, 4, 6, 7 , 8, 8, 10, 11)

步骤:

1. 创建一个空表Lc;

2. 依次从 La 或 Lb 中“摘取”元素值较小的结点插入到 Lc 表的最后,直至其中一个表变空为止;

3. 继续将 La 或 Lb 其中一个表的剩余结点插入在 Lc 表的最后。

代码实现:

void MergeList_Sq(SqList LA,SqList LB,SqList &LC){ 
     pa=LA.elem;  pb=LB.elem;     //指针pa和pb的初值分别指向两个表的第一个元素 
     LC.length=LA.length+LB.length;      	//新表长度为待合并两表的长度之和 
     LC.elem=new ElemType[LC.length];    	//为合并后的新表分配一个数组空间 
     pc=LC.elem;                         		//指针pc指向新表的第一个元素 
     pa_last=LA.elem+LA.length-1; 	//指针pa_last指向LA表的最后一个元素 
     pb_last=LB.elem+LB.length-1; 	//指针pb_last指向LB表的最后一个元素 
     while(pa<=pa_last && pb<=pb_last){  	//两个表都非空 
      if(*pa<=*pb) *pc++=*pa++;        	//依次“摘取”两表中值较小的结点      
      else *pc++=*pb++;      } pa++;             //LB表已到达表尾
     while(pb<=pb_last)  *pc+
     while(pa<=pa_last)  *pc++=*+=*pb++;          //LA表已到达表尾 
}//MergeList_Sq 

时间复杂度/空间复杂度为:

4c0cc2a499fa4124b9495c077f864043.png

有序表合并的优点:不需要开辟新的存储空间,可以使空间复杂度达到最低。


总结

以上就是本节所讲的内容,主要讲解链表的应用以及与顺序表的比较。希望各位大佬多多指点,我会在数据结构上一直持续更新下去!感谢佬们点支持!

  • 21
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 34
    评论
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山楂山楂丸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值