第3章数据结构- 线性表_第1页
第3章数据结构- 线性表_第2页
第3章数据结构- 线性表_第3页
第3章数据结构- 线性表_第4页
第3章数据结构- 线性表_第5页
已阅读5页,还剩74页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第三章线性表DS应用实践

线性表的概念

双向链表

循环链表

线性表的顺序存储

单向链表

线性结构特点在数据元素的非空有限集中存在唯一的一个被称作“第一个”的数据元素存在唯一的一个被称作“最后一个”的数据元素除第一个外,集合中的每个数据元素均只有一个前驱除最后一个外,集合中的每个数据元素均只有一个后继3.1线性表的概念例英文字母表(A,B,C,…..Z)是一个线性表定义:一个线性表是n个数据元素的有限序列3.1.1线性表的定义3.1线性表的概念特征:元素个数n—表长度,n=0空表1<i<n时ai的直接前驱是ai-1,a1无直接前驱ai的直接后继是ai+1,an无直接后继元素同构,且不能出现缺项3.1.1线性表的定义3.1.2线性表的抽象数据类型描述ADTList{

数据对象:D={ai|ai∈ElemType,i=1,2,...,n,n≥0}

数据关系:R={<ai-1,ai>|ai-1,ai∈D,i=2,...,n}基本操作:(详见下页)}ADTList

基本操作InitList(SqList

*L)//线性表的初始化,即构造一个空的线性表LDestroyList(SqList&L)//释放线性表L占用的内存空间ListEmpty(SqListL)//判断线性表L是否为空表ListLength(SqListL)//求线性表的长度,返回L中元素个数GetElem(SqListL,inti,DataType

*e)//求线性表L中第i(1≤i≤n)个元素的值

基本操作LocateElem(SqListL,

DataType

e)//返回L中第1个与e满足关系的数据元素位序ListTraverse(SqList

L)//依次对线性表L的每个元素进行遍历ClearList(SqList

*L)//将线性表L重置为空表PutElem(SqList

L,inti,DataType

*e)//给线性表L中第i个元素赋值ListInsert(SqList

*L,inti,DataType

e)//在线性表L的第i个元素之前插入新的元素eListDelete(SqList

*L,inti,DataType

*e)//删除L的第i个元素,并用e返回其值,L的长度减1

基本操作CreateListHead(SqList

*L,intn)//用头插法建立带表头结点的单链线性表LCreateListTail(SqList

*L,intn)//用尾插法建立带表头结点的单链线性表L定义:用一组地址连续的存储单元存放一个线性表叫~元素地址计算方法LOC(ai+1)=LOC(ai)+d

LOC(ai)=LOC(a1)+(i-1)*dd—一个元素占用的存储单元个数LOC(ai)—线性表第i个元素的地址3.2线性表的顺序存储特点:

实现逻辑上相邻—物理地址相邻实现随机存取实现:可用C语言的一维数组实现在C语言中,线性表的顺序存储的类型定义如下:typedef

int

DataType;//DataType类型根据实际情况而定,这里假设为int#defineMAXSIZE100//MAXSIZE可根据实际情况而定typedef

struct{

DataType

data[MAXSIZE];

intlength;}SqList;图3.1线性表的顺序存储结构

a1a2an01n-112n内存V数组下标元素序号M-1typedef

int

DataType;#defineMAXSIZE100例typedef

struct{

DataType

data[MAXSIZE]

intlength;}SqList;备用空间数据元素不是简单类型时,可定义结构体数组3.2.2顺序表的基本运算1.线性表的初始化int

