线性表顺序表算法设计_第1页
线性表顺序表算法设计_第2页
线性表顺序表算法设计_第3页
线性表顺序表算法设计_第4页
线性表顺序表算法设计_第5页
已阅读5页,还剩45页未读 继续免费阅读

下载本文档

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

文档简介

2.2.3顺序表算法设计顺序表算法设计:数据采用顺序表存储,利用顺序表的根本操作来完成求解任务。1/16【例2-3】长度为n的线性表A采用顺序存储结构。设计一个时间复杂度为O(n)、空间复杂度为O(1)的算法,该算法删除线性表中所有值为x的数据元素。如果每删除一个值为x的元素都进行移动,其时间复杂度为O(n2),空间复杂度为O(1)。如果借助一个新的顺序表,存放将A中所有不为x的元素,其时间复杂度为O(n),空间复杂度为O(n)。以下两种方法都不满足要求:2/16解法一〔重建法〕:设删除A中所有值等于x元素后的顺序表为A1,显然A1包含在A中,为此A1重用A的空间。思路:扫描顺序表A,重建A只包含不等于x的元素。3/16011222删除所有x=2的元素〔k记录保存的元素个数,初值=0〕:2345k=3,L->length=k=31删除顺序表中所有值为x的元素〔方法1〕演示length63删除完成3k=0k=1k=2k=34/16对应的算法如下:voiddelnode1(SqList*&A,ElemTypex){intk=0,i; //k记录值不等于x的元素个数for(i=0;i<A->length;i++)if(A->data[i]!=x)//假设当前元素不为x,将其插入A中{A->data[k]=A->data[i]; k++; //不等于x的元素增1}A->length=k; //顺序表A的长度等于k}算法1:类似于建顺序表5/16解法二〔前移法〕:用k记录顺序表A中等于x的元素个数,一边扫描A一边统计k值。思路:将不为x的元素前移k个位置,最后修改A的长度。6/160112232删除所有x=2的元素〔k记录删除的元素个数,初值=0〕2345k=0,前移0个位置1k=1k=1,前移1个位置k=2k=2,前移2个位置k=3顺序表长度=6-k=3删除顺序表中所有值为x的元素〔方法2〕演示length63删除完成7/16对应的算法如下:voiddelnode2(SqList*&A,ElemTypex){intk=0,i=0;

//k记录值等于x的元素个数

while(i<A->length)

{if(A->data[i]==x)//当前元素值为x时k增1 k++;

else

//当前元素不为x时将其前移k个位置

A->data[i-k]=A->data[i];

i++;

}

A->length-=k; //顺序表A的长度递减k}8/16思考题

为什么说上述两个算法都能够满足题目的要求?9/16【例2-4】设顺序表L有10个整数。设计一个算法,以第一个元素为分界线〔基准〕,将所有小于等于它的元素移到该元素的前面,将所有大于它的元素移到该元素的后面。x无序整数序列≤xx>x10/160812273145536476809pivotijpivot=L->data[0]〔基准〕j从后向前找≤pivot的元素i从前向后找>pivot的元素3两者交换31

0

2

3

3

5

7

4

6

8解法1〔前后交换法〕:11/16voidmove1(SqList*&L){inti=0,j=L->length-1;ElemTypetmp;ElemTypepivot=L->data[0]; //以data[0]为基准while(i<j)

{ while(i<j&&L->data[j]>pivot)

j--;

//从后向前扫描,找一个≤pivot的元素

while(i<j&&L->data[i]<=pivot)

i++;

//从前向后扫描,找一个>pivot的元素

if(i<j) {tmp=L->data[i]; //L->data[i]

L->data[j]

L->data[i]=L->data[j];

L->data[j]=tmp; }

}

tmp=L->data[0];

//L->data[0]

L->data[j]

L->data[0]=L->data[j];L->data[j]=tmp;}12/1630812273145536476809pivot〔基准〕ijpivot=L->data[0]〔基准〕j从后向前找小于等于pivot的元素:前移i从前向后找大于pivot的元素:后移0

3

2

1

3

5

7

4

6

8解法2〔前后交换法〕:算法时间复杂度为O(n)。13/16voidmove2(SqList*&L){

inti=0,j=L->length-1;

ElemTypepivot=L->data[0]; //以data[0]为基准

while(i<j)

{while(j>i&&L->data[j]>pivot)

j--; //从右向左扫描,找≤pivot的data[j]

L->data[i]=L->data[j]; //将其放入data[i]处while(i<j&&L->data[i]<=pivot)

i++; //从左向右扫描,找>pivot的记录data[i]

L->data[j]=L->data[i]; //将其放入data[j]处}

L->data[i]=pivot; //放置基准}14/16两个记录a、b交换:tmp=a;a=b;b=tmp;需要3次移动多个相邻记录连续交换,如a、b、c:

位置1和位置2的元素交换

b、a、c需要3次移动

位置2和位置3的元素交换

b、c、a需要3次移动

为什么解法2比解法1更好?而采用:tmp=a;a=b;b=c;c=tmp;4次移动性能得到提高。共6次移动15/16线性表中每个结点有唯一的前驱结点和前驱结点。2.3.1

线性表的链式存储—链表设计链式存储结构时,每个逻辑结点存储单独存储,为了表示逻辑关系,增加指针域。

每个物理结点增加一个指向后继结点的指针域

单链表。每个物理结点增加一个指向后继结点的指针域和一个指向前驱结点的指针域

双链表。2.3

线性表的链式存储结构16/35线性表(a1,a2,…,ai,…an)映射逻辑结构存储结构a1a2an∧…L带头结点单链表示意图17/35a1a2an∧…第一个结点的操作和表中其他结点的操作相一致,无需进行特殊处理;无论链表是否为空,都有一个头结点,因此空表和非空表的处理也就统一了。单链表增加一个头结点的优点如下:带头结点单链表18/35

存储密度是指结点数据本身所占的存储量和整个结点结构中所占的存储量之比,即:一般地,存储密度越大,存储空间的利用率就越高。显然,顺序表的存储密度为1〔100%〕,而链表的存储密度小于1。存储密度=结点数据本身占用的空间结点占用的空间总量a18个字节4个字节存储密度=8/12=67%例如19/35思考题:

线性表的顺序存储结构和链式存储结构的差异?20/352.3.2

单链表单链表中结点类型LinkNode的定义如下:

typedefstructLNode

//定义单链表结点类型{ElemTypedata;

structLNode*next;

//指向后继结点}LinkNode;a21/35当访问过一个结点后,只能接着访问它的后继结点,而无法访问它的前驱结点。单链表的特点ab…p…22/35插入操作:将值为x的新结点*s插入到*p结点之后。1、插入结点和删除结点操作特点:只需修改相关结点的指针域,不需要移动结点。〔1〕插入结点23/35abx…p…s

s->next=p->next

p->next=s插入操作语句描述如下:

s->next=p->next;

p->next=s;单链表插入结点演示24/35删除操作:删除*p结点之后的一个结点。特点:只需修改相关结点的指针域,不需要移动结点。〔2〕删除结点25/35abx…p…p->next=p->next->next删除操作语句描述如下:

p->next=p->next->next;单链表删除结点演示26/35先考虑如何整体建立单链表。

2、建立单链表a[0..n-1]带头结点的单链表L整体创立建立单链表的常用方法有两种。27/35从一个空表开始,创立一个头结点。依次读取字符数组a中的元素,生成新结点将新结点插入到当前链表的表头上,直到结束为止。Lai-1a1…ais〔1〕头插法建表注意:链表的结点顺序与逻辑次序相反。28/35voidCreateListF(LinkNode*&L,ElemTypea[],intn){LinkNode*s;inti;L=(LinkNode*)malloc(sizeof(LinkNode));L->next=NULL; //创立头结点,其next域置为NULL头插法建表算法如下:∧L29/35for(i=0;i<n;i++) //循环建立数据结点{ s=(LinkNode*)malloc(sizeof(LinkNode)); s->data=a[i]; //创立数据结点*s s->next=L->next; //将*s插在原开始结点之前,头结点之后 L->next=s;}}Lai-1a1…aiss->next=L->next;L->next=s;30/35La1aj…aisr〔2〕尾插法建表注意:链表的结点顺序与逻辑次序相同。从一个空表开始,创立一个头结点。依次读取字符数组a中的元素,生成新结点将新结点插入到当前链表的表尾上,直到结束为止。增加一个尾指针r,使其始终指向当前链表的尾结点31/35voidCreateListR(LinkNode*&L,ElemTypea[],intn){LinkNode*s,*r;inti;L=(LinkNode*)malloc(sizeof(LinkNode));//创立头结点r=L; //r始终指向尾结点,开始时指向头结点尾插法建表算法如下:∧Lr32/35for(i=0;i<n;i++) //循环建立数据结点{ s=(LinkNode*)malloc(sizeof(LinkNode)); s->data=a[i]; //创立数据结点*s r->next=s; //将*s插入*r之后 r=s;}r->next=NULL; //尾结点next域置为NULL}rLa1ai-1…aisr->next=s33/353、线性表根本运算在单链表上的实现〔1〕初始化线性表InitList(L)该运算建立一个空的单链表,即创立一个头结点。voidInitList(LinkNode*&L){L=(LinkNode*)malloc(sizeof(LinkNode));//创立头结点L->next=NULL;}∧L34/35〔2〕销毁线性表DestroyList(L)释放单链表L占用的内存空间。即逐一释放全部结点的空间。voidDestroyList(LinkNode*&L){

LinkNode*pre=L,*p=L->next;

//pre指向*p的前驱结点

初始时L∧…prep35/35while(p!=NULL) //扫描单链表L

{free(pre); //释放*pre结点

pre=p; //pre、p同步后移一个结点

p=pre->next;

}

free(pre);

//循环结束时,p为NULL,pre指向尾结点,释放它}循环结束时L∧prep=NULL…36/35〔3〕判线性表是否为空表ListEmpty(L)假设单链表L没有数据结点,那么返回真,否那么返回假。boolListEmpty(LinkNode*L){

return(L->next==NULL);}∧L空表的情况37/35〔4〕求线性表的长度ListLength(L)返回单链表L中数据结点的个数。intListLength(LinkNode*L){intn=0;LinkNode*p=L; //p指向头结点,n置为0〔即头结点的序号为0〕

初始时L∧…pn=038/35while(p->next!=NULL)

{ n++; p=p->next;

}

return(n); //循环结束,p指向尾结点,其序号n为结点个数}循环结束时L∧pn为结点个数…39/35〔5〕输出线性表DispList(L)逐一扫描单链表L的每个数据结点,并显示各结点的data域值。voidDispList(LinkNode*L){LinkNode*p=L->next; //p指向开始结点

while(p!=NULL)

//p不为NULL,输出*p结点的data域

{ printf("%d",p->data); p=p->next; //p移向下一个结点

}

printf("\n");}L∧p…40/35〔6〕求线性表L中位置i的数据元素GetElem(L,i,&e)思路:在单链表L中从头开始找到第i个结点,假设存在第i个数据结点,那么将其data域值赋给变量e。41/35boolGetElem(LinkNode*L,inti,ElemType&e){intj=0;LinkNode*p=L; //p指向头结点,j置为0〔即头结点的序号为0〕while(j<i&&p!=NULL){ j++; p=p->next;}找第i个结点*p循环结束时Lean∧…i…p42/35if(p==NULL) //不存在第i个数据结点,返回false

returnfalse;

else

//存在第i个数据结点,返回true

{e=p->data;

returntrue;

}}Lean∧…i…p43/35〔7〕按元素值查找LocateElem(L,e)思路:在单链表L中从头开始找第1个值域与e相等的结点,假设存在这样的结点,那么返回位置,否那么返回0。intLocateElem(LinkNode*L,ElemTypee){

inti=1;

LinkNode*p=L->next; //p指向开始结点,i置为1

while(p!=NULL&&p->data!=e)

{p=p->next; //查找data值为e的结点,其序号为ii++;

}

循环结束时Le∧…i…p44/35Le∧…i…if(p==NULL) //不存在元素值为e的结点,返回0return(0);

else

//存在元素值为e的结点,返回其逻辑序号i

return(i);}算法的时间复杂度为O(n)

不具有随机存取特性45/35〔8〕插入数据元素ListInsert(&L,i,e)思路:先在单链表L中找到第i-1个结点*p,假设存在这样的结点,将值为e的结点*s插入到其后。boolListInsert(LinkNode*&L,inti,ElemTypee){

intj=0;

LinkNode*p=L,*s; //p指向头结点,j置为0

while(j<i-1&&p!=NULL)

{ j++; p=p->next;

}查找第

温馨提示

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

最新文档

评论

0/150

提交评论