408计算机学科专业基础综合——数据结构

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_31790817/article/details/83926832

第1章 绪论

1.1 数据结构的基本概念

数据元是数据的基本单位,一个数据元素可由若干个数据项完成,数据项是构成数据元素的不可分割的最小单位。例如,学生记录就是一个数据元素,它由学号、姓名、性别等数据项组成。

数据对象是具有相同性质的数据元素的集合,是数据的一个子集。

数据类型是一个值的集合和定义在此集合上一组操作的总称。

  • 原子类型:其值不可再分的数据类型
  • 结构类型:其值可以再分解为若干成分(分量)的数据类型
  • 抽象数据类型:抽象数据组织和与之相关的操作

抽象数据类型(ADT)是指一个数学模型以及定义在该模型上的一组操作。抽象数据类型的定义仅取决于它的一组逻辑特性,而与其在计算机内部如何表示和实现无关。通常用(数据对象、数据关系、基本操作集)这样的三元组来表示。

数据结构的三要素:

  1. 逻辑结构是指数据元素之间的逻辑关系,即从逻辑关系上描述数据,独立于计算机。分为线性结构和非线性结构,线性表、栈、队列属于线性结构,树、图、集合属于非线性结构。
  2. 存储结构是指数据结构在计算机中的表示(又称映像),也称物理结构,包括数据元素的表示和关系的表示,依赖于计算机语言,分为顺序存储(随机存取)、链式存储(无碎片)、索引存储(检索速度快)、散列存储(检索、增加、删除快)。
  3. 数据的运算:包括运算的定义和实现。运算的定义是针对逻辑结构的,指出运算的功能;运算的实现是针对存储结构的,指出运算的具体操作步骤。

选择题

1.可以用(抽象数据类型)定义一个完整的数据结构。

3.以下属于逻辑结构的是(有序表)
A 顺序表 B 哈希表 C 有序表 D 单链表

4.以下与数据的存储结构无关的术语是(栈)
A 循环队列 B 链表 C 哈希表 D 栈

6.在存储数据时,通常不仅要存储各数据元素的值,还要存储(数据元素之间的关系)

7.链式存储设计时,结点内的存储单元地址(一定连续),不同结点间可以(不连续)

1.2 算法和算法评价

算法是对特定问题求解步骤的一种描述,有五个特性:有穷性、确定性、可行性、输入、输出。一个算法有零个或多个的输入,有一个或多个的输出

时间复杂度是指该语句在算法中被重复执行的次数,不仅依赖于问题的规模n,也取决于待输入数据的性质。

空间复杂度定义为该算法所耗费的存储空间。算法原地工作是指算法所需辅助空间是常量,即O(1)。

第2章 线性表

2.1 线性表的定义和基本操作

线性表是具有相同数据类型的n个数据元素有限序列。除第一个元素外,每个元素有且仅有一个直接前驱;除最后一个元素外,每个元素有且仅有一个直接后继。

注意:线性表是一种逻辑结构,表示元素之间一对一的相邻关系。顺序表和链表是指存储结构。两者属于不同层面的概念,因此不要混淆。

选择题

2.以下(由100个字符组成的序列)是一个线性表。
A 由n个实数组成的集合 B 由100个字符组成的序列
C 所有整数组成的序列(无穷) D 邻接表(存储结构)

2.2 线性表的顺序表示

线性表的顺序存储又称为顺序表。它是用一组地址连续的存储单元,依次存储线性表中的数据元素,从而使得逻辑上相邻的两个元素在物理位置上也相邻。

顺序表的特点是表中元素的逻辑顺序与其物理顺序相同。
顺序表最主要的特点是随机访问(随机存取),即通过首地址和元素序号可以在O(1)的时间内找到指定的元素。但插入和删除操作需要移动大量元素
顺序表的存储密度高,每个结点只存储数据元素。

顺序表插入操作:
最好情况:在表尾插入,元素后移语句不执行,时间复杂度为O(1)
最坏情况:在表头插入,元素后移语句将执行n次,时间复杂度为O(n)
平均情况:平均时间复杂度为O(n)

顺序表删除操作:
最好情况:删除表尾元素,无需移动元素,时间复杂度为O(1)
最坏情况:删除表头元素,需要移动除第一个元素外的所有元素,时间复杂度为O(n)
平均情况:平均时间复杂度为O(n)

顺序表按值查找(顺序查找):
最好情况:查找的元素就在表头,仅需比较一次,时间复杂度为O(1)
最坏情况:查找的元素在表尾或不存在时,需要比较n次,时间复杂度为O(n)
平均情况:平均时间复杂度为O(n)

选择题

4.若线性表最常用的操作是存取第i个元素及其前驱和后继元素的值,为了提高效率,应采用(顺序表)的存储方式。

5.一个线性表最常用的操作是存取任一指定序号的元素和在最后进行插入删除操作,则利用(顺序表)存储方式可以节省时间。

10.若长度为n的非空线性表采用顺序存储结构,在表的第i个位置插入一个数据元素,i的合法值应该是(1 ≤ i ≤ n+1)

2.3 线性表的链式表示

链式存储线性表时,不需要使用地址连续的存储单元,即它不要求逻辑上相邻的两个元素在物理位置上也相邻,对线性表的插入和删除不需要移动元素,只需要修改指针。

