当前位置: 首页 > article >正文

数据结构之线性表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

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


总结

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


http://www.kler.cn/a/9248.html

相关文章:

  • Chromium 中sqlite数据库操作演示c++
  • 【信号处理】基于联合图像表示的深度学习卷积神经网络
  • VSCode中python插件安装后无法调试
  • 【随机种子】Random Seed是什么?
  • ESLint 使用教程(四):ESLint 有哪些执行时机?
  • WPF+MVVM案例实战与特效(二十八)- 自定义WPF ComboBox样式:打造个性化下拉菜单
  • 【中级软件设计师】—操作系统考点总结篇(二)
  • 蓝桥杯嵌入式第十二届初赛题目解析
  • Baumer工业相机堡盟相机如何使用BGAPI SDK实现相机资源的正确释放(C++)
  • Redis使用教程之jedis客户端sendCommand方法的byte[]入参,防止混淆string的byte与数值byte的区别
  • 电脑误删除的文件怎么恢复
  • 从零开始学习Blazor
  • SHELL函数可课后作业
  • 使用Schrödinger Python API系列教程 -- 介绍 (一)
  • 6.S081——虚拟内存部分——xv6源码完全解析系列(2)
  • 用于语义分割模型的t-SNE可视化
  • ftp传输文件大小有限制吗 ftp文件传输工具有哪些
  • fate-serving-server增加取数逻辑并源码编译
  • vue3中tsx语法一些了解
  • Vue+nodejs快递收发寄件揽件代取网点查询系统
  • 编译技术-优化理论
  • 【剧前爆米花--爪哇岛寻宝】java文件操作和io流
  • 应急响应真的很重要!
  • 全排列1_dfs
  • 数据安全-数据分类分级方案设计
  • Thinkphp 6.0多语言