文档详情

C语言二级考点复习

无***
实名认证
店铺
DOC
5.02MB
约103页
文档ID:155492755
C语言二级考点复习_第1页
1/103

1.1 算法1.1.1 算法的基本概念算法是指对解题方案的准确而完整的描述简单地说,就是解决问题的操作步骤值得注意的是,算法不等于数学上的计算方法,也不等于程序在用计算机解决实际问题时,往往先设计算法,用某种表达方式(如流程图)描述,然后再用具体的程序设计语言描述此算法(即编程)在编程时由于要受到计算机系统运行环境的限制,因此,程序的编制通常不可能优于算法的设计1.1.1.1 算法的基本特征一般来说,一个算法应具有以下4个基本特征1)可行性(Effectiveness):算法在特定的执行环境中执行,应当能够得出满意的结果,即必须有一个或多个输出2)确定性(Definiteness):算法中的每一个步骤都必须有明确的定义,不允许有模棱两可的解释和多义性3)有穷性(Finiteness):算法必需在有限时间内做完,即算法必需能在执行有限个步骤之后终止4)拥有足够的情报:要使算法有效必需为算法提供足够的情报当算法拥有足够的情报时,此算法才是有效的;而当提供的情报不够时,算法可能无效1.1.2.1 算法的时间复杂度算法的时间复杂度是指执行算法所需要的计算工作量为了能够比较客观地反映出一个算法的效率,在度量一个算法的工作量时,不仅应该与所使用的计算机、程序设计语言以及程序编制者无关,而且还应该与算法实现过程中的许多细节无关。

算法的计算工作量是用算法所执行的基本运算次数来度量的,而算法所执行的基本运算次数是问题规模(通常用整数n表示)的函数即算法的工作量=f(n)例如,在N×N矩阵相乘的算法中,整个算法的执行时间与该基本操作(乘法)重复执行的次数n3成正比,也就是时间复杂度为n3,即f(n)=O(n3)在有的情况下,算法中的基本操作重复执行的次数还随问题的输入数据集不同而不同例如在起泡排序的算法中,当要排序的数组a初始序列为自小至大有序时,基本操作的执行次数为0;当初始序列为自大至小有序时,基本操作的执行次数为n(n-1)/2对这类算法,可以采用平均性态和最坏情况复杂性两种方法来分析1.1.2.2 算法的空间复杂度算法的空间复杂度是指执行这个算法所需要的内存空间一个算法所占用的存储空间包括算法程序所占的空间、输入的初始数据所占的存储空间以及算法执行过程中所需要的额外空间其中额外空间包括算法程序执行过程中的工作单元以及某种数据结构所需要的附加存储空间如果额外空间量相对于问题规模来说是常数,则称该算法是原地(in place)工作的在许多实际问题中,为了减少算法所占的存储空间,通常采用压缩存储技术,以便尽量减少不必要的额外空间。

1.2.1.1 数据的逻辑结构由数据结构的定义可知,一个数据结构应包含以下两方面信息:(1)表示数据元素的信息;(2)表示各数据元素之间的前后件关系在此定义中,并没有考虑数据元素的存储,所以上述的数据结构实际上是数据的逻辑结构数据的逻辑结构是对数据元素之间的逻辑关系的描述,它可以用一个数据元素的集合和定义在此集合中的若干关系来表示数据的逻辑结构有两个要素:一是数据元素的集合,通常记为D;二是D上的关系,它反映了数据元素之间的前后件关系,通常记为R一个数据结构可以表示成B=(D,R)其中B表示数据结构为了反映D中各数据元素之间的前后件关系,一般用二元组来表示例如,如果把一日三餐看作一个数据结构,则可表示成B=(D,R)D={早餐,午餐,晚餐}R={(早餐,午餐),(午餐,晚餐)}数据的逻辑结构包括线性结构、树型结构图、网状结构图和集合图4种1.2.1.2 数据的存储结构数据的逻辑结构在计算机存储空间中的存放形式称为数据的存储结构(也称数据的物理结构)在进行数据处理时,被处理的各数据元素总是被存放在计算机的存储空间中,而且各数据元素在计算机存储空间中的位置关系与它们的逻辑关系可能不同由于数据元素在计算机存储空间中的位置关系可能与逻辑关系不同,因此,为了表示存放在计算机存储空间中的各数据元素之间的逻辑关系(即前后件关系),在数据的存储结构中,不仅要存放各数据元素的信息,还需要存放各数据元素之间的前后件关系的信息。

一种数据的逻辑结构根据需要可以表示成多种存储结构,常用的存储结构有顺序、链接、索引等存储结构而采用不同的存储结构,其数据处理的效率是不同的因此,在进行数据处理时,选择合适的存储结构是很重要的1.2.3 线性结构与非线性结构如果在一个数据结构中一个数据元素都没有,则称该数据结构为空的数据结构在只有一个数据元素的数据结构中,删除该数据元素,就得到一个空的数据结构;在一个空的数据结构中插入一个新的元素后变成非空根据数据结构中各数据元素之间前后件关系的复杂程度,一般将数据结构分为两大类型:线性结构与非线性结构如果一个非空的数据结构满足下列两个条件:(1)有且只有一个根结点;(2)每一个结点最多有一个前件,也最多有一个后件则称该数据结构为线性结构线性结构又称为线性表由此可见,性结构中,各数据元素之间的前后件关系是很简单的需要特别说明的是,在一个线性表中插入或删除任何一个结点后还应是线性结构如果一个数据结构不是线性结构,则称之为非线性结构在非线性结构中,各数据元素之间的前后件关系要比线性结构复杂链式结构是总常用的非线性结构线性结构与非线性结构都可以是空的数据结构对于空的数据结构,如果对该数据结构的运算是按线性结构的规则来处理的,则属于线性结构;否则属于非线性结构。