单链表是非随机存储的存储结构,即不能直接找到表中某个特定的结点。

头结点和头指针的区分:不管带不带头结点,头指针始终指向链表的第一个结点,而头结点是带头结点链表中的第一个结点,结点内通常不存储信息。

采用头插法建立单链表:从一个空表开始,生成新结点,并将读取到的数据存放在新结点的数据域中,然后将新结点插入到当前链表的表头,即头结点之后。
读入数据的顺序与生成的链表中元素的顺序是相反的。
每个结点插入的时间为O(1),设单链表长为n,则总的时间复杂度为O(n)。

采用尾插法建立单链表:将新结点插入到当前链表的表尾上,为此必须增加一个尾指针r,使其始终指向当前链表的尾结点。
时间复杂度和头插法相同。

按序号查找结点值:在单链表中从第一个结点出发,顺指针next域逐个往下搜索,直到找到第i个结点为止,否则返回最后一个结点指针域NULL。
时间复杂度为O(n)。

按值查找表结点:从单链表第一个结点出发,由前往后依次比较表中各结点数据域的值,若某结点数据域的值等于给定值e,则返回该结点的指针,否则返回NULL。
时间复杂度为O(n)。

插入结点操作:先检查插入位置的合法性,然后找到待插入位置的前驱结点,即第i-1个结点,再在其后插入新结点。
主要的时间开销在于查找第i-1个元素,时间复杂度为O(n)。若是在给定的结点后面插入新结点,则时间复杂度仅为O(1)。

删除结点操作:先检查删除位置的合法性,然后找到待删除位置的前驱结点,即第i-1个结点,再将其删除。
时间复杂度为O(n)。

双链表结点中有两个指针prior和next,分别指向其前驱结点和后继结点。双链表中执行按值查找和按位查找的操作和单链表相同,但双链表插入、删除操作的时间复杂度仅为O(1)。

循环单链表和单链表的区别在于,表中最后一个结点的指针不是NULL,而改为指向头结点,从而整个链表形成一个环。故表中没有指针域为NULL的结点。
循环双链表 L中,某结点*p为尾结点时,p->next=L;当循环双链表为空表时,其头结点的prior域和next域都等于L。

静态链表是借助数组来描述线性表的链式存储结构,结点也有数据域data和指针域next,这里的指针是结点的相对地址(数组下标),又称为游标。

顺序表和链表的比较:

  1. 存取方式:顺序表可以顺序存取,也可以随机存取,链表只能从表头顺序存取元素。
  2. 逻辑结构与物理结构:采用顺序存储时,逻辑上相邻的元素,其对应的物理存储位置也相邻。而采用链式存储时,逻辑上相邻的元素,其物理存储位置则不一定相邻。
  3. 查找、插入和删除操作:对于按值查找,当顺序表在无序的情况下,两者的时间复杂度均为O(n);而当顺序表有序时,可采用折半查找,时间复杂度为O(logn)。对于按序号查找,顺序表支持随机访问,时间复杂度仅为O(1),而链表的平均时间复杂度为O(n)。链表插入、删除较优,只需修改相关结点的指针域即可。
  4. 空间分配:链式存储的结点空间只在需要的时候申请分配。
  5. 通常较稳定的线性表选择顺序存储,而频繁做插入、删除操作的线性表(即动态性较强)宜选择链式存储。

选择题

2.对于一个线性表即要求能够进行较快速地插入和删除,又要求存储结构能反映数据之间的逻辑关系,则应该用链式存储方式。

4.下列关于线性表说法正确的是(D)
I. 顺序存储方式只能用于存储线性结构(同样适合图和树的存储,如满二叉树的顺序存储)
II. 取线性表的第i个元素的时间与i的大小有关(无关,顺序存储)
III. 静态链表需要分配较大的连续空间,插入和删除不需要移动元素
IV. 在一个长度为n的有序单链表中插入一个新结点并仍保持有序的时间复杂度为O(n)
V. 若用单链表来表示队列,则应该选用带尾指针的循环链表
A I、II B I、III、IV、V C IV、V D III、IV、V

7.给定有n个元素的一维数组,建立一个有序单链表的最低时间复杂度是(O(nlogn))

8.将长度为n的单链表链接在长度为m的单链表后面,其算法的时间复杂度为O(m)

9.单链表中,增加一个头结点的目的是为了(方便运算的实现)。

10.在一个长度为n的带头结点的单链表h上,设有尾指针r,则执行(删除单链表中最后一个元素)操作与链表的表长有关。

11.对于一个头指针为head的带头结点的单链表,判定该表为空表的条件是(head->next==NULL);对于不带头结点的单链表,则判定空表的条件是(head == NULL)

13.某线性表中最常见的操作是在最后一个元素之后插入一个元素和删除第一个元素,则采用(仅有尾指针的单循环链表)存储方式最省时间。

18.与单链表相比,双链表的优点之一是(访问前后相邻结点更灵活)。

19.带空结点的双循环链表L为空的条件是(L->prior==L && L->next == L)

20.一个链表最常用的操作是在末尾插入结点和删除结点,则选用(带头结点的双循环链表)最节省时间。