InitList(SqList*L){

L.length=0;//空表,长度为0

returnOK;}3.2.2顺序表的基本运算2.释放线性表voidDestroyList(SqList&L){

if(L->data)

free(L->data);//释放线性表占据的所有存储空间}3.2.2顺序表的基本运算3.判断线性表是否为空表int

ListEmpty(SqListL){

if(L.length==0)

returnTRUE;

if(L.length!=0)

returnFALSE;}3.2.2顺序表的基本运算4.求线性表的长度int

ListLength(SqListL){

return(L.length);}3.2.2顺序表的基本运算5.求线性表中第i个元素的值int

GetElem(SqList

L,int

i,DataType*e){

if(i<1||i>L.length)

returnERROR;//判断i值是否合理,若不合理,返回ERROR

*e=L.data[i-1];//数组中第i-1的单元存储着线性表中第i个数据元素的内容

returnOK;}3.2.2顺序表的基本运算6.返回线性表中第1个与e满足关系的数据元素位序int

LocateElem(SqListL,DataTypee){

int

i;

for

(i=1;

i<=L.length;

++i)

{

if

(e

==

L.data[i-1])

return

i;

}

return

FALSE

}

3.2.2顺序表的基本运算7.遍历线性表void

ListTraverse(SqList

L)

{

int

i;

for

(i=i;

i<=L.length;

++i)

printf("%d

",

L.data[i-1]);

}

3.2.2顺序表的基本运算8.清空线性表voidClearList(SqList*L){

L->length=0;//将线性表的长度置为0}3.2.2顺序表的基本运算9.给线性表中第i个元素赋值int

PutElem(SqList

L,int

i,DataType*e){

if(i<1||i>L.length)

returnERROR;//判断i值是否合理,若不合理,返回ERROR

L.data[i-1]=*e;//数组中第i-1的单元存储着线性表中第i个数据元素的内容

returnOK;}定义:线性表的插入是指在第i(1in+1)个元素之前插入一个新的数据元素x,使长度为n的线性表变成长度为n+1的线性表

需将第i至第n共(n-i+1)个元素后移3.2.2顺序表的基本运算10.插入数据元素ai-1和ai

的逻辑关系发生了变化。在线性表的顺序存储结构中,由于逻辑上相邻的数据元素在物理上也是相邻的,因此,除非i=n+1,否则必须移动元素才能反映这个逻辑关系的变化。图3.2

线性表插入前后的状况内存a1a2aiai+1an01i-1V数组下标n-1in12i元素序号i+1nn+1内存a1a2aiai+1an01i-1V数组下标n-1in12i元素序号i+1nn+1an-1xint

ListInsert(SqList*L,int

i,DataTypee){

intk;

if(L->length==MAXSIZE)returnERROR;

if(i<1||i>L->length+1)returnERROR;

if(i<=L->length)

{for(k=L->length-1;k>=i-1;k--)

L->data[k+1]=L->data[k];

}

L->data[i-1]=e;

L->length++;

returnOK;

}算法时间复杂度T(n)设Pi是在第i个元素之前插入一个元素的概率,则在长度为n的线性表中插入一个元素时,所需移动的元素次数的平均次数为:11.线性表中数据元素的删除

变成长度为n-1的线性表

需将第i+1至第n共(n-i)个元素前移定义:线性表的删除是指将第i(1in)个元素删除,使长度为n的线性表

图3.3线性表删除前后的状况内存a1a2aiai+1an01i-1V数组下标n-1in12i元素序号i+1nn+1内存a1a2ai+1V数组下标01i-1n-2in-112i元素序号i+1n-1nanai+2int

ListDelete(SqList*L,int

i,DataType*e){

intk;if(L->length==0)returnERROR;if(i<1||i>L->length)returnERROR;*e=L->data[i-1];if(i<L->length){

for(k=i;k<L->length;k++) L->data[k-1]=L->data[k];}L->length--;returnOK;}设Qi是删除第i个元素的概率,则在长度为n的线性表中删除一个元素所需移动的元素次数的平均次数为:故在顺序表中插入或删除一个元素时,平均移动表的一半元素,当n很大时,效率很低算法评价顺序存储结构的优缺点优点逻辑相邻,物理相邻可随机存取任一元素存储空间使用紧凑缺点插入、删除操作需要移动大量的元素预先分配空间需按最大空间分配,利用不充分表容量难以扩充练习:1.实现在顺序表中按值插入元素。2.给定一个顺序表L=(a1,a2,a3,...,an),请设计一个算法删除所有值大于min而且小于max的元素。实现在顺序表中按值插入元素int

ListInsert(SqList*L,DataTypee){

intk; if(L->length==MAXSIZE)returnERROR;

for(k=L->length;k>=1;k--) {if(L->data[k-1]>e) {L->data[k]=L->data[k-1]; } else {break;} } L->data[k]=e; L->length++; returnOK;}给定一个顺序表L=(a1,a2,a3,...,an),请设计一个算法删除所有值大于min而且小于max的元素int

ListDelete(SqList*L,int

min,intmax){

int

k,i;if(L->length==0)returnERROR;

for(k=1;k<=L->length;k++) {if(L->data[k-1]>min&&L->data[k-1]<max) {for(i=k;i<L->length;i++) {L->data[i-1]=L->data[i];} L->length--; k--; }}returnOK;}3.3单向链表顺序表的存储特点是用物理上的相邻来实现逻辑上的相邻,它要求用连续的存储单元顺序存储线性表中各元素,因此,对顺序表插入、删除时需要通过移动数据元素来实现,影响了运行效率。线性链表不需要用地址连续的存储单元来实现,而是通过“链”建立起数据元素之间的逻辑结构。

3.3单向链表特点:用一组任意的存储单元存储线性表的数据元素利用指针实现了用不相邻的存储单元存放逻辑上相邻的元素每个数据元素ai,除存储本身信息外,还需存储其直接后继的信息。这两部分信息组成数据元素的存储映像,称为结点。由于上述链表的每个结一个点只有一个指示其直接相继的信息,故将这种链表称为单向链表,简称为单链表。结点

数据域:元素本身信息指针域:指示直接后继的存储位置数据域指针域结点n个结点(ai(1≤i≤n)的存储映像)链结成一个链表,即为线性表

(a1,a2,….,an)的链式存储结构。整个链表的存取必须从头指针开始进行,头指针指示链表中第一个结点(即第一个数据元素的存储映像)的存储位置。同时,由于最后一个数据元素没有直接后继,则线性链表中最后一个结点的指针为空(NULL)。

L为单链表的头指针,它指向表中第一个结点。若L为空(NULL),则所表示的线性表为“空”表,其长度n为“零”。在单链表的第一个结点之前附设一个结点,称之为“头结点”。头结点的数据域可以不存储任何信息,指针域存储指向第一个结点的指针(即第一个元素结点的存储位置)。单链表的头指针指向头结点。若线性表为空表,则头结点的指针域为“空”。

(a)非空表

(b)空表图3.4

带头指针的单链表用C语言定义的单链表结构如下:typedef

structNode{

DataTypedata;

structNode*next;}Node;typedef

structNode*LinkList;

ZHAOQIANSUNLIZHOUWUZHENGWANG^H例线性表(ZHAO,QIAN,SUN,LI,ZHOU,WU,ZHENG,WANG)43131NULL3771925数据域指针域LIQIANSUNWANGWUZHAOZHENGZHOU存储地址1713192531374331H头指针(1)InitList(LinkList*L)//初始化单链表(2)ListEmpty(LinkList

L)//判断单链表是否为空(3)ClearList(LinkList*L)//单链表的置空(4)CreateListTail(LinkList*L,int

n)//从尾创建添加结点(5)CreateListHead(LinkList*L,int