1.3.2 线性表的顺序存储结构通常,线性表可以采用顺序存储和链式存储,本小节主要讨论顺序存储结构线性表的顺序存储指的是用一组地址连续的存储单元依次存储线性表的数据元素线性表的顺序存储结构具备如下两个基本特征:(1)线性表中的所有元素所占的存储空间是连续的;(2)线性表中各数据元素在存储空间中是按逻辑顺序依次存放的用顺序存储结构存储的线性表称为顺序表在顺序表中,其前、后件两个元素在存储空间中是紧邻的,且前件元素一定存储在后件元素的前面如长度为n的线性表(a1,a2,…,ai,…,an)的顺序存储如图1-6所示在顺序表中,如果每个元素占有K个存储单元,则下标为i+1的元素的存储位置与下标为i的元素的存储位置之间,满足下列关系:ADR(ai+1)=ADR(ai)+K通常把顺序表中第1个数据元素的存储地址ADR(a1)称为线性表的首地址,线性表中第i个元素ai的存储地址为:ADR(ai)=ADR(a1)+(i-1)K例如,在顺序表中存储数据(14,23,25,78,15,68,27),每个数据元素占有2个存储单元,第1个数据元素14的存储地址是200,则第3个数据元素25的存储地址是:ADR(a3)=ADR(a1)+(3-1)×2=200+4=204从这种表示方法可以看到,它是用元素在计算机内物理位置上的相邻关系来表示元素之间逻辑上的相邻关系。

只要确定了首地址,线性表内任意元素的地址都可以方便地计算出来1.3.3 顺序表的插入运算顺序表的插入运算是指在表的第i(1≤i≤n+1)个位置上,插入一个新结点x,使长度为n的顺序表(a1,…,a i-1,ai,…,an)变成长度为n+1的顺序表(a1,…,ai-1,x,ai,…,an)在第i个元素之前插入一个新元素,完成插入操作主要有以下3个步骤1)把原来第n个结点至第i个结点依次往后移一个元素位置2)把新结点放在第i个位置上3)修正线性表的结点个数例如,图1-4(a)表示一个存储空间为10,长度为7的顺序表为了在顺序表的第6个元素(即56)之前插入一个值为27的数据元素,则需将第6个和第7个数据元素依次往后移动一个位置,空出第6个元素的位置,如图1-4(a)中箭头所示,然后将新元素27插入到第6个位置插入一个新元素后,顺序表的长度增加1,变为8,如图1-4(b)所示一般情况下,在第i(1≤i≤n)个元素之前插入一个元素时,需将第i个元素之后(包括第i个元素)的所有元素向后移动一个位置再例如,在图1-4(b)的顺序表的第2个元素之前,再插入一个值为35的新元素,采用同样的步骤:将第2个元素之后的元素(包括第2个元素),即第2个元素至第8个元素,共n-i+1=8-2+1=7个元素向后移动一个位置,然后将新元素插入到第2个位置,如图1-4(b)中箭头所示。

插入后,线性表的长度增加1,变成9,如图1-7(c)所示 顺序表的插入运算,其时间主要花费在结点的移动上,所需移动结点的次数不仅与表的长度有关,而且与插入的位置有关1.4.1 栈及其基本运算1.栈的定义栈(Stack)是一种特殊的线性表,它所有的插入与删除都限定在表的同一端进行在栈中,一端是封闭的,既不允许进行插入元素,也不允许删除元素;另一端是开口的,允许插入和删除元素例如,枪械的子弹匣就可以用来形象地表示栈结构如图1-9(a)所示,子弹匣的一端是完全封闭的,最后被压入弹匣的子弹总是最先被弹出,而最先被压入的子弹最后才能被弹出在栈中,允许插入与删除的一端称为栈顶,不允许插入与删除的另一端称为栈底当栈中没有元素时,称为空栈例如,没有子弹的子弹匣为空栈通常用指针top来指示栈顶的位置,用指针bottom来指向栈底假设栈S=(a1,a2,…,an),则称a1 为栈底元素,an为栈顶元素栈中元素按a1,a2,…,an的次序进栈,退栈的第一个元素应为栈顶元素an图1-9(b)是栈的入栈、退栈示意图2.栈的特点根据栈的上述定义,栈具有以下特点栈的修改原则是"后进先出"(Last In First Out,LIFO) 或"先进后出"(First In Last Out,FILO),因此,栈也称为"后进先出"表或"先进后出"表。

3.栈的基本运算栈的基本运算包括入栈、退栈和读栈定元素1)入栈运算入栈运算是指在栈顶位置插入一个新元素首先将栈顶指针加1(即top加1),然后将新元素插入到栈顶指针指向的位置当栈顶指针已经指向存储空间的最后一个位置时,说明栈空间已满,不可能再进行入栈操作这种情况称为栈"上溢"错误2)退栈运算退栈是指取出栈顶元素并赋给一个指定的变量首先将栈顶元素(栈顶指针指向的元素)赋给一个指定的变量,然后将栈顶指针减1(即top减1)当栈顶指针为0时,说明栈空,不可进行退栈操作这种情况称为栈的"下溢"错误3)读栈顶元素读栈顶元素是指将栈顶元素赋给一个指定的变量这个运算不删除栈顶元素,只是将它赋给一个变量,因此栈顶指针不会改变当栈顶指针为0时,说明栈空,读不到栈顶元素图1-10所示是一个顺序表示的栈的动态示意图随着元素的插入和删除,栈顶指针top反应了栈的状态不断地变化1.4.2.2 循环队列及其运算在实际应用中,队列的顺序存储结构一般采用循环队列的形式所谓循环队列,就是将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间在循环队列中,用队尾指针rear指向队列中的队尾元素,用排头指针front指向排头元素的前一个位置。