21.设对n个元素的线性表的运算只有4种:删除第一个元素;删除最后一个元素;在第一个元素之前插入新元素;在最后一个元素之后插入新元素,则最好使用(只有头结点指针没有尾结点指针的循环双链表)。

22.一个链表最常用的操作是在最后一个元素之后插入一个元素和删除第一个元素,则选用(不带头结点且有尾指针的单循环链表)最节省时间。

25.需要分配较大的空间,插入和删除不需要移动元素的线性表,其存储结构为(静态链表)。

第3章 栈和队列

3.1 栈

栈:后进先出(LIFO),又称为后进先出的线性表

顺序栈的实现:
栈顶指针:S.top,初始时设置S.top=-1栈顶元素:S.data[S.top]。
进栈操作:栈不满时,栈顶指针先加1,再送值到栈顶元素。S.data[++S.top]=x
出栈操作:栈非空时,先取栈顶元素值,再将栈顶指针减1。x=S.data[S.top–]
栈空条件:S.top==-1;栈满条件:S.top==Maxsize-1;栈长:S.top+1

注意:如果栈顶指针初始化为S.top=0,即栈顶指针指向栈顶元素的下一个位置,则入栈操作变为S.data[S.top++]=x;出栈操作变为x=S.data[–S.top]。相应的栈空、栈满条件也会发生变化。

共享栈:利用栈底位置相对不变的特性,可以让两个顺序栈共享一个一维数据空间,将两个栈的栈底分别设置在共享空间的两端,两个栈顶向共享空间的中间延伸。
两个栈的栈顶指针都指向栈顶元素,top0=-1时0号栈为空,top1=Maxsize时1号栈为空;仅当两个栈顶指针相邻(top1-top0=1)时,判断为栈满当0号栈进栈时top0先加1再赋值,1号栈进栈时top1先减1再赋值;出栈时刚好相反,0号栈先出栈再减1,1号栈先出栈再加1.
共享栈是为了更有效地利用存储空间,其存取数据的时间复杂度均为O(1)。

链栈的优点是便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。通常采用单链表实现,并规定所有操作都是在单链表的表头进行的。这里规定链栈没有头结点,Lhead指向栈顶元素。
采用链式存储,便于结点的插入和删除。对于带头结点和不带头结点的链栈,在具体的实现方面有所不同。

选择题

1.栈和队列具有相同的(逻辑结构)。

2.栈是(限制存取点的线性结构)。
A 顺序存储的线性结构(还有链栈,非顺序存储) B 链式存储的非线性结构
C 限制存取点的线性结构 D限制存取点的非线性结构(栈肯定是线性结构)

7.设链表不带头结点且所有操作均在表头进行,则下列最不适合作为链栈的是(只有表头结点指针,没有表尾指针的单向循环链表)。

11.3个不同的元素依次进栈,能得到(5)中不同的出栈序列。1/(n+1) * ((2n)!/(n!*n!))

26.采用共享栈的好处是(节省存储空间,降低发生上溢的可能)。

27.下列关于栈的叙述中,错误的是(I、III、IV)
I. 采用非递归方式重写递归程序时必须使用栈(反例:斐波那契数列一个循环即可)
II. 函数调用时,系统要用栈保存必要的信息
III. 只要确定了入栈次序,即可确定出栈次序(不确定)
IV. 栈是一种受限的线性表,允许在其两端进行操作(一端而已,栈顶)

3.2 队列

队列也是一种操作受限的线性表,只允许在表的一端进行插入,而在表的另一端进行删除。(先进先出的线性表)

队列的顺序实现是指分配一块连续的存储单元存放队列中的元素,并附设两个指针front和rear分别指示队头元素和队尾元素的位置。设队头指针指向队头元素,队尾指针指向队尾元素的下一个位置(也可以让rear指向队尾元素,front指向队头元素的前一个位置)。
初始状态(队空条件):Q.front==Q.rear == 0.
进队操作:队不满时,先送值到队尾元素,再将队尾指针加1。
出队操作:队不空时,先取队头元素值,再将队头指针加1.

循环队列,即把存储队列元素的表从逻辑上看成一个环。
初始时:Q.front==Q.rear == 0.
出队:队首指针进1,Q.front=(Q.front+1)%MaxSize
入队:队尾指针进1,Q.rear=(Q.rear+1)%MaxSize
队列长度:(Q.rear+MaxSize-Q.front)%MaxSize
出队入队时:指针都按顺时针方向进1.

为了区分队空还是队满的情况,有三种处理方式:
1)牺牲一个单元来区分队空和队满,队头指针在队尾指针的下一位置作为队满的标志:
队满条件为:(Q.rear+1)%MaxSize == Q.front
队空条件仍为:Q.front==Q.rear
队列中元素的个数:(Q.rear-Q.front+MaxSize)%MaxSize

2)类型中增设表示元素个数的数据成员:
队空条件为:Q.size== 0
队满条件为:Q.size == Maxsize
3)类型中增设tag数据成员,以区分是队满还是队空。

队列的链式表示称为链队列,是一个同时带有队头指针和队尾指针的单链表。头指针指向队头结点,尾指针指向队尾结点,即单链表的最后一个结点。
当Q.front==NULL && Q.rear == NULL时,链式队列为空。

