C语言入门教程全第9章.ppt
《C语言入门教程全第9章.ppt》由会员分享,可在线阅读,更多相关《C语言入门教程全第9章.ppt(282页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、9.1 数据结构与算法概述 9.1.1 数据结构的相关概念数据结构的相关概念实践证明,要想更有效地使用计算机,仅仅掌握计算机语言而缺乏数据结构和算法的有关知识,是难以处理诸多复杂应用问题的。早期的计算机主要解决纯数值计算的问题,以此为加工对象的程序设计称为数值型程序设计。其涉及的操作对象比较简单,其一般为整型、实型数据等。后来,随着计算机应用领域的不断拓宽,解决非数值计算的问题越来越引起人们的关注。例如,金融管理、文献检索、计算机辅助设计等。这些问题主要集中于对数据集合中的各元素以各种方式进行运算,如插入、更新、删除、查找等。在此涉及的数据类型比较复杂,而且数据元素之间具有各种特定的联系,所以
2、,如果了解了数据集合中元素之间的关系以及如何组织和表示这些数据,就能大大提高计算机处理问题的效率。数据结构是一门研究非数值运算的程序设计问题的学科,它包含以下3个方面的内容:(1)数据集合中各数据元素之间的逻辑结构。(2)对数据进行处理时,各数据元素在计算机中的存储(物理)结构。(3)对数据的抽象运算。1数据(data)数据是反映客观事物信息符号的集合,也是计算机程序要加工的对象。这个集合中包括客观事物的数值、字符以及能够输入到计算机中并被计算机程序处理的符号。计算机发展初期,由于计算机主要用于数值计算,数据指的就是数值。随后由于计算机应用的普及,数据的含义也比原来变得更加广泛。如文字、表格、
3、声音、图形、图像等都属于数据的范畴。2数据元素(data element)数据元素是数据集合中的客体(个体),是数据的基本单位,有时也称为节点或记录。例如数据集合N=1,2,3,4,5中整数15都是数据元素。每个数据元素的表现形式是由一个或多个数据项组成的。数据项是具有独立含义的最小标识单位,例如,在老师档案信息管理中的每一位老师就是一个数据元素,组成它的数据项可以是姓名、性别、年龄等。3数据对象(data object)数据对象是具有相同特性的数据元素的集合,是数据的一个子集。例如,一周中的7天就是一个数据对象,可表示为集合W=Mon,Tue,Wed,Thu,Fri,Sat,Sun;再如,字
4、母数据对象可表 示为集合C=A,B,Z。4数据类型(data type)数据类型是一个值的集合和定义在该值集上的一组操作的总称。程序中出现的每一个变量必须与一个而且只能与一个数据类型相联系,它不仅规定了该变量可以设定的值的集合,还规定了该集合上的运算。各种语言规定了它所允许的数据类型。在C语言中,基本数据类型包括整型、实型等,这些变量的值是不可再分的;而构造类型包括数组、结构体等,这些变量的值是可以再分的,也可以说它们是带结构的数据,它们的成分可以是基本数据类型,也可以是构造数据类型等。5数据结构(data structure)数据结构指的是数据之间的相互关系,即数据的组织形式。可以用集合论的
5、方法定义数据结构如下:S=(D,R)D=ai|aiElemSet,i=0,1,2,3,n,n0R=|ai-1,aiD,2in数据结构S是一个二元组,其中D是一个数据元素的有限集合,R是定义在关系D上的有限集合,即R是由有限个关系所构成的集合。若n=0时,则D是一个空集。数据结构分为逻辑结构与物理结构两种。(1)数据的逻辑结构。数据的逻辑结构就是数据元素间的逻辑关系,它研究的是数据元素及其关系的数学特性,与数据的存储无关,是独立于计算机的。数据的逻辑结构可概括地分为线性结构和非线性结构两种,如图9.1.1所示。图9.1.1 数据的逻辑结构线性结构的逻辑特性是有且仅有一个开始元素和一个终结元素,除
6、第一个元素以外,其他元素有且仅有一个直接前驱;除最后一个元素外,其他元素都有且仅有一个直接后继。非线性结构的逻辑特性是一个元素可能有多个直接前驱和直接后继。线性结构主要有线性表、栈和队列等,而非线性结构分为树型结构和图型结构等。(2)数据的物理结构。数据的物理结构又称存储结构,是数据及其关系在计算机中的存放形式,是逻辑结构在计算机存储器中的映像,也就是它的具体实现,通常用高级语言中各种数据类型来描述。在进行实际的数据处理时,被处理的数据都是存放在计算机的存储空间中,而且,各数据在计算机存储空间的位置关系与它们的逻辑关系通常是不同的。因此,为了能表示出存放在计算机存储空间的各个节点之间的逻辑关系
7、,在数据的存储结构中,不但要存放各个节点的信息,还要存放各个节点之间逻辑关系的信息。下面介绍4种常见的存储结构:1)顺序存储结构。顺序存储结构主要用于线性的数据结构。它是把逻辑上相邻的数据元素节点存储在物理上相邻的存储单元中,各节点之间的逻辑关系由存储单元的邻接关系来体现。如图9.1.2所示为顺序存储结构,假设每个节点占据长度为l(字母,以下同)的存储空间,这个逻辑结构在物理存储器中以一定的顺序占用连续的存储空间。对于这种结构,只需要知道第一个元素的地址和每一个元素所占的存储单元数就可以得到任何一个元素所在的位置。在顺序存储结构中存取任意一个元素所需要的时间是相等的。图9.1.2 顺序存储结构
8、 2)链式存储结构。顺序存储结构比较适合于线性结构,而非线性结构一般很难用顺序存储结构来实现,所以,通常不用顺序存储结构,而是用链式存储结构来实现非线性结构。链式存储结构是给节点附加指针字段。在这种存储结构中,节点所占的存储单元分为两部分:一部分是用来存放节点自身的信息,称为数据域;另一部分是用来存放该节点后继节点的存储单元的地址,称为指针域。指针域中可以有一个或者多个指针,用来表示节点的一个或多个后继,也可以用来表示其他节点的地址。在用链式存储结构存储一个非线性结构时,节点中的指针个数可以根据该节点的直接后继个数来设置。如图9.1.3所示的链式存储结构,在Addr1的存储单元中,既包含了节点
9、a1本身的信息,又包含了它的后继节点a2的存储单元的地址Addr1+3l,其他节点与此类似。图9.1.3 链式存储结构 由此不难看出,链式存储结构可以存储线性结构,也可以存储非线性结构。在链式存储结构中,各个节点在存储空间中的前后位置关系与其逻辑顺序也可以不一致,其存储空间也可以不连续。3)索引存储结构。在线性结构中,所有节点可以排成一个序列,每个节点在该序列中都有对应的位置值,这个位置值就是节点的索引号。索引存储结构是用节点的索引号来确定节点的存储地址。可用以下两种方法实现索引存储:建立一个附加的索引表,索引表中第i项的值就是第i个节点的存储地址。如果每个节点所占单元数都相等,可用位置值的线
10、性函数的值来指出节点对应的存储地址,即第i个节点di的地址为LOC(di)=(i-1)l+d,其中l为节点所占单元数,d为开始节点d1对应的存储地址。4)散列存储结构。散列存储结构是指根据节点的关键字值来确定其存储地址,也称为哈希法。用这种方法进行存储时,每个节点分散地存储在存储单元中,其查找的效率是很高的,关键问题是怎样选择哈希函数和研究解决冲突的办法。上述4种存储结构也可以组合起来对数据进行存储映像。同一个逻辑结构可以有多种不同的存储方法,应根据具体情况进行选择。另外,存储结构只是数据结构的一个重要方面,如果逻辑结构相同但存储结构不同,也是不同的数据结构。例如,如果用顺序存储结构存储线性表
11、,则称为顺序表;如果用链式存储结构存储线性表,则称为链表。9.1.2 算法评价算法评价在第3章中读者已初步了解了算法的概念、特性等,在前面其他章节的编程举例中还学习了不少给定的算法。而解决同一个问题通常有许多不同的算法。算法评价的目的首先在于从解决同一个问题的不同算法中选择出较为合适的一种,其次在于知道怎样对现有算法进行改进,进而设计出更好的算法。对于算法的评价可以从以下几个方面进行。1正确性正确性(correctness)是设计和评价算法的首要条件,一个正确的算法是指在有合理的数据输入的情况下,能够在有限的运行时间内得出正确的结果。要从理论上证明一个算法的正确性,并不是一件容易的事,所以通常
12、可采用各种典型的输入数据上机调试算法,并使算法中的每段代码都被测试过,若发现错误及时修正,最终可以验证出算法的正确性。2健壮性健壮性(robustness)是指一个算法对不合理(又称不正确、非法、错误等)数据输入的反应和处理能力。一个好的算法应该能够识别出错误数据并进行相应的处理。对错误数据的处理一般包括打印出错误信息、调用错误处理程序、返回标识错误的特定信息、中止程序运行等。3可读性可读性(readability)是指一个算法供人们阅读和理解的容易程度。一个可读性好的算法,应该符合结构化和模块化程序设计的思想,应该对其中的每个功能模块、重要数据类型或语句加以必要注释;应该建立相应的文档,对整
13、个算法的功能、结构、使用及有关事项进行说明。4简单性简单性(simplicity)是指一个算法所采用数据结构和方法的简单程度。如对数组进行查找时,采用顺序查找的方法比采用二分查找的方法要简单;对数组进行排序时,采用简单选择排序的方法比采用堆排序或快速排序的方法要简单。但最简单的算法往往不是最有效的,即有可能占用较长的运行时间和较多的内存空间。算法的简单性便于用户编写、分析和调试,所以对于处理少量数据的情况是适用的,但若要处理大量的数据,则算法的有效性比简单性更重要。有效性主要表现为时间复杂度和空间复杂度。5时间复杂度时间复杂度(time complexity)是指计算机执行一个算法时在时间上的
14、消耗度量。度量一个程序的执行时间通常有两种方法:事后统计和事前分析估算。通常人们采用第二种方法,所以这里只介绍事前分析估算方法。一般情况下,把算法中一条语句重复执行的次数称为此语句的频度,它常表示为问题规模n的某个函数,记作F(n)。而算法的时间复杂度则记作T(n)=O(F(n)下面举例说明如何求时间复杂度:for(i=0;in;i+)for(j=0;jn;j+)bij=0;for(k=0;kn;k+)bij=bij+aik*akj;以执行次数最多的语句(bij=bij+aik*akj;)进行计算:语句频度:F(n)=n3时间复杂度:T(n)=O(F(n)=O(n3)下列程序段的时间复杂度如下
15、:(1)x=x+1;T(n)=O(1)(2)for(j=0;jn;j+)x=x+1;T(n)=O(n)(3)for(j=0;jn;j+)for(k=0;knext=p-next;p-next=s;在进行指针的修改时,必须要注意其修改的顺序,假如把上述两条语句顺序颠倒,那么执行结果就完全错误。在带头节点的单链表的第i个元素之后插入元素x的算法描述如下:ListInsert_L(LinkList*L,int i,ElemType x)(2)删除运算。单链表的删除运算与插入运算一样,在删除时,不需要移动元素,只须修改有关的指针内容。在单链表上进行删除运算时指针的变化如图9.2.7所示。上述指针修改可
16、描述如下:p-next=p-next-next;图9.2.7 单链表上删除节点时指针的变化情况在带头节点的单链表中删除第i个元素的算法描述如下:3其他形式的链表根据实际需要,线性表的链式存储结构还有循环链表和双向链表等其他形式。(1)循环链表。循环链表是线性表的另一种链式存储结构,它的特点是表中最后一个节点的指针域不为空,而是指向表头,整个链表形成一个环。如图9.2.8(a)、(b)所示分别表示具有头节点的非空循环链表和空循环链表。图9.2.8 循环链表循环链表与一般链表的不同之处在于只要给定循环链表中任一节点的地址,就可以遍历表中所有节点,而不必从头指针开始。这样有可能对某些运算带来方便。(
17、2)双向链表。前面讨论的链表都是单向链表,它们只能单方向地寻找表中的节点,若要寻找前驱节点,则需从表头指针出发查找或向后循环一周查找,当表长为n时执行时间为O(n)。为克服其单向性缺点,可采用双向链表。在双向链表的节点中有两个指针域,一个指向直接后继,一个指向直接前驱,如图9.2.9所示。图9.2.9 双向链表双向链表的节点类型定义如下:typedef struct Dlnode /*定义双向链表节点 类型*/ElemType data;struct DLnode*left;struct DLnode*right;DLnode,*DLinkList;此类型包含有3个域:数值域data、左指针域
18、left和右指针域right。left域用于指向其前驱节点,right域用于指向其后继节点。由于双向链表具有对称性,因此从表中某一给定的节点可随意向前或向后查找。但在执行插入、删除运算时,需同时修改两个方向上的指针。9.2.4 线性表的应用线性表的应用一元多项式相加是线性表的一个典型应用实例。多项式的操作是表处理中经常出现的操作,我们以一元多项式相加为例,说明线性链表在实际中的应用。一个一元多项式Pn(x)可以表示为Pn(x)=P0+P1x+P2x2+pnxn该多项式按升幂排列,并由n+1个系数唯一确定,因此可以用一个线性表P表示为P=(p0,p1,p2,pn)其指数i隐含在系数pi的序号内。
19、一元多项式的存储结构可以采用顺序存储结构,也可以用链式存储结构,这要取决于执行何种操作。如果只求多项式的值,无须修改多项式的系数和指数,则采用顺序存储结构为宜。但在进行多项式相加时,通常要改变多项式的系数和指数,而且在实际问题中,经常会出现多项式的次数很高但又存在大量的零系数项的情况,例如:S(x)=8+2x1050+3x2000这时如果采用顺序存储结构会浪费大量的存储空间,故一般采用链式存储结构。用链式存储结构表示多项式是把每一个非零系数项构成链表中的一个节点,节点是由两个数据域和一个指针域构成,如图9.2.10(a)所示。其中,exp(i)表示该项的指数,称为指数域;coef(i)表示该项
20、的系数,称为系数域;next(i)是指向下一个非零系数的节点,称为指针域。整个多项式Pn(x)如图 9.2.10(b)所示。图9.2.10 一元多项式的链式存储结构设有一元多项式A(x)和B(x),现要求其相加结果C(x)=A(x)+B(x)。其运算规则为:将两个多项式中指数相同的项对应系数相加,若和不为零,则构成C(x)中的一项;A(x)和B(x)中所有指数不相同的项均复制到C(x)中。其运算规则如下:假设指针qa和qb分别指向多项式A和多项式B中当前进行比较的某个节点,则比较两个节点中的指数项,有下列3种情况:(1)指针qa所指节点的指数值指针qb所指向节点的指数值,则应摘取qb指针所指节
21、点插入到C(x)链表中去。(3)指针qa所指节点的指数值=指针qb所指向节点的指数值,则把两个节点中的系数相加,若和数不为0,则修改qa所指节点的系数值,同时释放 qb所指向节点;反之,从多项式A的链表中删除相应节点,并释放指针qa和qb所指节点。如图9.2.11(a)所示,为带头节点的单链表表示的多项式A5(x)=8-2x+15x5,B8(x)=2x+7x4-9x5+3x8;如图9.2.11(b)所示表示相加后的“和多项式”C(x)。图9.2.11 用链式存储结构进行多项式求和9.3 栈和队列 9.3.1 栈的定义及其运算栈的定义及其运算1栈的定义栈(stack)又称堆栈,它实际上是一种操作
22、受限的特殊的线性表,是限定仅在表的一端进行插入和删除的线性表。在栈中,允许插入与删除的一端称为栈顶,不允许插入与删除的一端称为栈底。栈顶元素总是最后被插入的元素,自然也是最先被删除的元素;栈底元素总是最先被插入的元素,自然也是最后才被被删除的元素。也是说栈是按照“先进后出”(First In Last Out,FILO)或者“后进先出”(Last In First Out,LIFO)的原则组织数据的,所以,栈也被称为“先进后出”表或“后进先出”表。由此可以看出,栈具有记忆功能。通常用指针top指示栈顶的位置,用指针bottom指向栈底。向栈中插入一个元素(即插入为新的栈顶元素)称为入栈运算,从
23、栈中删除一个元素(即删除栈顶元素)称为出栈运算。栈顶指针top动态反图9.3.1 栈的示意图映了栈中元素的变化情况。如图9.3.1所示为栈的示意图。栈这种结构在日常生活中是很常见的。例如子弹夹就是一种栈的例子,最先压入的子弹总是最后一个被弹出,而最后压入的子弹最先被弹出,这就遵循了“后进先出”或“先进后出”的原则。2栈的基本运算(1)建立一个空栈。(2)判断空栈。(3)读栈顶元素。(4)求栈的长度,返回栈的数据元素个数。(5)入栈,将元素插入到栈顶。(6)出栈,删除栈顶元素。9.3.2 栈的存储结构栈的存储结构1栈的顺序存储结构顺序栈实现栈的顺序存储结构最简单的方法是用一维数组来存储。由于栈底
24、不变,而栈顶是随入栈、出栈操作动态变化的,因此必须记住栈顶的位置,并且由于栈是有容量限制的,因此用C语言定义顺序栈的结构如下:#define Stack_NUM 100#define Stack_MORENUM 10typedef struct ElemType*bottom;ElemType*top;int stacksize;SqStack;其中,stacksize说明栈当前可用的最大容量。栈的初始化操作如下:按设定的初始分配量进行第一次存储分配,bottom称为栈底指针,在顺序栈中,它始终指向栈底的位置,如果bottom的值为NULL,则表明栈结构不存在。在程序设计语言中,用一维数组S(
25、1:m)作为栈的顺序存储空间,其中m为栈的最大容量。如图9.3.2(a)所示是容量为10的栈顺序存储空间,栈中已经有6个元素;如图9.3.2(b)和图9.3.2(c)所示分别为入栈与出栈后的状态。图9.3.2 顺序栈的插入与删除运算 在栈的顺序存储空间S(1:m)中,S(bottom)通常为栈底元素(是在栈非空的情况下),S(top)为栈顶元素。top=0表示栈空,top=m表示栈满。在栈上进行操作,都比较容易实现,下面介绍顺序栈的建立、插入和删除的算法。(1)建立空栈。Init_StackSq(SqStack*S)2栈的链式存储结构链栈顺序栈最大的缺点是:必须设置最大容量,但是当栈的容量不固
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 入门教程
限制150内