因此,从排头指针front指向的后一个位置直到队尾指针rear指向的位置之间所有的元素均为队列中的元素一维数组(1:m),最大存储空间为m,数组(1:m)作为循环队列的存储空间时,循环队列的初始状态为空,即front=rear=m,图1-13所示是循环队列初始状态的示意图循环队列的初始状态为空,即front=rear=m循环队列主要有两种基本运算:入队运算和退队运算1)入队运算入队运算是指在循环队列的队尾加入一个新元素首先将队尾指针进1(即rear=rear+1),并当rear=m+1时置rear=1;然后将新元素插入到队尾指针指向的位置例如,在图1-14(a)中进行入队运算,首先队尾指针进1,此时rear=m+1,置rear=1,则在第1个位置上插入数据a,见图1-14(b);当插入第2个数据b时,队尾指针进1,rear=2,在第2个位置上插入数据b,依此类推,直到把所有的数据元素插入完成,见图1-14(c)所示2)退队运算退队运算是指在循环队列的队头位置退出一个元素并赋给指定的变量首先将队头指针进1(即front=front+1),并当front=m+1时,置front=1;然后将排头指针指向的元素赋给指定的变量。

例如,在图1-14(c)中进行退队运算时,排头指针进1(即front+1),此时front=m+1,置front=1,删除此位置的数据,即数据a从图1-14(a)和图1-14(c)可以看出,循环队列在队列满时,和队列空时都有front=rear,如何区分循环队列是空还是满的呢?在实际应用中,通常增加一个标志量S,S值的定义如下:循环队列为空时S=0循环队列为非空时S=1由此可以判断队列空和队列满这两种情况当S=0时,循环队列为空,此时不能再进行退队运算,否则会发生"下溢"错误当S=1时,并且front=rear时,循环队列满此时不能再进行入队运算,否则会发生"上溢"错误在定义了S以后,循环队列初始状态为空,表示为:S=0,且front=rear=m1.5 线性链表线性表的顺序存储结构具有简单、操作方便等优点但在对其做插入或删除操作时,需要移动大量的元素因此,对于大的线性表,特别是元素变动频繁的大线性表不宜采用顺序存储结构,而是通常采用链式存储结构1.5.1 线性单链表的结构1.5.1.1 线性链表的基本概念 在链式存储结构中存储数据结构的存储空间可以不连续,各数据结点的存储顺序与数据元素之间的逻辑关系可以不一致,而数据元素之间的逻辑关系是由指针域来确定的。

链式存储方式既可用于表示线性结构,也可以表示非线性结构线性表的链式存储结构称为线性链表由于这种链表中,每个结点只有一个指针域,故又称为单链表在链式存储方式中,要求每个结点由两部分组成:一部分用于存放数据元素值,称为数据域;另一部分用于存放指针,称为指针域其中指针用于指向该结点的前一个或后一个结点(即前件或后件)如图1-15所示1.5.1.3 带链的栈与队列(1)带链的栈栈也是线性表,也可以采用链式存储结构在实际应用中,带链的栈可以用来收集计算机存储空间中所有空闲的存储结点,这种带链的栈称为可利用栈,如图1-19(a)所示2)带链的队列队列也是线性表,也可以采用链式存储结构,如图1-19(b)所示1.5.2 线性链表的基本运算对线性链表进行的运算主要包括查找、插入、删除、合并、分解、逆转、复制和排序1.5.2.1 性链表中查找指定元素查找指定元素所处的位置是插入和删除等操作的前提,只有先通过查找定位才能进行元素的插入和删除等进一步的运算在链表中查找指定元素必须从队头指针出发,沿着指针域Next逐个结点搜索,直到找到指定元素或链表尾部为止,而不能像顺序表那样,只要知道了首地址,就可以计算出任意元素的存储地址。

因此,线性链表不是随机存储结构在链表中,如果有指定元素,则扫描到等于该元素值的结点时,停止扫描,返回该结点的位置,因此,如果链表中有多个等于指定元素值的结点,只返回第一个结点的位置如果链表中没有元素的值等于指定元素,则扫描完所有元素后,返回NULL1.5.2.2 线性链表的插入线性链表的插入是指在链式存储结构下的线性链表中插入一个新元素插入运算是将值为x的新结点插入到表的第i个结点的位置上,即插入到ai-1与ai之间因此,我们必须首先找到ai-1的存储位置p,然后生成一个数据域为x的新结点*p,并令结点*p的指针域指向新结点,新结点的指针域指向结点ai如图1-15所示图1-15线性表的插入示意图1.5.2.3 线性链表的删除线性链表的删除是指在链式存储结构下的线性链表中删除包含指定元素的结点删除运算是将表的第i个结点删去因为在单链表中结点ai的存储地址是在其直接前趋结点ai-1的指针域Next中,所以我们必须首先找到ai-1的存储位置p然后令p->Next指向ai的直接后件结点,即把ai从链上摘下最后释放结点ai的空间如图1-16所示图1-16线性表的删除示意图1.5.3 线性双向链表的结构及其基本运算1.5.3.1 什么是双向链表在单链表中,从某个结点出发可以直接找到它的直接后件,时间复杂度为O(1) ,但无法直接找到它的直接前件;在单循环链表中,从某个结点出发可以直接找到它的直接后件,时间复杂度仍为O(1),直接找到它的直接前件,时间复杂度为O(n)。