双端队列是指允许两端都可以进行入队和出队操作的队列,其元素的逻辑结构仍是线性结构。
输出受限的双端队列:允许在一端进行插入和删除,但在另一端只允许插入。
输入受限的双端队列:允许在一端进行插入和删除,但在另一端只允许删除。

设有一个双端队列,输入序列为1,2,3,4:
(1)能由输入受限的双端队列得到,但不能由输出受限的双端队列得到的输出序列是4,1,3,2
(2)能由输出受限的双端队列得到,但不能由输入受限的双端队列得到的输出序列是4,2,1,3
(3)既不能由输入受限的双端队列得到,又不能由输出受限的双端队列得到的输出序列是4,2,3,1

选择题

11.最适合用做链队的链表是(带队首指针和队尾指针的非循环单链表)。

12.最不适合用做链式队列的链表是(只带队首指针的非循环双链表)。

13.在用单链表实现队列时,队头在链表的(链头)位置。

14.用链式存储方式的队列进行删除操作时需要(头尾指针可能都要修改)

15.在一个链队列中,假设队头指针为front,队尾指针为rear,x所指向的元素需要入队,则需要执行的操作为(rear->next=x, x->next=null, rear=x)

16.假设循环单链表表示的队列长度为n,队头固定在链表表尾,若只设头指针,则进队操作的时间复杂度为(O(n))

栈和队列的应用

栈的应用:括号匹配、表达式求值、递归
队列的应用:层次遍历、计算机系统

选择题

9.执行(广度优先搜索图)操作时,需要使用队列作为辅助存储空间。

3.4 特殊矩阵的压缩存储

数组是由n个相同类型的数据元素构成的有限序列。

数组的存储结构:
一维数组
多维数组:按行优先和按列优先

矩阵的压缩存储:
对称矩阵、上(下)三角矩阵、对角矩阵

对称矩阵:将对称矩阵A[1…n][1…n]存放在一维数组B[n(n+1)/2]中,只存放主对角线和下三角区的元素。元素下标之间的对应关系如下(数组下标从0开始):
k=i(i-1)/2+j-1(当i≥j,即下三角区和主对角线元素)
k=j(j-1)/2+i-1(当i<j,即上三角区元素)

三角矩阵
下三角矩阵A[1…n][1…n]存放在一维数组B[n(n+1)/2+1]中,存储下三角区和主对角线上的元素,以及存储对角线上方的常量一次。元素下标之间的对应关系如下(数组下标从0开始):
k=i(i-1)/2+j-1(当i≥j,即下三角区和主对角线元素)
k=n(n+1)/2(当i<j,即上三角区元素)

上三角矩阵A[1…n][1…n]存放在一维数组B[n(n+1)/2+1]中,存储上三角区和主对角线上的元素,以及存储对角线下方的常量一次。元素下标之间的对应关系如下(数组下标从0开始):
k=(i-1)(2n-i+2)/2+(j-i)(当i≤j,即上三角区和主对角线元素)
k=n(n+1)/2(当i>j,即下三角区元素)

三对角矩阵:三对角矩阵3条对角线上的元素Ai,j在一维数组B中存放的下标为k=2i+j-3;反之,若已知三对角矩阵中某元素Ai,j在一维数组B中存放于第k个位置,则可求得i=(k+1)/3+1(向下取整),j=k-2i+3.

稀疏矩阵:将非零元素及其相应的行和列构成一个三元组(行标,列标,值)。

选择题

注意:数组下标从0开始还是从1开始,按列优先存储还是按行优先存储

9.适用于压缩存储稀疏矩阵的两种存储结构是(三元组表和十字链表

第4章 树与二叉树

4.1 树的基本概念

树是N个结点的有限集合,N=0时,称为空树。
树中一个结点的子结点个数称为该结点的度,树中结点的最大度数称为树的度
结点的层次从树根开始定义,根结点为第1层
结点的深度是从根结点开始自顶向下逐层累加的;结点的高度时从叶结点开始自底向上逐层累加的。
树的高度(又称深度)是树中结点的最大层数。
树中两个结点之间的路径是由这两个结点之间所经过的结点序列构成的,而路径长度是路径上所经过的边的个数

树的性质:
1)树中的结点数等于所有结点的度数加1.
2)度为m的树中第i层上至多有m^(i-1)个结点(i≥1)。
3)高度为h的m叉树至多有(m^h-1)/(m-1)个结点。
4)具有n个结点的m叉树的最小高度为logm (n(m-1)+1)向上取整。

选择题

1.树最适合用来表示(元素之间具有分支层次关系)的数据。

3.树的路径长度是从树根到每一结点的路径长度的(总和)。

4.2 二叉树的概念

二叉树:每个结点至多只有两棵子树(即二叉树不存在度大于2的结点),子树有左右之分,不能任意颠倒次序。

满二叉树:一棵高度为h,并且含有2^h-1个结点的二叉树称为满二叉树,即树中的每一层都含有最多的结点,除叶子结点之外的每个结点度数均为2.对于编号为i的结点,如果有双亲,其双亲为i/2(向下取整),如果有左孩子,则左孩子为2i,如果有右孩子,则右孩子为2i+1.

