软件技术基础Word文件下载.docx
《软件技术基础Word文件下载.docx》由会员分享,可在线阅读,更多相关《软件技术基础Word文件下载.docx(64页珍藏版)》请在冰豆网上搜索。
(2)适宜采用什么样的存储结构?
(3)有哪些基本运算?
如何实现?
数据结构的3个层次如下:
数据的逻辑结构、数据的存储结构和数据操作相关算法集合。
【例11-1】职工档案表如表11-1所示。
表11-1职工档案表
这张档案表可称为一个数据结构,它是一个线性表结构,表中的每一行为一个数据元素(它是数据结构的基本单位),它由“姓名”、“性别”和“奖惩”等字段组成。
①表中数据元素的逻辑关系如下:
对表中任一元素,与它相邻且在它前面的数据元素(也称为直接前趋)最多只有一个;
与表中任一数据元素相邻且在它后面的数据元素(也称直接后继)最多也只有一个。
表中的第一个元素没有直接前趋,故称为开始数据元素,最后一个数据元素没有直接后继,故称为终点元素(例如:
表中“表静”)所在元素的直接前趋为“胡一民”所在的数据元素;
直接后趋为“张冬梅”所在的数据元素)。
②该表的存储方式(指计算机存储器如何表示这种关系):
表中的数据元素是顺序地邻接在一片连续的单元之中,而不是用指针将这些元素链接在一起。
③对表元素怎样进行查找、删除和插入等操作方能提高数据操作效率。
通常,算法的设计取决于数据的逻辑结构,算法的实现取决于数据的物理存储结构。
11.1.3 逻辑结构和物理结构
1.逻辑结构
数据是指由有限的符号(比如,“0”和“1”,具有其自己的结构、操作和相应的语句)组成的元素的集合。
结构是元素之间的关系的集合。
通常来说,一个数据结构DS可以表示为一个二元组。
DS=(D,S),
这里D是数据元素的集合(或者是“结点”,可能含有“数据项”或“数据域”),S是定义在D(或其他集合)上的关系的集合,S={R|R:
D×
…},称为元素的逻辑结构。
数据元素逻辑关系(逻辑结构)分为两大类。
(1)线性结构。
其逻辑特征如下:
有且仅有一个开始元素和一个终点元素,所有数据元素最多只有一个直接前趋和一个直接后继,线性表就是一个典型的线性结构。
(2)非线性结构。
该结构中一个数据元素可能有多个直接前趋或直接后继。
①图结构。
数据元素的直接前趋和直接后继的个数不作限制。
②树结构。
有且仅有一个根元素无直接前趋,其他元素有且仅有一个直接前趋;
每个元素都可能有多个直接后继;
除根元素外,所有数据元素都存在一条从根元素到该元素的路径。
2.数据的物理结构
数据的物理结构(存储结构)是指逻辑结构的存储镜像(image)。
数据结构DS的物理结构P对应于从DS的数据元素到存储区M(维护着逻辑结构S)的一个映射:
P:
(D,S)-M
数据元素在计算机中的存储方法(即数据的存储结构,也称物理结构),分为4类。
(1)顺序存储方法。
把逻辑上相邻的数据元素存储在物理位置上相邻的存储单元里,元素间的逻辑关系由存储单元的邻接关系体现,其存储表示称为顺序存储结构、顺序存储方法主应用于线线的数据结构,如线性表和数组等,但非线性数据结构也可以通过某种线性化方法来实现顺序存储。
(2)链接存储方法。
并不要求逻辑上相邻的元素在物理位置上也相邻,元素的逻辑关系是由附加的指针字段表示,它要借助于程序语言的指针类型描述元素的存储地址,每个数据元素所占存储单元分成两部分:
元素数据项和指针项(指出其后继或前趋元素的存储地址,从而形成一个链)。
(3)索引存储方法。
在存储元素信息的同时,还建立附加的索引表。
索引表的每一项称为索引项,索引项的一般形式如下:
关键字,地址
其中,关键字是能唯一标识一个元素的数据项,而地址则指示存储位置。
(4)散列存储方法(地址转移法)。
根据元素的关键字,通过某一散列函数直接计算出该元素的存储地址。
3.二者的关系
同一种逻辑结构采用不同的存储方法,可得到不同的存储结构,采用何种存储方法来表示相应的逻辑结构,主要是根据算法来具体确定。
例如,线性表是一种逻辑结构,采用顺序方法的存储方法,该结构为顺序表;
若采用链接方法的存储表示,该结构为链表:
若采用散列方法
11.2线性结构
线性结构是数据结构中最简单且最常用的一种数据结构·
其基本特点是鳌鱼亘鲜,良多刻易线性结构的数据元素可排成一个线性队列:
a1,a2,a3,a4,…,an
其中,a1为起始元素an为终点元素。
线性结构有各种类型,如线性表、姆和队列等。
11.2.1线性表
在线性表中,除首元素外,每个元素有且仅有一个直接前驱;
除尾元素外,每个元素有且仅有一个直接后继。
1.线性表的逻辑结构
(1)概念。
线性表。
线性表是由n(n≥0)个数据元素(a1,a2,…,an)构成的有限序列。
记作:
L=((a1,a2,…,an)
其中,a1为首元素,an为尾元素,表的长度(表长)为线性表中数据元素的数目。
空表。
不含任何数据元素的线性表称为空表。
【例11-2】线性表举例。
①字母表。
L1=(A,B,C…,Z)
表长为26。
②姓名表。
L2=(李明,陈小平,王林,周爱玲)
表长为4。
(2)线性表的特征。
对于L=(a1,a2,…,ai,ai-+1,…,an)有如下特征。
①ai-1在ai之前,称ai-1是ai的直接前驱,其中1<
i<
n,。
②ai-+1在ai之后,称ai-+1是ai的直接后继,其中l<
n。
③a1没有前驱。
④an没有后继。
⑤ai(1<
n)有且仅有一个直接前驱和一个直接后继。
(3)线性表的主要基本操作有以下几种。
①INITIATE(L)。
初始化,设定一个空的线性表L,
②LENGTH(L)。
求表长,返回线性表电教抿元素的个数。
③GET(L,i)。
取元素礴回线性表中第i个数据元素。
④LOCATE(L,x)。
定位,返回值等于х的数据元素在线性表中的序号,若不存在这样的元素,则返回0。
2.线性表的物理结构
(1)顺序表(顺序存储结构)。
当线性表采用顺庄存储结构时,称之为顺序表,即将线性表中的数据元素依次放到计算机存储器中一组地址连续的存储单元中,这种分配方式称为顺序分配或顺序映像。
由此得到的存储结构称为顺序存储结构或向量(一维数组)。
在顺序表中,数据元素按逻辑次序依次放在一组地址连续的存储单元里。
由于逻辑上相邻的元素存放在内存相邻的相邻单元里,所以顺序表的逻辑关系蕴含在存储单元的邻接关系中。
设顺序表中的每个元素占用k个存储单元,索引号为1的数据元素a1的内存地址为LOC(a1),则索引号为i的数据元素ai的内存地址为
LOC(ai)=LOC(a1)+(i一1)k
显然,顺序表中每个元素的存储地址是该元素在表中索引号的线性函数。
只要知道某元素在顺序表中的索引号,就可以确定其在内存中的存储位置。
顺序表的特点如下:
①物理上相邻的元素在逻辑上也相邻;
②可随机存取;
③存储密度大,空间利用率高;
对顺序表可进行插入、删除等操作,但运算效率低,需要大量的数据元素移位。
【例11-3】在如图11-1所示的顺序表中,在数据元素b,d之间插入c,则步骤如下:
图11-1例11-3中的顺序表
1先将f、e、d按次序向后移动一个位置;
②将c放入元素移动后空出的位置上;
③元素总数加1。
当元素个数为n时,要在第i个元素前插入新元素,需移动n-i+1个元素。
在等概率情况下,插入一个新元素平均需移动(n+1)/2个元素。
【例11-4】在如图11-2所示的顺序表中,删除元素。
,则步骤如下:
图11-2 例11-4中的顺序表
①将d、e按次序向左移动一个位置;
②元素个数减1。
元素个数为n时,要删除第i个元素,需移动n-i+1个元素。
在等概率情况下,删除一个元平均需移动n/2个元素。
(2)线性链表。
采用顺序表的运算效率较低,需要大量的数据元素的移位。
而采用链式存储结构的链表是用一组任意的存储单元来存放线性表的数据元素,这组存储单元既可以是连续的,也可以是不连续的,甚至可以是零星分布在内存中的任何位置上,从而可以大大提高存储器的使用效率。
①单链表(singlylinkedlist)。
单链表是链式结构中最简单和最基本的结构。
单链表的每个数据元素都由两部分组成:
存储元素值的数据域(data)和存储直接后继元素存储地址的指针域(next)。
其结构可用示意图11-3表示如下。
图11-3 单链表结点的结构
一个线性表a1,a2,…,an,对应的单链表可用逻辑示意图11-4表示。
其中,h为链表的头指针,用以确定线性表中第一个元素对应的存储位置。
链表的终点元素无直接后继,,其指针域为空,在图中用^表示。
图11-4
通常在单链表的第一元素之前附加一个称为头结点的元素。
头结点的数据域可以不存放任何数据,也可以存放像线性表的表长的数据信息,如图11-5表示
a.单链表中的插入。
【例11-5】设有线性表a1,a2,…,an用带头结点的单链表存储,现要求在数据元素ai
图11-5
的结点之前插人一个数据元素为x的结点。
首先应找到数据元素ai-1的结点P,以便打开ai-1与ai两数据元素之间的链;
然后申请一个新的结点空间t,放上数据值x;
最后,重新建立ai-1与两两数据元素之间的链,构成新的链表。
算法示意图如图11-6所示
图11-6
b.单链表中的删除。
删除操作和插入操作一样,首先要找到指定删除结点的前趋结点(假设为P),然后将删除结点的指针域内容赋予P结点的指针域。
【例11-6】删除单链表中的一个结点。
删除前如图11-7所示。
图11-7
删除后前如图11-8所示。
图11-8
c.单链表的优缺点。
优点:
插入、删除操作时移动的元素少。
缺点:
所有的操作都必须顺链操作,访问不方便。
②循环单链表(circularlist)。
在单链表中最后一个结点的指针域为空(NULI),表示单链表的最后一个结点,如图11-9所小。
图11-9
③双向链表(doublylinkedlist)。
在单链表中,每个结点的指针域只放了一个指针,
该指针指向该结点元素的直接后继元素的结点,每查找一个数据元素,都必须从头结点开始,从前向后单方向的搜寻。
如果在链表的每个结点上再增加一个指向表中每个元素的直接前趋的指针域。
就可以实现线性链表从后向前的搜寻,即可双向查找。
这种指针域包括指向该结点的直接前趋和直接后续的两个指针的存储结构,称为双向链表,简称双链表。
双链表的结点结构图如图11-10所示。
图11-10
一个带头结点的双链表中,并不需要用头指针h来命名这个链表,因为,知道任一结点的指针,就可以访问整个链表的所有结点,包括头结点。
双向链表的逻辑示意图如图11-11所示。
图11-11
11.2.2栈与队列
栈与队列是两种特殊的线性表。
即它们的逻辑结构与线性表相同,只是其插入、删除运算仅限制在线性表的一端或两端进行。
1.栈(stack)
(1)定义。
只允许在一端插入和删除的顺序表,如图11-12所示。
允许插入和删除的一端称为栈顶(top)。
另一端称为栈底(bottom)。
当表中没有元素时称为空栈。
(2)特点。
后进先出(lastin,firstout,LIFO)。
(3)栈的基本运算有5种。
SETNULL(s)(置空栈)。
将栈s置成空栈。
图11-12
EMPTY(s)判空栈。
这是一个布尔函数,若栈s为空栈,返回值为“真”;
否则,返回值为“假”。
PUSH(s,x)(进栈,又称压栈)。
在栈、的顶部插人(亦称压人)元素二。
POP(s)(出栈)。
若栈3不空,则删除(亦称弹出)顶部元素x。
TOP(s)(取栈顶)。
取栈顶元素,并不改变栈中内容。
(4)进栈示例,如图11-13所示。
(5)出栈示例,如图11-14所示。
图11-13 进栈示例
图11-14出栈示例
2.队列(queue)
队列是只允许在一端删除,在另一端插入的顺序表。
如图11-15所示。
允许删除的一端叫做队头(front),允许插入的一端叫做队尾(rear)。
(2)特性。
先进先出(firstinfirstout,FIFO)。
(3)队列的5种基本操作。
SETNULL(q)(置空队列)。
将队列q初使为空。
EMPTY(q)(判队列空)。
若队列q为空队列,返回“真”;
否则返回“假”。
ENTER(q)(入队列)。
若队列q未满,在原队尾后加入数据元素x,使x成为新的队尾元素。
DELETE(q)(出队列)。
若队列q不空,则将队列的队头元素删除。
图11-15
GETHEAD(q)取队头元素)。
若队列q不空,则返回队头数据元素,但不改变队列中内容。
(4)队列的入队和出队(如图11-16),
图11-16
入队时,队尾指针先进,rear=rear-1,再将新元素按rear指示的位置加入队列。
出队时,队头指针先进,front=front+1,再将下标为front的元素取出。
如果,当队满时再入队将溢出出错;
队空时再出队将队空处理。
(5)循环队列(circularqueue)。
当把一维数组表示的队列的第maxsize个位置与第1个位置构成一个首尾相接的环时,就得到循环队列。
循环队列的入队和出队如图11-17所示。
图11-17循环队列的入队和出队
11.2.3线性表的查找
1.概念
关键字(keyword)。
关键字是数据元素中可以唯一标识一个数据元素的数据项。
查找。
根据给定的关键字值,在一组数据中确定一个关键字值等于给定关键字值的数据元素,即在表中查询某个记录是否存在。
若存在这样的数据元素,则称查找是成功的;
否则称查找不成功。
一组待查数据元素的集合又称为查找表。
关于查找,一般要明确下述两个问题。
(1)查找的方法。
按照数据元素的组织方式决定采用的查找方法;
为了提高查找方法的效率,又要求数据元素采用某些特殊的组织方式。
因此,在研究各种查找方法时,必须弄清各种方法所适用的组织方式。
(2)查找算法的评价。
标准有时间复杂度和空间复杂度两个。
在查找算法中,基本运算是给定值与关键字值的比较,所以引出一个成为平均查找长度的概念,作为评价查找算法好坏的依据。
2.常用线性表查找方法
(1)顺序查找。
基本思想:
从第1个元素开始,逐个把元素的关键字值和给定值比较,若某个元素的关键字值和给定值相等,则查找成功;
若直至第n个记录都不相等,说明不存在满足条件的数据元素,查找失败。
查找表的存储结构既适用于顺序存储结构也适用于链式存储结构。
【例11-7】在如图11-18所示的线性表中查找54和19,
图11-18例11-7的线性表
找54---?
:
成功,查找长度为5。
找19---?
失败,查找长度为9。
容易推导出,在长度为n的线性表中进行查找的平均查找长度为(n+1)/2
(2)二分法查找(折半查找)。
将数列按有序化〔递增或递减)排列,查找过程中采用跳跃式方式查找,即先以有序数列的中点位置为比较对象,如果要找的元素值小于该中点元素,则将待查序列缩小为左半部分,否则为右半部分。
通过一次比较,将查找区间缩小一半。
折半查找是一种高效的查找方法。
它可以明显减少比较次数,提高查找效率。
但是,折半查找的先决条件是查找表中的数据元素必须有序
算法步骤描述。
第1步,首先确定整个查找区间的中间位置:
mid=(left+right)/2
第2步,用待查关键字值与中间位置的关键字值进行比较。
①若等于中间位置的关键字值,则查找成功
②若大于中间位置的关键字值,则在后(右)半个区域继续进行折半查找
③若小于中间位置的关键字值,则在前(左)半个区域继续进行折半查找。
第3步,对确定的缩小区域再按折半公式,重复上述步骤。
最后,得到结果要么查找成功,要么查找失败。
【例11-8】对给定数列(有序){3,5,11,17,21,23,28,30,32,50},按折半查找算法,查找关键字值为30的数据元素。
算法步骤如图11-19所示
图11-19例8-8的算法步骤
折半查找的算法讨论。
ASL,≦<
log2n,即每经过一次比较,查找范围就缩小一半。
经log2"
次计较就可以完成查找过程。
因要求有序,所以要求查找数列必须有序,而对所有数据元素按大小排序是非常费时的操作。
另外,顺序存储结构的插入、删除操作不便利。
(3)分块查找。
分块查找又称索引顺序查找,这是顺序查找的一种改进方法
将n个数据元素“按块有序”划分为m块(m≦n)。
每一块中的结点不必有序,但块与块之间必须“按块有序”;
即第1块中任一元素的关键字都必须小于第2块中任一元素的关键字;
而第2块中任一元素的关键字又都必须小于第3块中的任一元素的关键字,……。
每个块中元素不一定是有序的。
算法操作步骤如下。
第1步,先选取各块中的最大关键字构成一个索引表。
第2步,查找分两步。
首先,先对索引表进行二分查找或顺序查找,以确定待查记录在哪一块中;
其次,在已确定的块中用顺序法进行查找。
执行上述操作,就可以实现得到查找结果。
【例11-8】分块查找。
待查序列为{22,12,13,9,8,33,42,44,38,24,48,60,58,75,47}。
按“块有序,,分3块:
(22,12,13,9,8),(33,42,44,38,24),(48,6,58,74,47),选取每块中最大的关键字组成索引表〔22,44,74」,查找关键字值为60的元素。
首先,用折半查找法确定在索引表中的位置为mid=2,key的值60与a[2]比较,60>a[2],确定在第3块中进行查找。
在第3块中用顺序法查找,比较两次,就可以找出60的元素来,如图11-20所示。
图11-20 例11-9的算法步骤
分块查找算法的优缺点如下。
插入、删除操作方便;
只要找到对应的块,在块中任意位置操作均可。
索引表增加了辅助存储空间。
11.2.4排序
1.概念
(1)排序。
将文件或表中的记录,通过某种方法整理成按关键字大小次序排列的处理过程
①内部排序(内排序)。
在计算机内存中进行的排序。
②外部排序(外排序。
借助计算机外存进行的排序。
(2)排序的稳定性。
假设在待排序的文件中,存在两个具有相同关键字的记录R(i)与R(j),其中R(i)位于R(j)之前。
在用某种排序法排序之后,R(i)仍位于R(j)之前,则称这种排序方法是稳定的;
否则,称这种排序方法是不稳定的。
例如:
(10,25,22,42,25,30,18)排序后为(10,18,22,25,25,30,42)是稳定的。
(10,25,22,42,25,30,18)排序后为(10,18,22,25,25,30,42)是不稳定的。
2.内排序方法
(1)对顺序表的排序。
①插入排序。
插入排序分为直接插入排序、折半插入排序、2-路插人排序、表插人排序和希尔(Shell)排序。
②选择排序。
选择排序分为简单选择排序(或称选择排序)、树形选择排序和堆排序。
③交换排序。
交换排序分为冒泡排序和快速排序。
④归并排序。
归并排序分为2-路归并排序和k-路归并排序。
⑤基数排序。
基数排序分为多关键字排序、最高位优先法、最低位优先法和链式基数排序。
(2)对单链表的排序。
对单链表的排序有直接插入、简单选择、冒泡排序和基数排序。
3.几种常用排序方法
(1)插入法排序。
思想:
将待排序的记录插入到已排序的子文件中去,使得插入之后得到的子文件仍然是有序子文件。
插入一个记录,首先要对有序子文件进行查找,以确定这个记录的插入位置。
按查找方式的不同,插入排序又可以分为线性插入排序和折半插入排序,前者使用顺序查找,后者使用折半查找。
[0118-101插入法排序。
算法步骤如图11-21所示。
图11-21例11-10的算法步骤
(2)选择排序。
设待排序的文件为(r[1],r[2]…,r[n]),关键字为(r[1],key,r[2].key,…,r[n].key)。
第1趟:
在(r[1]〕,r[2],…,r[n])中,选出关键字最小的记录r[min].key,若min<>1,则交换r[1]和r[min];
需要进行n一1次比较。
第2趟:
在n-1个记录(r[2],…,r[n])中,选出关键字最小的记录r[min].key,,min<>2,则交换r[2]和r[min];
需要进行n-2次比较。
第n-1趟:
在最后的2个记录记录(r[n-1],r[n])中,选出关键字最小的记录r[min].key,若min<
>
n-1,则交换r[n-1]和r[min];
需要进行1次比较。
【例11-11】选择排序。
算法步骤如图11-22所示。
可以看出,算法是不稳定的。
(3)冒泡排序。
设待排序的文件为(r[1],r[2],…r[n])。
从r[1]开始,依次比较两个相邻记录的关键字r[i].key和r[i+1].Key,若r[i].key>
r[i+1].key,则交换记录r[i]和r[i+l]的位置;
否则,不交换。
第1趟之后,n个关键字中最大的记录移到了r[n]的位置上。
从r[1]开始,依次比较两个相邻记录的关键字r[i].key和r[i+1].key,,若r[i].key>
r[i+1].Key,则交换记录r[i]和r[i+1]的位置;
第2趟之后,前n-1个关键字中最大的记录移到了r[n-1]的位置上。
作完n-1趟,或不需再交换记录时为止
【例11-12】冒泡排序过程。
算法步骤如图11-23所示。
图11-22例11-11的算法步骤 图11-23 例11-12的算法步骤
(4)快速