有时,希望能快速找到一个结点的直接前件,这时,可以在单链表中的结点中增加一个指针域指向它的直接前件,这样的链表,就称为双向链表(一个结点中含有两个指针)如果每条链构成一个循环链表,则会得到双向循环链表,如图1-17所示图1-17双向链表示意图1.5.3.2 双向链表的基本运算(1)插入在HEAD为头指针的双向链表中,在值为Y的结点之后插入值为X的结点,插入结点的指针变化,如图1-18所示(若改为在值为Y的结点之前插入值为X的结点,可以做类似分析) 图1-18 双向链表的插入(2)删除在以HEAD为头指针的双向链表中删除值为X的结点,删除算法的指针变化,如图1-19所示 图1-19 双向链表的删除1.5.4 循环链表的结构及其基本运算从单链表可知,最后一个结点的指针域为NULL,表示单链表已经结束如果将单链表最后一个结点的指针域改为存放链表中头结点(或第一个结点)的地址,就使得整个链表构成一个环,又没有增加额外的存储空间,如图1-20所示这样的链表称为循环链表 图1-20循环链表的逻辑结构 对单链表的访问是一种顺序访问,从其中某一个结点出发,只能找到它的直接后继(即后件),但无法找到它的直接前驱(即前件),而且对于空表和第一个结点的处理必须单独考虑,空表与非空表的操作不统一。

在循环链表中,只要指出表中任何一个结点的位置,就可以从它出发访问到表中其他所有的结点并且,由于表头结点是循环链表所固有的结点,因此,即使在表中没有数据元素的情况下,表中也至少有一个结点存在,从而使空表和非空表的运算统一1.6.2 二叉树的定义及其基本性质1.6.2.1 二叉树的定义二叉树是由n(n≥0)个结点的有限集合构成,此集合或者为空集,或者由一个根结点及两棵互不相交的左右子树组成,并且左右子树都是二叉树二叉树可以是空集合,根可以有空的左子树或空的右子树二叉树不是树的特殊情况,它们是两个概念二叉树具有以下两个特点:(1)非空二叉树只有一个根结点;(2)每一个结点最多有两棵子树,且分别称为该结点的左子树与右子树二叉树的每个结点最多有两个孩子,或者说,在二叉树中,不存在度大于2的结点,并且二叉树是有序树(树为无序树),其子树的顺序不能颠倒,因此,二叉树有5种不同的形态,如图1-26所示图1-26(a)表示空二叉树;图1-26(b)是仅有根结点的二叉树,即左子树和右子树都为空二叉树;图1-26(c)是左、右子树均非空的二叉树;图1-26(d)是左子树非空,右子树为空的 二叉树;图1-26(e)是右子树非空,左子树为空的二叉树。

在二叉树中,当一个非根结点的结点,既没有右子树,也没有左子树时,该结点即是叶子结点1.6.2.2 二叉树的基本性质二叉树具有以下几个性质:性质1:在二叉树的第k层上至多有2k-1(k≥1)个结点性质2:深度为m的二叉树至多有2m-1个结点深度为m的二叉树表示该二叉树共有m层根据性质1,只要将第1层到第m层上的最大的结点数相加,就可以得到整个二叉树中结点数的最大值,及21-1+22-1+…+2m-1=2m-1性质3: 对任何一棵二叉树,度为0的结点(即叶子结点)总是比度为2的结点多一个证明:设一棵非空二叉树中有n个结点,叶子结点个数为n0,度为1的结点个数为n1,度为2的结点个数为n2所以:n=n0+n1+n2 (1)在二叉树中,除根结点外,其余每个结点都有且仅有一个前件(直接前驱)和一条从其前件结点指向它的边假设边的总数为B,则二叉树中总的结点数为:n=B+1 (2)由于二叉树中的边都是由度为1和度为2的结点发出的所以有:B=n1+n2×2 (3)综合(1)、(2)、(3)式,可得:n0=n2 +1性质4: 具有n个结点的完全二叉树的深度至少为[log2n]+1,其中[log2n]表示log2n的整数部分。

1.6.2.3 满二叉树与完全二叉树满二叉树和完全二叉树是两种特殊形态的二叉树1)满二叉树满二叉树是指除最后一层外,每一层上的所有结点都有两个子结点即在满二叉树的第k层上有2k-1个结点从上面满二叉树定义可知,必须是二叉树每一层上的结点数都达到最大,否则就不是满二叉树深度为m的满二叉树有2m-1个结点图1-23是两棵满二叉树图1-23(a)是深度为3的满二叉树,图1-23(b)是深度为4的满二叉树 图1-23 满二叉树在满二叉树中,只有度为2和度为0的结点,没有度为1的结点所有度为0的结点即叶子结点都在同一层,即最后一层2)完全二叉树完全二叉树是指除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺少右边的若干结点完全二叉树也可以这样来描述:如果对满二叉树的结点进行连续编号,从根结点开始,对二叉树的结点自上而下,自左至右用自然数进行连续编号,则深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1到n的结点一一对应时,称之完全二叉树由完全二叉树可知,满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树图1-28(a)是深度为3的3棵完全二叉树,图1-28(b)是深度为4的一棵完全二叉树。

完全二叉树还具有以下两个性质:性质1:具有n个结点的完全二叉树深度为[log2n]+1性质2: 如果对一棵有n个结点的完全二叉树的结点按层序编号(从第1层到第[log2n]+1层,每层从左到右),则对任一结点k(1≤k≤n),有: ①如果k=1,则结点k父结点,是二叉树的根;如果k>1,则该结点的父结点编号为INT(k/2); ②如果2k≤n,则结点k的左子结点编号为2k;否则该结点没有左子结点(显然也没有右子结点); ③如果2k+1≤n,则结点k的右子结点编号为2k+1;否则该结点没有右子结点1.6.2.4 二叉树的存储结构在计算机中,二叉树通常采用链式存储结构用于存储二叉树中各元素的存储结点由两部分组成:数据域与指针域但在二叉树中,由于每一个元素可以有两个后件(两个子结点),因此,用于存储二叉树的存储结点的指针域有两个:一个用于指向该结点的左子结点的存储地址,称为左指针域;另一个用于指向该结点的右子结点的存储地址,称为右指针域如图1-29所示由于二叉树的存储结构中每一个存储结点有两个指针域,因此,二叉树的链式存储结构也称为二叉链表1.6.3 二叉树的遍历二叉树的遍历是指不重复地访问二叉树中的所有结点。