完全二叉树:设一个高度为h,有n个结点的二叉树,当且仅当其每一个结点都与高度为h的满二叉树中编号为1~n的结点一一对应时,称为完全二叉树。
1)若i≤n/2(向下取整),则结点i为分支结点,否则为叶子结点。
2)叶子结点只可能在层次最大的两层上出现。对于最大层次中的叶子结点,都依次排列在该层最左边的位置上。
3)如果有度为1的结点,只可能有一个,且该结点只有左孩子而无右孩子。
4)若n为奇数,则每个分支结点都有左子女和右子女;若n为偶数,则编号最大的分支结点(编号为n/2)只有左子女,没有右子女,其余分支结点左右子女都有。

二叉排序树:左子树上所有结点的关键字均小于根结点的关键字,右子树上所有结点的关键字均大于根结点的关键字。

平衡二叉树:树上任一结点的左子树和右子树的深度之差不超过1.

二叉树的性质:
1)非空二叉树上叶子结点等于度为2的结点数加1,即N0=N2+1
2)非空二叉树上第k层上至多有2^(k-1)个结点
3)高度为H的二叉树至多有2^H-1个结点
4)对完全二叉树按从上到下、从左到右的顺序依次编号1~N,则有以下关系:
a. 当i>1时,结点i的双亲结点编号为i/2(向下取整)
b. 当2i≤N时,结点i的左孩子编号为2i,否则无左孩子
c. 当2i+1小于等于N时,结点i的右孩子编号为2i+1,否则无右孩子。
d. 结点i所在层次(深度)为log2 i(向下取整)+1
5)具有N个结点的完全二叉树的高度为log2 (N+1)(向上取整)或log2 N(向下取整)+1

二叉树的顺序存储结构就是用一组地址连续的存储单元依次自上而下、自左至右存储完全二叉树上的结点元素。
完全二叉树和满二叉树采用顺序存储比较合适。
注意:二叉树属于树,都可以用树的存储结构来存储,但是树却不都能用二叉树的存储结构来存储。

二叉树的链式存储结构:链式结构是指用一个链表来存储一棵二叉树,二叉树中每一个结点用链表的一个链结点来存储。二叉链表至少包含三个域:数据域data、左指针域lchild、右指针域rchild。
在含有n个结点的二叉链表中含有n+1个空链域。

4.3 二叉树的遍历和线索二叉树

先序遍历PreOrder:访问根结点,先序遍历左子树,先序遍历右子树
中序遍历InOrder:中序遍历左子树,访问根结点,中序遍历右子树
后序遍历PostOrder:后序遍历左子树,后序遍历右子树,访问根结点
时间复杂度均为O(n),在递归遍历中,递归工作栈的栈深恰好为树的高度。

层次遍历:需要借助一个队列。先将二叉树根结点入队,然后出队,访问该结点,如果它有左子树,则将左子树根结点入队;如果它有右子树,则将右子树根结点入队。然后出队,对出队结点访问,如此反复,直到队列为空。

由二叉树的先序序列和中序序列可以唯一确定一棵二叉树;
由二叉树的后序序列和中序序列可以唯一确定一棵二叉树;
由二叉树的层序序列和中序序列可以唯一确定一棵二叉树。
如果只知道二叉树的先序序列和后序序列,则无法确定一棵二叉树。

线索二叉树:为了加快查找结点前驱和后继的速度。
二叉树线索化时,通常规定:若无左子树,令lchild指向其前驱结点;若无右子树,令rchild指向其后继结点,还需要增加那个标志域表明当前指针域所指对象时指向左(右)子结点还是直接前驱(后继)。
ltag=0(lchild域指示结点的左孩子)
ltag=1(lchild域指示结点的前驱)
rtag=0(rchild域指示结点的右孩子)
rtag=1(rchild域指示结点的后继)

选择题

22.引入线索二叉树的目的是(加快查找结点的前驱和后继的速度)。

23.线索二叉树是一种(物理)结构。

24.n个结点的线索二叉树上含有的线索数为(n+1)

29.二叉树在线索化后,仍不能有效求解的问题是(后序线索二叉树中求后序后继)
A 先序线索二叉树中求先序后继
B 中序线索二叉树中求中序后继
C 中序线索二叉树中求中序前驱
D 后序线索二叉树中求后序后继

31.(后序线索树)的遍历仍需要栈的支持
A 前序线索树 B 中序线索树 C 后序线索树 D 所有线索树

34.先序序列为a,b,c,d的不同二叉树的个数是(14)(1/(n+1) * (2n!)/(n!*n!))

4.4 树、森林

树的存储结构:既可以采用顺序存储结构,也可以采用链式存储结构

双亲表示法:采用一组连续空间来存储每个结点,同时在每个结点中增设一个伪指针,指示其双亲结点在数组中的位置。
利用了每个结点(根结点除外)只有唯一双亲的性质,可以很快得到每个结点的双亲结点,但是求结点的孩子时需要遍历整个结构。

孩子表示法:将每个结点的孩子结点都用单链表链接起来形成一个线性结构,则N个结点就有N个孩子链表(叶子结点的孩子链表为空表)。
寻找子女的操作非常直接,而寻找双亲的操作需要遍历N个结点中孩子链表指针域所指向的N个孩子链表。