n)//从头创建添加结点(6)ListLength(LinkList

L)//获取链表结点数量(表长)(7)GetElem(LinkList

L,int

i,DataType*e)//获取指定位置结点(8)LocateElem(LinkList

L,DataType

e)//获取指定数据元素的位序(9)ListInsert(LinkList*L,int

i,DataType

e)//插入指定位置的数据元素(10)ListDelete(LinkList*L,int

i,DataType*e)//删除指定位置的数据元素(11)ListTraverse(LinkList

L)//单链表的遍历3.3.3单向链表的基本操作(1)初始化单向链表int

InitList(LinkList&L){L=(LinkList)malloc(sizeof(Node));

if(!L)returnERROR;L->next=NULL;returnOK;}算法3.3初始化单链表(2)判断是否为空若L为空表,则返回TRUE,否则返回FALSE。int

ListEmpty(LinkListL){

if(L->next)returnFALSE;elsereturnTRUE;}算法3.4判断单链表是否为空(3)置空int

ClearList(LinkList&L){LinkList

p,q; p=L->next;//p指向第一个结点

while(p)//没到表尾

{ q=p->next;

free(p); p=q; } L->next=NULL; returnOK;}算法3.5单链表的置空(4)求表长int

ListLength(LinkListL){

inti=0;

LinkListp=L->next;

while(p){i++;p=p->next;}returni;}算法3.6单链表的表长(5)取值intGetElem(LinkListL,inti,DataType*e){intj;

LinkListp; p=L->next; j=1; while(p&&j<i)

{p=p->next;++j;} if(!p||j>i)returnERROR; *e=p->data; returnOK;}(6)求位序(查找)int