在遍历二叉树的过程中,一般先遍历左子树,再遍历右子树在先左后右的原则下,根据访问根结点的次序不同,二叉树的遍历可以分为3种:前序遍历、中序遍历、后序遍历1.前序遍历前序遍历中"前"的含义是:访问根结点在访问左子树和访问右子树之前即首先访问根结点,然后遍历左子树,最后遍历右子树;并且在遍历左子树和右子树时,仍然先访问根结点,然后遍历左子树,最后遍历右子树前序遍历可以描述为:若二叉树为空,则执行空操作;否则①访问根结点,②前序遍历左子树,③前序遍历右子树例如,对图1-30中的二叉树进行前序遍历的结果(或称为该二叉树的前序序列)为:A,B,D,H,E,I,C,F,G2.中序遍历中序遍历中"中"的含义是:访问根结点在访问左子树和访问右子树两者之间即首先遍历左子树,然后访问根结点,最后遍历右子树并且在遍历左子树和右子树时,仍然首先遍历左子树,然后访问根结点,最后遍历右子树中序遍历可以描述为:若二叉树为空,则执行空操作;否则①中序遍历左子树,②访问根结点,③中序遍历右子树例如,对图1-30中的二叉树进行中序遍历的结果(或称为该二叉树的中序序列)为:H,D,B,E,I,A,C,G,F3.后序遍历后序遍历中"后"的含义是:访问根结点在访问左子树和访问右子树之后。

即首先遍历左子树,然后遍历右子树,最后访问根结点;并且在遍历左子树和右子树时,仍然首先遍历左子树,然后遍历右子树,最后访问根结点后序遍历可以描述为:若二叉树为空,则执行空操作;否则①后序遍历左子树,②后序遍历右子树,③访问根结点例如,对图1-30中的二叉树进行后序遍历的结果(或称为该二叉树的后序序列)为:H,D,I,E,B,G,F,C,A1.7.1.1 顺序查找顺序查找(顺序搜索)是最简单的查找方法,它的基本思想是:从线性表的第一个元素开始,逐个将线性表中的元素与被查元素进行比较,如果相等,则查找成功,停止查找;若整个线性表扫描完毕,仍未找到与被查元素相等的元素,则表示线性表中没有要查找的元素,查找失败在进行顺序查找过程中,如果线性表中的第一个元素就是要查找的元素,则比较次数为1;如果最后一个元素才是要找的元素,或者性表中,没有要查找的元素,则需要与线性表中所有的元素比较,这是顺序查找的最坏情况在平均情况下,利用顺序查找法性表中查找一个元素,大约要与线性表中一半的元素进行比较由此可以看出,对于大的线性表来说,顺序查找的效率很低虽然顺序查找的效率不高,但在下列两种情况下也只能采用顺序查找:(1)如果线性表是无序表(即表中的元素是无序的),则不管是顺序存储结构还是链式存储结构,都只能用顺序查找。

2)即使是有序线性表,如果采用链式存储结构,也只能用顺序查找1.7.1.2 二分法查找二分法查找也称拆半查找,是一种高效的查找方法能使用二分法查找的线性表必须满足两个条件:●用顺序存储结构;●线性表是有序表在本书中,为了简化问题,而更方便讨论,"有序"是特指元素按非递减排列,即从小到大排列,但允许相邻元素相等下一节排序中,有序的含义也是如此对于长度为n的有序线性表,利用二分法查找元素X的过程如下将X与线性表的中间项比较:●如果X的值与中间项的值相等,则查找成功,结束查找;●如果X小于中间项的值,则性表的前半部分以二分法继续查找;●如果X大于中间项的值,则性表的后半部分以二分法继续查找例如,长度为8的线性表关键码序列为:[5,12,26,29,37,45,46,69],被查元素为37,首先将与线性表的中间项比较,即与第4个数据元素29相比较,37大于中间项29的值,则性表[37,45,46,69]继续查找;接着与中间项比较,即与第2个元素45相比较,37小于45,则性表[37]继续查找,最后一次比较相等,查找成功顺序查找法每一次比较,只将查找范围减少1,而二分法查找,每比较一次,可将查找范围减少为原来的一半,效率大大提高。

可以证明,对于长度为n的有序线性表,在最坏情况下,二分法查找只需比较log2n次,而顺序查找需要比较n次1.8.1.1 冒泡排序法冒泡排序法是最简单的一种交换类排序方法在数据元素的序列中,对于某个元素,如果其后存在一个元素小于它,则称之为存在一个逆序冒泡排序(Bubble Sort)的基本思想就是通过两两相邻数据元素之间的比较和交换,不断地消去逆序,直到所有数据元素有序为止冒泡排序法的基本过程如下:第一遍,性表中,从前往后扫描,如果相邻的两个数据元素,前面的元素大于后面的元素,则将它们交换,并称为消去了一个逆序在扫描过程中,线性表中最大的元素不断的往后移动,最后,被交换到了表的末端此时,该元素就已经排好序了然后对当前还未排好序的范围内的全部结点,从后往前扫描,如果相邻两个数据元素,后面的元素小于前面的元素,则将它们交换,也称为消去了一个逆序在扫描过程中,最小的元素不断地往前移动,最后,被换到了线性表的第一个位置,则认为该元素已经排好序了对还未排好序的范围内的全部结点,继续第二遍,第三遍的扫描,这样,未排好序的范围逐渐减小,最后为空,则线性表已经变为有序了图1-31是一个冒泡排序法的例子。