孩子兄弟表示法:又称为二叉树表示法,即以二叉树表作为树的存储结构,使每个结点包括三部分内容:结点值、指向结点第一个孩子结点的指针和指向结点下一个兄弟结点的指针(沿此域可以找到结点的所有兄弟结点)。
可以方便地实现树转换为二叉树的操作,易于查找结点的孩子等,但缺点是从当前结点查找其双亲结点比较麻烦。

给定一棵树,可以找到唯一的一棵二叉树与之对应。

树转换为二叉树的规则:每个结点左指针指向它的第一个孩子结点,右指针指向它在树中的相邻兄弟结点,可表示为“左孩子右兄弟”。由于根结点没有兄弟,所以由树转换而得的二叉树没有右子树。

森林转换为二叉树的规则与树相似。

二叉树转换为森林的规则:若二叉树非空,则二叉树根及其左子树为第一棵树的二叉树形式,二叉树根的右子树又可以看做是一个由除第一棵树外的森林转换后的二叉树,应用同样的方法,直到最后产生一棵没有右子树的二叉树为止。
二叉树转换为树和森林是唯一的。

树的遍历
先根遍历:若树非空,则先访问根结点,再按从左到右的顺序遍历根结点的每一棵子树。其访问顺序与这棵树相应二叉树的先序遍历顺序相同
后根遍历:若树非空,则按从左到右的顺序遍历根结点的每一棵子树,之后再访问根结点。其访问顺序与这棵树相应二叉树的中序遍历顺序相同
层次遍历:与二叉树的层次遍历思想基本相同,即按层序依次访问各结点。

森林的遍历
先序遍历森林:访问森林中第一棵树的根结点;先序遍历第一棵树中根结点的子树森林;先序遍历除去第一棵树之后剩余的树构成的森林。
中序遍历森林:中序遍历森林中第一棵树的根结点的子树森林;访问第一棵树的根结点;中序遍历除去第一棵树之后剩余的树构成的森林。

树的应用——并查集

选择题

1.下列关于树的说法中,正确的是(II)
I. 对于有n个结点的二叉树,其高度为log2 n(错误,单支树,高度为n)
II. 完全二叉树中,若一个结点没有左孩子,则它必是叶结点
III. 高度为h的完全二叉树对应的森林所含的树的个数一定是h(错误,满二叉树才有该性质)
IV. 一棵树中的叶子数一定等于与其对应的二叉树的叶子数(错误)

3.将森林转换为对应的二叉树,若在二叉树中,结点u是结点v的父结点的父结点,则在原来的森林中,u和v可能具有的关系是(I、II)
I. 父子关系 II. 兄弟关系 III. u的父结点与v的父结点是兄弟关系

7.设F是一个森林,B是由F变换来的二叉树。若F中有n个非终端结点,则B中右指针域为空的结点有(n+1)个

9.将森林F转换为对应的二叉树T,F中叶结点的个数等于(T中左孩子指针为空的结点个数)

12.若森林F有15条边、25个结点,则F包含树的个数是(10)
在n个结点的树中有n-1条边,那么对于每棵树,其结点数比边数多1.

4.5 树与二叉树的应用

二叉排序树(BST,又称为二叉查找树):左子树上所有结点关键字值均小于根结点的关键字值;右子树上所有结点关键字值均大于根结点的关键字值;左右子树本身也分别是一棵二叉排序树。
对二叉排序树进行中序遍历,可以得到一个递增的有序序列。

二叉排序树的查找、插入、构造、删除
二叉排序树查找算法的平均查找长度,主要取决于树的高度,即与二叉树的形态有关。
当有序表是静态查找表时,宜用顺序表作为其存储结构,而采用二分查找实现其查找操作;若有序表是动态查找表,则应选择二叉排序树作为其逻辑结构。

平衡二叉树(AVL):左子树和右子树都是平衡二叉树,且任意结点的左右子树高度差的绝对值不超过1。
平衡因子的值只可能是-1,0或1(左子树的高度-右子树的高度)

平衡二叉树的插入:LL平衡旋转(右单旋转)、RR平衡旋转(左单旋转)、LR平衡旋转(先左后右双旋转)、RL平衡旋转(先右后左双旋转)

平衡二叉树的查找:平均查找长度为O(log2 n)

从树根结点到任意结点的路径长度(经过的边数)与该结点上权值的乘积称为该结点的带权路径长度。树中所有叶结点的带权路径长度之和称为该树的带权路径长度

在含有N个带权叶子结点的二叉树中,其中带权路径长度(WPL)最小的二叉树称为哈夫曼树,也称为最优二叉树

哈夫曼树的构造:给定N个权值分别为w1~wN的结点
1)将这N个结点分别作为N棵仅含一个结点的二叉树,构成森林F
2)构造一个新结点,并从F中选取两棵根结点权值最小的树作为新结点的左右子树,并且将新结点的权值置为左右子树上根结点的权值之和
3)从F中删除刚才选出的两棵树,同时将新得到的树加入F中
4)重复2)和3),直至F中只剩下一棵树为止
特点
1)每个初始结点最终都成为叶结点,并且权值越小的结点到根结点的路径长度越大
2)构造过程中共新建了N-1个结点(双分支结点),因此哈夫曼树的结点总数为2N-1
3)每次构造都选择2棵树作为新结点的孩子,因此哈夫曼树中不存在度为1的结点

