版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第二章 线性表,2.1 线性表的概念及运算 2.1.1 线性表的逻辑结构 2.1.2 线性表的运算 2.2 线性表的顺序存储 2.2.1 顺序表 2.2.2 顺序表的基本运算 2.3 线性表的链式存储 2.3.1 单链表 2.3.2 单链表的基本运算 2.3.3 循环链表 2.3.4 双向链表 2.3.5 静态链表(基本概念) 2.4 顺序表和链表的比较,2.1 线性表的概念及运算 线性表(Linear List) :由n(n)个数据元素(结点)a1,a2, an组成的有限序列。其中数据元素的个数n定义为表的长度。当n=0时称为空表,常常将非空的线性表(n0)记作: (a1,a2,an) 例1
2、、26个英文字母组成的字母表 (A,B,C、Z) 例2、某校从1978年到1983年各种型号的计算机拥有量的变化情况。 (6,17,28,50,92,188),例3、学生健康情况登记表如下,例4、一副扑克的点数 (2,3,4,J,Q,K,A),从以上例子可看出线性表的逻辑特征是: 在非空的线性表,有且仅有一个开始结点a1,它没有直接前趋,而仅有一个直接后继a2; 有且仅有一个终端结点an,它没有直接后继,而仅有一个直接前趋a n-1; 其余的内部结点ai(2in-1)都有且仅有一个直接前趋a i-1和一个直接后继a i+1。 线性表是一种典型的线性结构。 数据的运算是定义在逻辑结构上的,而运算
3、的具体实现则是在存储结构上进行的。,利用线性表的基本操作清除表L中多余的 重复节点 PURGE(Linear_list *L ) int i=1,j,x,y; while(iLENGTH(L) x=GET(L,i); j=i+1; while(j=LENGTH(L) y=GET(L,j); if(x=y)DELETE(L,j); else j+; i+; ,2.2 线性表的顺序存储结构2.2.1 线性表,把线性表的结点按逻辑顺序依次存放在一组地址连续的存储单元里。用这种方法存储的线性表简称顺序表。 假设线性表的每个元素需占用C个存储单元,并以所占的第一个单元的存储地址作为数据元素的存储位置。则
4、线性表中第i+1个数据元素的存储位置LOC( a i+1)和第i个数据元素的存储位置LOC(ai)之间满足下列关系: LOC(a i+1)=LOC(a i)+c 线性表的第i个数据元素ai的存储位置为: LOC(ai)=LOC(a1)+(i-1)*c,由于C语言中的一维数组也是采用顺序存储表示,故可以用数组类型来描述顺序表。又因为除了用数组来存储线性表的元素之外,顺序表还应该用一个变量来表示线性表的长度,所以我们用结构类型来定义顺序表类型。 # define MaxSize 1024 typedef int DataType; typedef struct DataType dataMaxSi
5、ze; int last; Sequenlist;,2.2.2 顺序表上的基本运算 C语言中的数组下标从“0”开始,因此,若L是Sequenlist类型的顺序表变量,则表中第i个元素是l.datai-1。若L是Sqlist类型的顺序表指针变量,则表中第i个元素是(*l).datai-1或 l-datai-1。 以下主要讨论顺序表的插入和删除两种运算。 1、插入 线性表的插入运算是指在表的第i(0in)个位置上,插入一个新结点x,使长度为n的线性表:(a0,a i-1,ai,an-1), 变成长度为n+1的线性表 (a0,a i-1,x,ai,an-1),int Insert(sequenlis
6、t *l,DataType x,int i) /顺序表从0开始,i的位置为i-1 int j; if(il-last+1) printf(Position error); return NULL; if(l-last=MaxSize-1) printf(overflow); return NULL; for(j=l-last;j=i-1;j-) l-dataj+1=l-dataj; l-datai-1=x; l-last+; return 1; ,分析算法的复杂度。 这里的问题规模是,设表的长度为n。该算法的时间主要花费在结点后移语句的循环上,该语句的执行次数(即是移动结点的次数)。由此可看出
7、,所需移动结点的次数不仅依赖于表的长度,而且还与插入位置有关。 当i=n时,由于循环变量的终值大于初值,结点后移语句将不进行;这是最好情况,其时间复杂度O(1); 当i=0时,结点后移语句将循环执行n次,需移动表中所有结点,这是最坏情况 其时间复杂度为O(n)。,表项的插入,25 34 57 16 48 09 63 ,0 1 2 3 4 5 6 7,data,50,插入 x,25 34 57 50 16 48 09 63 ,0 1 2 3 4 5 6 7,data,50,i,2、删除 线性表的删除运算是指将表的第i(0in-1)结点删除,使长度为n的线性表: (a0,a i-1,ai,a i+
8、1,an-1) 变成长度为n-1的线性表 (a0,a i-1,a i+1,an-1) int Delete(Sequenlist *L,int i) int j; if(il.last) printf(“Position error”); return NULL; for(j=i;jlast;j+) l-dataj-1=l-dataj; l-last-; ,该算法的时间分析与插入算法相似,结点的移动次数也是由表长n和位置i决定。 若i=n,则由于循环变量的初值大于终值,前移语句将不执行,无需移动结点; 若i=1,则前移语句将循环执行n-1次,需移动表中除开始结点外的所有结点。这两种情况下算法的
9、时间复杂度分别为O(1)和O(n)。 平均时间复杂度也是O(n)。,表项的删除,2.3 线性表的链式存储,线性表的顺序表示的特点是用物理位置上的邻接关系来表示结点间的逻辑关系,这一特点使我们可以随机存取表中的任一结点,但它也使得插入和删除操作会移动大量的结点.为避免大量结点的移动,我们介绍线性表的另一种存储方式,链式存储结构,简称为链表(Linked List)。 链表是指用一组任意的存储单元来依次存放线性表的结点,因此,链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息,这个信息称为指针(pointe
10、r)或链(link)。这两部分组成了链表中的结点结构: 其中:data域是数据域,用来存放结点的值。next是指针域(亦称链域),用来存放结点的直接后继的地址(或位置)。,2.3.1 单链表,链表正是通过每个结点的链域将线性表的n个结点按其逻辑次序链接在一起的。由于上述链表的每一个结只有一个链域,故将这种链表称为单链表(Single Linked)。显然,单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。同时,由于终端结点无后继,故终端结点的指针域为空,即null(图示中也可用表示)。,例1、线性表:(bat,cat,eat,fat,
11、hat,mat)的单链表示意图如下:,头指针 head,head,单链表由表头唯一确定,因此单链表可以用头指针的名字来命名。 例如:若头指针名是head,则把链表称为表head用C语言描述的单链表如下: typedef char datatype; typedef struct node datatype data; struct node *next; listnode; typedef listnode *linklist; linklist head ,p;,一、建立单链表 假设线性表中结点的数据类型是字符,我们逐个输入这些字符型的结点,并以换行符n为输入结束标记。动态地建立单链表的常用
12、方法有如下两种: 1、头插法建表 该方法从一个空表开始,重复读入数据,生成新结点,将读入数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头上,直到读入结束标志为止。如读入ABCDE,产生如下形式:,linklist createlist_first(void) /不带头结点 DataType ch; linklist head,p; head=NULL; ch=getchar( ); while (ch !=n) p=(listnode*)malloc(sizeof(listnode); p-data=ch; p-next=head; head=p; ch=getchar( ); r
13、eturn (head); ,2、尾插法建表 头插法建立链表虽然算法简单,但生成的链表中结点的次序和输入的顺序相反。若希望二者次序一致,可采用尾插法建表。该方法是将新结点插入到当前链表的表尾上,为此必须增加一个尾指针p,使其始终指向当前链表的尾结点。例如读入ABCDE,产生如下形式:,linklist createlist_last() /不带头接点 DataType ch; linklist head,p,q; p=head=NULL; while(ch=getchar()!=n) q=(listnode *)malloc(sizeof(listnode); q-data=ch; if(he
14、ad=NULL) head=q; else p-next=q; p=q; p-next=NULL; return head ; ,如果我们在链表的开始结点之前附加一个结点,并称它为头结点,那么会带来以下两个优点: a、由于开始结点的位置被存放在头结点的指针域中,所以在链表的第一个位置上的操作就和在表的其它位置上的操作一致,无需进行特殊处理; b、无论链表是否为空,其头指针是指向头结点 在的非空指针(空表中头结点的指针域为空),因此空表和非空表的处理也就统一了。 其算法如下:,带表头结点的单链表,linklist create_headnode_list()/带头接点 char ch; link
15、list head=(linklist)malloc(sizeof(listnode); listnode *p,*r; r=head; while(ch=getchar( )!=n) p=(listnode*)malloc(sizeof(listnode); pdata=ch; rnext=p; r=p; rnext=NULL; return(head); ,查看创建不带头节点链表,建立带头节点的尾插法链表,在算法中,凡是涉及动态申请新结点空间时都应加错误处理: p=(listnode*)malloc(sizeof(listnode) if(p=NULL) printf(“No space
16、for node can be obtained”); return NULL; 以上算法的时间复杂度均为O(n)。,linklist getnode(linklist head, int i) /从带头节点的链表中获取第i个节点的指针 int j=1; listnode * p=head-next; while(p ,二、查找运算 1、按序号查找 在链表中,即使知道被访问结点的序号i,也不能象顺序表中那样直接按序号i访问结点,而只能从链表的头指针出发,顺链域next逐个结点往下搜索,直到第i个结点为止。因此,链表不是随机存取结构。 设单链表的长度为n,要查找表中第i个结点,仅当1in时,i的
17、值是合法的。但有时需要找头结点的位置,故我们将头结点看做是第0 个结点,其算法如下:,Listnode * locatenode(linklist head,int key) /带头节点 listnode * p=headnext; while( p 该算法的执行时间亦与输入实例中的的取值key有关,其平均时间复杂度的分析类似于按序号查找,也为O(n)。,2、按值查找 按值查找是在链表中,查找是否有结点值等于给定值key的结点,若有的话,则返回首次找到的其值为key的结点的存储位置;否则返回NULL。查找过程从开始结点出发,顺着链表逐个将结点的值和给定值key作比较。其算法如下:,三、插入运算
18、 插入运算是将值为x的新结点插入到表的第i个结点的位置上(即第i个结点前),即插入到ai-1与ai之间。因此,我们必须首先找到ai-1的存储位置p,然后生成一个数据域为x的新结点*q,并令结点*p的指针域指向新结点,新结点的指针域指向结点ai。从而实现三个结点ai-1,x和ai之间的逻辑关系的变化,插入过程如:,void insert_node(linklist *head,DataType x,int i) /带头节点, i的有效范围1next; int j=0; while ( q != NULL 时间复杂度亦为O(n),在带头节点的链表中插入节点,四、删除运算 删除运算是将表的第i个结点
19、删去。因为在单链表中结点ai的存储地址是在其直接前趋结点a i-1的指针域next中,所以我们必须首先找到a i-1的存储位置p。 然后令pnext指向ai的直接后继结点,即把ai从链上摘下。最后释放结点ai的空间,将其归还给“存储池”。用free(p)函数。,void delete_node(linklist *head, int i) /带头节点,i的有效范围1next,q; int j=0; while (p-next!=NULL ,在带头节点的链表中删除节点,设单链表的长度为n,则删去第i个结点仅当1in时是合法的。注意,当i=n+1时,虽然被删结点不存在,但其前趋结点却存在,它是终端
20、结点。因此被删结点的直接前趋*p存在并不意味着被删结点就一定存在,仅当*p存在(即p!=NULL)且*p不是终端结点 (即pnext!=NULL)时,才能确定被删结点存在。 显然此算法的时间复杂度也是O(n)。 从上面的讨论可以看出,链表上实现插入和删除运算,无须移动结点,仅需修改指针。,写一算法,对单链表实现就地逆置 Status LinkConvert(LinkList ,2.3.2 循环链表,循环链表时一种头尾相接的链表。其特点是无须增加存储量,仅对表的链接方式稍作改变,即可使得表处理更加方便灵活。 单循环链表:在单链表中,将终端结点的指针域NULL改为指向表头结点的或开始结点,就得到了
21、单链形式的循环链表,并简单称为单循环链表。 为了使空表和非空表的处理一致,循环链表中也可设置一个头结点。这样,空循环链表仅有一个自成循环的头结点表示。如下图所示:, 非空表, 空表,在用头指针表示的单链表中,找开始结点a1的时间是O(1),然而要找到终端结点an,则需从头指针开始遍历整个链表,其时间是O(n),在很多实际问题中,表的操作常常是在表的首尾位置上进行,此时头指针表示的单循环链表就显得不够方便.如果改用尾指针rear来表示单循环链表,则查找开始结点a1和终端结点an都很方便,它们的存储位置分别是(rearnext) next和rear,显然,查找时间都是O(1)。因此,实际中多采用尾
22、指针表示单循环链表。 由于循环链表中没有NULL指针,故涉及遍历操作时,其终止条件就不再像非循环链表那样判断p或pnext是否为空,而是判断它们是否等于某一指定指针,如头指什或尾指针等。,例、在链表上实现将两个带头节点循环线性表(a1,a2,a3,an)和(b1,b2,b3,bn)链接成一个线性表的运算。(ha和hb分别指向表尾) linklist connect(linklist ha,linklist hb) linklist p=ha-next; ha-next=hb-next-next; free(hb-next); hb-next=p; return(hb); ,2.3.3双链表,双
23、向链表(Double linked list):在单链表的每个结点里再增加一个指向其直接前趋的指针域prior。这样就形成的链表中有两个方向不同的链,故称为双向链表。形式描述为: typedef struct dnode datatype data; struc dnode *prior,*next; dlistnode; typedef dlistnode * dlinklist; dlinklist head;,和单链表类似,双链表一般也是由头指针唯一确定的,增加头指针也能使双链表上的某些运算变得方便,将头结点和尾结点链接起来也能构成循环链表,并称之为双向链表。 设指针p指向某一结点,则双
24、向链表结构的对称性可用下式描述: (pprior)next=p=(pnext)prior 即结点*p的存储位置既存放在其前趋结点*(pprior)的直接后继指针域中,也存放 在它的后继结点*(pnext)的直接前趋指针域中。,双向循环链表的插入 (非空表),first,first,31,48,15,在结点 *p 后插入25,p,p,31,48,25,15,q-prior = p; q-next = p-next; p-next = q; q-next-prior = q;,q,双向循环链表的插入 (空表),first,在结点 *p 后插入25,p,q,25,q-prior = p; q-next = p-next; ( = first ) p-next = q; q-next-prior = q; ( first-prior = q ),first,p,双向链表的前插操作算法如下: void d_insert_befor(dlistnode *p,datatype x) dlistnode *q=malloc(siz
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 美育基础概述 3
- 婚姻家庭继承法原理与实务
- 山西大学附属中学2025-2026学年高一下学期期中考试物理试卷
- 加油站消防安全管理制度
- 结构化视角下小学数学单元复习教学策略-以“圆”为例
- 义务教育学校标准化建设监测指标(试行)
- 新形势下修刮或剖皮机行业顺势崛起战略制定与实施分析报告
- 柴油打桩锤行业市场营销创新战略制定与实施分析报告
- 2023-2028年中国婚恋交友服务行业开拓第二增长曲线战略制定与实施分析研究报告
- 2026年跨境电商海外仓仓储合同协议
- 2026年安全生产月活动启动部署和主题宣贯课件附讲义教案和案例
- 2026年公务员遴选笔试真题及答案
- 2025年中国铁路兰州局集团有限公司招聘高校毕业生考试真题
- 新里程大学英语听说教程谭思坦课后部分参考答案
- ISO-37301-2021-合规管理体系要求及使用指南(中文版)
- 公文写作-常用公文写作规范与技巧课件
- 小学科学教育科学五年级上册运动和力 五上《测量力的大小》张杨
- 电子版-铁路货物运价规则
- 生产经营单位生产安全事故应急预案编制导则课件
- T∕CFA 020101021-2021 预应力铸铁锚垫板通用技术规范
- 《企业会计准则第31号——现金流量表》应用指南
评论
0/150
提交评论