在最坏情况下,对长度为n的线性表排序,冒泡排序需要比较的次数为n(n-1)/21.8.1.2 快速排序法 在冒泡排序中,一次扫描只能确保最大的元素或最小的元素移到了正确位置,而未排序序列的长度可能只减少了1快速排序(Quick Sort)是对冒泡排序方法的一种本质的改进快速排序的基本思想是:在待排序的n个元素中取一个元素K(通常取第一个元素),以元素K作为分割标准,把所有小于K元素的数据元素都移到K前面,把所有大于K元素的数据元素都移到K后面这样,以K为分界线,把线性表分割为两个子表,这称为一趟排序然后,对K前后的两个子表分别重复上述过程继续下去,直到分割的子表的长度为1为止,这时,线性表已经是排好序的了第一趟快速排序的具体做法是:附设两个指针low和high,它们的初值分别指向线性表的第一个元素(K元素)和最后一个元素首先从high所指的位置向前扫描,找到第一个小于K元素的元素并与K元素互相交换然后从low所指位置起向后扫描,找到第一个大于K元素的数据元素并与K元素交换重复这两步,直到low=high为止图1-32是一个快速排序法的例子 快速排序的平均时间效率最佳,为O(nlog2n),最坏情况下,即每次划分,只得到一个子序列,时间效率为O(n2)。

1.8.2.1 简单选择排序法简单选择排序(Simple Selection Sort)的基本思想是:首先从所有n个待排序的数据元素中选择最小的元素,将该元素与第1个元素交换,再从剩下的n-1个元素中选出最小的元素与第2个元素交换重复这样的操作直到所有的元素有序为止对初始状态为(73,26,41,5,12,34)的序列进行简单选择排序过程如图1-33所示图中方括号"[ ]"内为有序的子表,方括号"[ ]"外为无序的子表,每次从无序子表中取出最小的一个元素加入到有序子表的末尾步骤如下:从这6个元素中选择最小的元素5,将5与第1个元素交换,得到有序序列[ 5 ];从剩下的5个元素中挑出最小的元素12,将12与第2个元素交换,得到有序列[ 5,12 ];从剩下的4个元素中挑出最小的元素26,将26与第3个元素交换,得到有序序列[ 5,12,26 ];依此类推,直到所以的元素都有序地排列到有序的子表中 简单选择排序法在最坏的情况下需要比较n(n-1)/2次1.8.2.2 堆排序法堆排序属于选择类的排序方法1)堆的定义若有n个元素的序列(h1,h2,…,hn),将元素按顺序组成一棵完全二叉树,当且仅当满足下列条件时称为堆。

其中,i=1,2,3,…,n/21)情况称为小根堆,所有结点的值小于或等于左右子结点的值2)情况称为大根堆,所有结点的值大于或等于左右子结点的值本节只讨论大根堆的情况例如,序列(91,85,53,36,47,30,24,12)是一个堆,则它对应的完全二叉树如图1-36所示2)调整建堆在调整建堆的过程中,总是将根结点值与左、右子树的根结点进行比较,若不满足堆的条件,则将左、右子树根结点值中的大者与根结点值进行交换,这个调整过程从根节点开始一直延伸到所有叶子结点,直到所有子树均为堆为止3)堆排序首先将一个无序序列建成堆,然后将堆顶元素与堆中的最后一个元素交换不考虑已经换到最后的那个元素,将剩下的n-1个元素重新调整为堆,重复执行此操作,直到所有元素有序为止对于数据元素较少的线性表来说,堆排序的优越性并不明显,但对于大量的数据元素来说,堆排序是很有效的在最坏情况下,堆排序法需要比较的次数为O(nlog2n)1.8.3.1 简单插入排序法简单插入排序是把n个待排序的元素看成是一个有序表和一个无序表,开始时,有序表只包含一个元素,而无序表包含另外n-1个元素,每次取无序表中的第一个元素插入到有序表中的正确位置,使之成为增加一个元素的新的有序表。

插入元素时,插入位置及其后的记录依次向后移动最后有序表的长度为n,而无序表为空,此时排序完成简单插入排序过程如图1-33所示 图中方括号"[ ]"内为有序的子表,方括号"[ ]"外为无序的子表,每次从无序子表中取出第一个元素插入到有序子表中 在最好情况下,即初始排序序列就是有序的情况下,简单插入排序的比较次数为n-1次,移动次数为0次在最坏情况下,即初始排序序列是逆序的情况下,比较次数为n(n-1)/2,移动次数为n(n-1)/2假设待排序的线性表中的各种排列出现的概率相同,可以证明,其平均比较次数和平均移动次数都约为n2/4,因此直接插入排序算法的时间复杂度为O(n2)在简单插入排序中,每一次比较后最多移掉一个逆序,因此,这种排序方法的效率与冒泡排序法相同2.1.2 良好的编程风格应注意的因素程序设计风格是指编写程序时所表现出来的特点、习惯和逻辑思路良好的程序设计风格可以使程序结构清晰合理,程序代码便于维护,因此,程序设计风格深深地影响着软件的质量和维护要形成良好的程序设计风格,主要应注意和考虑下述一些因素1)源程序的文档化源程序文档化是指在源程序中可包含一些内部文档,以帮助阅读和理解源程序。

①符号名的命名规则:符号名的命名应具有一定的实际含义,以便理解程序功能②程序注释:在源程序中添加正确的注释可帮助人们理解程序程序注释可分为序言性注释和功能性注释,以给出程序的整体说明和程序的主要功能③视觉组织:可以在程序中利用空格、空行、缩进等技巧使程序层次清晰2)数据说明的方法为使程序中的数据说明易于理解和维护,可采用下列数据说明的风格,见表2-1表2-1 数据说明风格数据说明风格详细说明次序应规范化使数据说明次序固定,使数据的属性容易查找,也有利于测试、排错和维护变量安排有序化当多个变量出现在同一个说明语句中时,变量名应按字母顺序排序,以便于查找使用注释在定义一个复杂的数据结构时,应通过注释来说明该数据结构的特点(3)语句的结构为使程序更简单易懂,语句构造应该简单直接,应注意如下原则:①在一行内只写一条语句;②程序编写应优先考虑清晰性;③程序编写要做到清晰第一,效率第二;④在保证程序正确的基础上再要求提高效率;⑤避免使用临时变量而使程序的可读性下降;⑥避免不必要的转移;⑦尽量使用库函数;⑧避免采用复杂的条件语句;⑨尽量减少使用"否定"条件语句;⑩数据结构要有利于程序的简化;⑩要模块化,使模块功能尽可能单一化;⑩利用信息隐蔽,确保每一个模块的独立性;⑩从数据出发去构造程序;⑩不要修补不好的程序,要重新编写。