可变长度编码:对频率高的字符赋以短编码,而对频率较低的字符赋以较长一些的编码,从而使字符平均编码长度减短,起到压缩数据的效果。
如果没有一个编码是另一个编码的前缀,则称这样的编码为前缀编码
由哈夫曼树构造哈弗曼编码:首先将每个出现的字符当做一个独立的结点,其权值为它出现的频度,构造出相应的哈夫曼树。显然,所有字符结点都出现在叶结点中。我们可以将字符的编码解释为从根至该字符的路径上边标记的序列,其中边标记为0表示“转向左孩子”,标记为1表示“转向右孩子”。

选择题

1.对于二叉排序树,下面的说法(C)是正确的
A 二叉排序树是动态树表,查找失败时插入新结点时,会引起树的重新分裂和组合(错)
B 对二叉排序树进行层序遍历可得到有序序列(错,中序遍历)
C 用逐点插入法构造二叉排序树,若先后插入的关键字有序,二叉排序树的深度最大
D 在二叉排序树进行查找,关键字的比较次数不超过结点数的1/2(错)

第5章 图

5.1 图的基本概念

有向图、无向图
简单图:不存在重复边,不存在顶点到自身的边(数据结构中仅讨论简单图)
多重图的定义和简单图相反。

无向完全图:在无向图中,如果任意两个顶点之间都存在边,则称该图为无向完全图。含有n个顶点的无向完全图有n(n-1)/2条边。
有向完全图:在有向图中,如果任意两个顶点之间都存在方向相反的两条弧,则称该图为有向完全图。含有n个顶点的有向完全图有**n(n-1)**条有向边。

子图:设有两个图G=(V,E)和G’=(V’,E’),若V’是V的子集,且E’是E的子集,则称G’是G的子图。若有满足V(G’)=V(G)的子图G’,则为G的生成子图

连通、连通图和连通分量(无向图):在无向图中,若从顶点v到顶点w有路径存在,则称v和w是连通的。若图G中任意两个顶点都是连通的,则称图G为连通图,否则称为非连通图。无向图中的极大连通子图称为连通分量如果一个图有n个顶点,并且有小于n-1条边,则此图必是非连通图。

强连通图、强连通分量(有向图):在有向图中,若从顶点v到顶点w和从顶点w到顶点v之间都有路径,则称这两个顶点是强连通的。若图中任何一对顶点都是强连通的,则称该图为强连通图有向图中的极大强连通子图称为强连通分量

生成树、生成森林:连通图的生成树是包含图中全部顶点的一个极小连通子图。若图中顶点数为n,则它的生成树含有n-1条边。对于生成树而言,若砍去它的一条边,则它会变成非连通图,若加上一条边则会形成一个回路。

对于无向图,顶点v的度是指依附于该顶点的边的条数,记为TD(v)。
在具有n个顶点e条边的无向图中,全部顶点的度之和为2e,即无向图的全部顶点的度之和等于边数的两倍。

对于有向图,顶点v的度分为入度和出度,入度记为ID(v),出度记为OD(v)。顶点v的度等于其入度和出度之和,即TD(v)=ID(v)+OD(v)。
在具有n个顶点e条边的有向图中,有向图的全部顶点的入度之和与出度之和相等并且等于边数

带权图也称为网。
稠密图:边数很多;稀疏图:边数很少。一般当图G满足|E|<|V|*log|V|时,可以将G看成是稀疏图。

路径:顶点序列;路径长度:路径上边的数目。第一个顶点和最后一个顶点相同的路径称为回路或环如果一个图有n个顶点,并且有大于n-1条边,则此图一定有环

在路径序列中,顶点不重复出现的路径称为简单路径。除第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路称为简单回路

有一个顶点的入度为0,其余顶点的入度均为1的有向图称为有向树

选择题

2.一个有n个顶点和n条边的无向图一定是(有环的)。

3.如果从无向图的任意顶点出发进行一次深度优先搜索即可访问所有顶点,则该图一定是(连通图)。

4.下列关于图的叙述,正确的是(III)
I. 回路是简单路径(错误,回路是第一个顶点和最后一个顶点相同的路径,简单路径是顶点不重复出现的路径)
II. 存储稀疏图,用邻接矩阵比邻接表更省空间(错误,应用邻接表)
III. 若有向图中存在拓扑序列,则该图不存在回路(正确,存在回路的图不存在拓扑序列)

7.若无向图G=(V,E)中含有7个顶点,要保证图G在任何情况下都是连通的,则需要的边数最少是(16)(6*5/2+1)

10.一个有28条边的非连通子图至少有(9)个顶点。(25=8*7/2,8+1=9)

11.对于一个有n个顶点的图:如果是连通无向图,其边的个数至少为(n-1);如果是连通有向图,其边的个数至少为(n)

13.在有n个顶点的有向图中,每个顶点的度最大可达(2n-2)

14.具有6个顶点的无向图,当有(11)条边时能确保是一个连通图。(5*4/2+1)

17.如果有n个顶点的图是一个环,则它有(n-1)棵生成树。

18.若一个具有n个顶点,e条边的无向图是一个森林,则该森林中必有(n-e)棵树。