LocateElem(LinkList

L,DataTypee){inti=0;

LinkListp=L->next;

while(p){i++;

if(p->data==e)//找到这样的数据元素

returni;p=p->next;}return0;}算法3.8单链表某元素的位序算法评价?pabes在线性表两个数据元素a和b间插入e,已知p指向as->next=p->next;p->next=s;算法评价(7)单链表的插入(7)单链表的插入int

ListInsert(LinkList&L,int

i,DataTypee){ intj;

LinkList

p,s; p=L; j=1; while(p&&j<i)//寻找第i个结点

{ p=p->next; ++j; } if(!p||j>i)returnERROR;

(7)单链表的插入 s=(LinkList)malloc(sizeof(Node));//生成新结点

s->data=e; s->next=p->next; p->next=s; returnOK;}pabc算法评价单链表中删除b,设p指向ap->next=p->next->next;(8)单链表的删除q=p->next;p->next=q->next;q(8)单链表的删除int

ListDelete(LinkList&L,int

i,DataType*e){

intj;

LinkList

p,q; p=L; j=1; while(p->next&&j<i) {p=p->next;++j; } if(!(p->next)||j>i)returnERROR;

(8)单链表的删除 q=p->next; p->next=q->next; *e=q->data;//将q结点中的数据给e

free(q);//系统回收此结点,释放内存

returnOK;}(9)单链表的遍历int

ListTraverse(LinkListL){intcount=0;

LinkListp=L->next;

while(p){

printf("%d",p->data);p=p->next;count++;}

printf("\n");return(count);}(10)头插法随机产生n个元素的值,建立带表头结点的单链线性表L(头插法)。voidCreateListHead(LinkList&L,intn){

LinkListp;

inti; srand(time(0));//初始化随机数种子

L=(LinkList)malloc(sizeof(Node)); L->next=NULL;

(10)头插法

for(i=0;i<n;i++) { p=(LinkList)malloc(sizeof(Node)); p->data=rand()%100+1;//随机生成100以内的数字*

p->next=L->next; L->next=p; }}(11)尾插法