4)输入输出输入输出方式和风格应尽可能方便用户的使用,应考虑如下原则:(1)对所有输入的数据都要检验数据的合法性;(2)检查输入项的各种重要组合的合理性;(3)输入格式要简单,使得输入的步骤和操作尽可能简单;(4)输入数据时,应允许使用自由格式;(5)应允许默认值;(6)输入一批数据时,最好使用输入结束标志;(7)在以交互式输入/输出方式进行输入时,要在屏幕上使用提示符明确提示输入的请求,同时在数据输入过程中和输入结束时,应在屏幕上给出状态信息;(8)当程序设计语言对输入格式有严格要求时,应保持输入格式与输入语句的一致性2.2.1 结构化程序设计的原则结构化程序设计方法的重要原则是自顶向下、逐步求精、模块化及限制使用goto语句1)自顶向下程序设计时,先考虑总体,后考虑细节;先考虑全局目标,后考虑局部目标2)逐步求精对复杂问题,应设计一些子目标做过渡,逐步细化3)模块化模块化是把程序要解决的总目标分解为分目标,再进一步分解为具体的小目标,把每个小目标称为一个模块4)限制使用goto语句2.2.2 结构化程序的基本结构与特点1966年,Boehm和Jacopini证明了程序设计语言仅仅使用顺序、选择和重复三种基本控制结构就足以表达出各种其他形式结构的程序设计方法。

它们的共同特征是:严格地只有一个入口和一个出口1)顺序结构顺序结构是指按照程序语句行的先后顺序,自始至终一条语句一条语句地顺序执行,它是最简单也是最常用的基本结构如图2-1所示,虚线框内就是一个顺序结构,在执行A中的运算后,必然执行B中的运算,然后执行C中的运算,没有分支,也没有转移和重复 (2)选择结构选择结构又称分支结构,简单选择结构和多分支选择结构都属于这类基本结构,这种结构可以根据设置的条件,判断应该选择哪一枝分支来执行相应的语句序列图2-2虚线框内是一个简单选择结构根据条件C判断,若成立则执行A中的运算,若不成立则执行B中的运算3)重复结构重复结构又称为循环结构,它根据给定的条件,判断是否需要重复执行某一相同的或类似的程序段在程序设计语言中,重复结构对应两类循环语句,对先判断后执行的循环体称为当型循环结构;对先执行循环体后判断的称为直到型循环结构,如图2-4所示总之,遵循结构化程序的设计原则,按结构化程序设计方法设计出的程序具有明显的优点:●程序易于理解、使用和维护;●提高了编程工作的效率,降低了软件开发成本2.3.2 面向对象方法的基本概念关于面向对象方法,对其概念有许多不同的看法和定义,但是都涵盖对象及对象属性与方法、类、继承、多态性几个基本要素。

2.3.2.1 对象对象是面向对象方法中最基本的概念对象可以用来表示客观世界中的任何实体,也就是说,应用领域中有意义的、与所要解决的问题有关系的任何事物都可以作为对象总之,对象是对问题域中某个实体的抽象例如,书本、课桌、老师、电脑等都可以看做一个对象面向对象的程序设计方法中涉及的对象是系统中用来描述客观事物的一个实体,是构成系统的一个基本单位,它由一组表示其静态特征的属性和它可执行的一组操作组成客观世界中的实体通常既具有静态的属性,又具有动态的行为,因此,面向对象方法学中的对象是由描述该对象属性的数据以及可以对这些数据施加的操作封装在一起构成的统一体对象可以执行的操作表示它的动态行为属性即对象所包含的信息,它在设计对象时确定,一般只能通过执行对象的操作来改变操作描述了对象执行的功能,若通过信息的传递,还可以为其他对象使用对象具有如下特点:①标识唯一性:指对象是可区分的,并且由对象的内在本质来区分,而不是通过描述来区分;②分类性:指可以将具有相同属性和操作的对象抽象成类;③多态性:指同一个操作可以是不同对象的行为;③封装性:从外面看只能看到对象的外部特征,而不知道也无需知道数据的具体结构以及实现操作的算法;⑤模块独立性好:对象是面向对象的软件的基本模块,对象内部各种元素彼此结合得很紧密,内聚性强。

2.3.2.2 类和实例类是具有共同属性、共同方法的对象的集合,是关于对象的抽象描述,反映属于该对象类型的所有对象的性质一个具体对象则是其对应类的一个实例要注意的是:"实例"这个术语,必然是指一个具体的对象"对象"这个术语,则既可以指一个具体的对象,也可以泛指一般的对象因此,在使用"实例"这个术语的地方,都可以用"对象"来代替,而使用"对象"这个术语的地方,则不一定能用"实例"来代替例如,"大学生"是一个大学生类,它描述了所有大学生的性质因此,任何大学生都是类"大学生"的一个对象(这里的"对象"不可以用"实例"来代替),而一个具体的大学生"张三"是类"大学生"的一个实例类是关于对象性质的描述,它同对象一样,包括一组数据属性和在数据上的一组合法操作2.3.2.3 消息消息传递是对象间通信的手段,一个对象通过向另一对象发送消息来请求其服务消息机制统一了数据流和控制流消息的使用类似于函数调用通常一个消息由下述3部分组成:●接收消息的对象名称;●消息选择符(也称为消息名);●零个或多个参数消息只告诉接收对象需要完成什么操作,但并不指示怎样完成操作消息完全由接收者解释,独立决定采用什么方法来完成所需的操作。