5.2 图的存储及基本操作

邻接矩阵存储,就是用一个一维数组存储图中顶点的信息,用一个二维数组存储图中边的信息(即各顶点之间的邻接关系),存储顶点之间邻接关系的二维数组称为邻接矩阵
1)无向图的邻接矩阵是对称矩阵(并且唯一),在实际存储邻接矩阵时只需存储上(或下)三角矩阵的元素即可,对规模特大的邻接矩阵可采用压缩存储。
2)邻接矩阵表示法的空间复杂度为O(n2),其中n为图的顶点数|V|
3)对于无向图,邻接矩阵的第i行(或第i列)非零元素(或非∞元素)的个数正好是第i个顶点的度
4)对于有向图,邻接矩阵的第i行(或第i列)非零元素(或非∞元素)的个数正好是第i个顶点的出度(或入度)
5)容易确定顶点之间是否有边相连,但难以确定图中有多少条边
6)稠密图适合使用邻接矩阵的存储表示

邻接表就是对图G中的每个顶点vi建立一个单链表,第i个单链表中的结点表示依附于顶点vi的边(对于有向图则是以顶点vi为尾的弧),这个单链表就称为顶点vi的边表(对于有向图则称为出边表)。边表的头指针和顶点的数据信息采用顺序存储(称为顶点表),所以在邻接表中存在两种结点:顶点表结点和边表结点
顶点表结点由顶点域(data)和指向第一条邻接边的指针(firstarc)构成,边表(邻接表)结点由邻接点域(adjvex)和指向下一条邻接边的指针域(nextarc)构成。
1)如果G为无向图,则所需的存储空间为O(|V|+2|E|);如果G为有向图,则所需的存储空间为O(|V|+|E|)
2)对于稀疏图,采用邻接表表示将极大地节省存储空间
3)容易找出顶点的所有邻边,但难以确定两个顶点之间是否存在边
4)图的邻接表表示并不唯一

十字链表有向图的一种链式存储结构。
既容易找到vi为尾的弧,也容易找到vi为头的弧,因而容易求得顶点的出度和入度。
图的十字链表表示是不唯一的,但一个十字链表表示确定的一个图。

邻接多重表无向图的另一种链式存储结构。

选择题

1.关于图的存储结构,(B)是错误的
A 使用邻接矩阵存储一个图时,在不考虑压缩存储的情况下,所占用的存储空间大小只与图中的顶点数有关,与边数无关
B 邻接表只用于有向图的存储,邻接矩阵适用于有向图和无向图
C 若一个有向图的邻接矩阵,对角线以下元素为0,则该图的拓扑序列必定存在
D 存储无向图的邻接矩阵是对称的,故只需存储邻接矩阵的下(或上)三角部分即可

2.若图的邻接矩阵中主对角线上的元素皆为0,其余元素全为1,则可以断定该图一定是(完全图)

8.一个图的邻接矩阵表示唯一,邻接表表示不唯一。

9.用邻接表法存储图所用的空间大小(与图的顶点数和边数有关)

10.若邻接表中有奇数个边表结点,则一定是(图为有向图)(无向图采用邻接表表示,有偶数个边表结点)

13.假设有n个顶点e条边的有向图用邻接表表示,则删除与某个顶点v相关的所有边的时间复杂度为(O(n+e))

14.求有向图结点的度,必须遍历整个邻接表

15.邻接多重表是(无向图)的存储结构

16.十字链表是(有向图)的存储结构

5.3 图的遍历

广度优先搜索(BFS):不是一个递归的算法,必须借助一个辅助队列,以记忆正在访问的顶点的下一层顶点。
类似的思想还应用于Dijkstra单源最短路径算法和Prim最小生成树算法。
空间复杂度为O(|V|);采用邻接表存储方式时,时间复杂度为O(|V|+|E|);采用邻接矩阵存储方式时,时间复杂度为O(|V|^2)

广度优先生成树:一给定图的邻接矩阵存储表示是唯一的,故其广度优先生成树也是唯一的,但由于邻接表存储表示不唯一,故其广度优先生成树也是不唯一的。

深度优先搜索(DFS):对于同样一个图,基于邻接矩阵的遍历所得到的DFS序列和BFS序列是唯一的,基于邻接表的遍历所得到的DFS序列和BFS序列是不唯一的。
空间复杂度为O(|V|);采用邻接表存储方式时,时间复杂度为O(|V|+|E|);采用邻接矩阵存储方式时,时间复杂度为O(|V|^2)

选择题

2.对于一个非连通无向图G,采用深度优先遍历访问所有顶点,调用DFS的次数正好等于(连通分量数)

7.用邻接表存储的图的深度优先遍历算法类似于树的(先序遍历),而其广度优先遍历算法类似于树的(按层次遍历)

12.判断有向图是否存在回路,除了可以利用拓扑排序外,还可以利用(深度优先遍历算法)

13.使用DFS算法递归地遍历一个无环有向图,并在退出递归时输出相应顶点,这样得到的顶点序列是(逆拓扑有序)

15.图的广度优先生成树的树高比深度优先生成树的树高(小或相等)

5.4 图的应用

猜你喜欢

转载自blog.csdn.net/sinat_31790817/article/details/83926832
今日推荐