随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法)。voidCreateListTail(LinkList&L,intn){

LinkList

p,r;

inti; srand(time(0)); L=(LinkList)malloc(sizeof(Node)); r=L;

(11)尾插法 for(i=0;i<n;i++) { p=(Node*)malloc(sizeof(Node)); p->data=rand()%100+1; r->next=p; r=p; } r->next=NULL;}它是一种动态结构不需预先分配空间指针占用额外存储空间不能随机存取,查找速度慢单链表特点1.在下面链表中按顺序插入结点q,写出核心程序段1628H4360^52q设计算法2.将单链表中所有重复的结点删除,只保留第一个3.将两个有序单链表合并成一个有序单链表,合并后p1为结果链表,p2为空。2009年研究生考试真题(15分)已知一个带有表头结点的单链表,结点结构为假设该链表只给出了头指针list。在不改变链表的前提下,请设计一个尽可能高效的算法,查找链表中倒数第k个位置上的结点(k为正整数)。若查找成功,算法输出该结点的data域的值,并返回1;否则,只返回0。要求:(1)描述算法的基本设计思想(2)描述算法的详细实现步骤(3)根据设计思想和实现步骤,采用程序设计语言描述算法(使用C或C++或JAVA语言实现),关键之处请给出简要注释datalink(1)基本思想:从头至尾遍历单链表,并用指针p指向当前结点的前k个结点,当遍历到链表的最后一个结点时,指针p所指向的结点即为所查找的结点(2)详细步骤:增加两个指针变量和一个整形变量,从链表头向后遍历,其中指针p1指向当前遍历的结点,指针p指向p1所指结点的前k个结点,如果p1之前没有k个结点,那么p指向表头结点。用整型变量i表示当前遍历了多少个结点,当i>k时,指针p随着每次的遍历,也向前移动一个结点。当遍历完成时,p或者指向表头结点,或者指向链表中倒数第k的位置上的结点(3)int

LocateElement(Linklist

list,intk){p1=list->link;p=list;i=1;while(p1){p1=p1->link;i++;

if(i>k)p=p->link;}

if(p==list)return0;else{printf(“%d\n”,p->data);return1;}}3.4循环链表循环链表是另一种形式的链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环,从表中任何一结点出发均可找到表中其他结点。

(a)非空表(b)空表图3.5单循环链表循环链表的操作和线性链表基本一致,差别仅在于算法中的循环条件不是p或p->next是否为空,而是在于它们是否等于头指针。3.5双向链表(doublelinkedlist)对单链表进行改进的另一种方法是构成双向链表。双向链表中每个结点除了有向后的指针(next)外,还有一个指向前一个结点的指针(prior),这样形成的链表中有两条不同方向的链,因此,从某一个结点均可向两个方向访问。这样构成的链表有两个方向不同的链,简称为双向链表。3.5双向链表(doublelinkedlist)图3.7双向循环链表结点结构其中链域prior和next分别指向本结点的直接前趋结点和直接后继结点。数据域指针域指针域结点存储数据元素data存储后继结点的地址next存储前趋结点的地址prior如果循环链表的结点再采用双向指针,就成为双向循环链表也成为双链表。图3.8是一个具有空表头结点的双向循环链表,其表尾结点的向右指针指向空表头结点,空表头结点的向左指针指向表尾结点。

图3.8双向循环链表

L空双向循环链表:双链表较单链表虽然要多占用一些存储单元,但对其插入和删除操作以及查找结点的前趋和后继都非常方便。在链表较长,插入、删除较频繁或需要经常查找结点的前趋和后继的情况下使用双链表比较合适。双链表结构是一种对称结构,设指针p指向双链表的某一结点,则双链表的对称性可用下式来表示:

p=(p->next)->prior=(p->prior)->next亦即结点*p的地址既存放在其前趋结点*(p->prior)的后继指针域中,又存放在它的后继结点*(p->next)的前趋指针域中。3.5.2双向链表的基本操作与单链表相比较,双向链表只是增加了直接前继的指针域,故其存储结构可表示为:typedef

struct

DuLNode{DataTypedata;struct

DuLNode*prior;

struct

DuLNode*next;}DuLNode,*DuLink;在双向链表上进行操作基本上和单向链表相同,例如,查找结点也是要从头指针指示的头结点开始,但插入和删除时必须同时修改两个方向上的指针。(1)双向链表的插入在带头结点的双向链表L中结

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论