一个对象能够接收不同形式、不同内容的多个消息;相同形式的消息可以送往不同的对象,不同的对象对于形式相同的消息可以有不同的解释,能够作出不同的反应一个对象可以同时往多个对象传递消息,两个对象也可以同时向某一个对象传递消息消息传递如图2-4所示2.3.2.4 继承继承是面向对象的一个主要特征继承是使用已有的类定义作为基础建立新类的技术已有的类可当作基类来应用,则新类相应地可当作派生类来引用广义地说,继承是指能够直接获得已有的性质和特征,而不必重复定义它们例如,"四边形"类是"矩形"类的父类,"四边形"类可以有"顶点坐标"等属性,有"移动"、"旋转"、"求周长"等操作而"矩形"类除了继承"四边形"类的属性和操作外,还可定义自己的属性和操作,"长"、"宽"等属性和"求面积"等操作继承具有传递性,如果类Z继承类Y,类Y继承类X,则类Z继承类X因此,一个类实际上继承了它上层的全部基类的特性,也就是说,属于某类的对象除了具有该类定义的特性外,还具有该类上层全部基类定义的特性继承分为单继承与多重继承单继承是指一个类只允许有一个父类,即类等价为树型结构多重继承是指一个类允许有多个父类多重继承的类可以组合多个父类的性质构成所需要的性质。

继承的优点是:相似的对象可以共享程序代码和数据结构,从而大大减少了程序中的冗余信息,提高软件的可重用性,便于软件修改维护另外,继承性使得用户在开发新的应用系统时不必完全从零开始,可以继承原有的相似系统的功能或者从类库中选取需要的类,再派生出新的类以实现所需的功能2.3.2.5 多态性对象根据所接收的消息而做出动作,同样的消息被不同的对象接收时可导致完全不同的行为,该现象称为多态性在面向对象的软件技术中,多态性是指子类对象可以像父类对象那样使用,同样的消息既可以发送给父类对象也可以发送给子类对象例如,在一般类polygon(多边形)中定义了一个方法 "Show" 显示自身,但并不确定执行时到底画一个什么图形特殊类square和类rectangle都继承了polygon类的显示操作,但其实现的结果却不同,把名为Show的消息发送给一个rectangle类的对象是在屏幕上画矩形,而将同样消息名的消息发送给一个square类的对象则是在屏幕上画一个正方形如图2-6所示,这就是多态性的表现多态性机制不仅增强了面向对象软件系统的灵活性,进一步减少了信息冗余,而且显著提高了软件的可重用性和可扩充性3.1.1.1 软件的定义计算机软件由两部分组成。

●一是机器可执行的程序和数据;●二是机器不可执行的,与软件开发、运行、维护、使用等有关的文档软件的构成见表3-1计算机软件是由程序、数据及相关文档构成的完整集合,它与计算机硬件一起组成计算机系统表3-1 计算机软件各组成部分的含义概念含 义软件程序、数据和文档程序软件开发人员依据用户需求开发的,用某种程序设计语言描述的,能够在计算机中执行的语句序列数据使程序能够正常操纵信息的数据结构文档与程序开发、维护和使用有关的资料我国国家标准(简称国标,GB)中对计算机软件(Software)完整的定义是: 与计算机系统操作有关的计算机程序、规程、规则,以及可能有的文件、文档及数据3.1.1.3 软件的分类计算机软件按功能分为系统软件、应用软件、支撑软件(或工具软件)系统软件是管理计算机的资源,提高计算机的使用效率,为用户提供各种服务的软件例如,操作系统(OS)、数据库管理系统(DBMS)、编译程序、汇编程序和网络软件等系统软件是最靠近计算机硬件的软件应用软件为了应用于特定的领域而开发的软件例如,我们熟悉的Word 2003、Winamp、和Flashget等软件属于应用软件。

支撑软件是介于系统软件和应用软件之间,协助用户开发软件的工具型软件,其中包括帮助程序人员开发和维护软件产品的工具软件,也包括帮助管理人员控制开发进程和项目管理的工具软件例如,Dephi、PowerBuilder等3.1.2.2 软件危机随着计算机软件规模的扩大,软件本身的复杂性不断增加,研制周期显著变长,正确性难以保证,软件开发费用上涨,生产效率急剧下降,从而出现了人们难以控制软件发展的局面,即所谓的"软件危机"软件危机主要表现在:(1)软件需求的增长得不到满足;(2)软件开发成本和进度无法控制;(3)软件质量难以保证;(4)软件不可维护或维护程度非常低;(5)软件成本不断提高;(6)软件开发生产效率的提高赶不上硬件的发展和应用需求的增长总之,可以将软件危机归结为成本、质量和生产率等问题3.1.2.3 软件工程的产生为了摆脱软件危机,北大西洋公约组织成员国软件工作者于1968年和1969年两次召开会议(NATO会议),认识早期软件开发中所存在的问题和产生问题的原因,提出软件工程的概念国标(GB) 中指出软件工程是应用于计算机软件的定义、开发和维护的一整套方法、工具、文档、实践标准和工序。

软件工程包括3个要素,即方法、工具和过程方法是完成软件工程项目的技术手段;工具支持软件的开发、管理、文档生成;过程支持软件开发的各个环节的控制、管理自软件工程概念的提出,该研究领域吸引了众多的学者,并开展了大量的理论和技术的研究,形成了"软件工程学"这一计算机科学中的分支它所包含的内容。

下载提示
相关文档
正为您匹配相似的精品文档