如有错误欢迎指正,题目根据教材----------严蔚敏数据结构(c语言版 第2版)人民邮电电子版
数据结构Ⅰ复习题
- 一、填空题
- 1.算法应该具备的5个重要特性有___有穷性___、确定性、可行性、输入和输出。
- 2.非空单链表L中*p是头结点的条件是 __P==L_____ 。
- 3.深度为10的满二叉树共含有 __1023_____ 个结点。
- 4.当无向图是稠密图时,更适合采用__邻接矩阵_____ 作为其存储结构。
- 5.对含有8个元素的一组关键字进行哈希检索,若给定装填因子为0.8,则哈希表的表长应设定为 __10__ 。
- 6.抽象数据类型可用三元组(D,S,P)表示,其中,D是数据对象,S是D上的关系集,P是对D的基本 _操作_ 集。
- 7.设有一个二维数组A,行下标的范围从0 ~ 5,列下标的范围是从0 ~ 7,若A按列优先方式存储,元素A[3][5]的起始地址与当A按行优先方式存储时_A[4][1]_____ 元素的起始地址一致。
- 8.一棵有255个叶子结点的完全二叉树,最多有 _510___ 个结点。
- 9.在一个有向图中,所有顶点的入度之和等于所有顶点的出度之和的__1__倍。
- 10.给定关键码序列:{22,41,53,46,30},哈希函数为:H(key)=key mod 6,基本表长度为6,用链地址法解决冲突构建哈希表,则此哈希表在等概率情况下查找成功的平均查找长度是 __7/5____ 。
- 11.数据的逻辑结构分为集合、线性结构、树形结构和 _图状结构_ 4种。
- 12. 设栈S和队列Q的初始状态为空,元素e1,e2,e3,e4,e5,e6依次通过栈S,一个元素出栈后即进入队列Q,若6个元素出队的序列是e2,e4,e3,e6,e5,e1,则栈的容量至少应该是 __3__ 。
- 13.用顺序存储的方法,将完全二叉树中所有结点按层逐个从左到右的顺序存放在一维数组R[1..N]中,若结点R[i]有右孩子,则其右孩子是 _R[2i]___ 。
- 14.一个具有n个顶点的有向图最多有 _n(n-1)__条边。
- 15.一个无序序列可以通过构造一棵 _二叉排序_树而变成一个有序序列,构造树的过程即为对无序序列进行排序的过程。
- 二、单项选择题
- 1.下面程序段的时间复杂度为( B )
- 2.线性表的链式存储有利于( A )运算的实现。
- 3.设栈S初始为空时S.top == S.base(base为栈底指针,top为栈顶指针),最大存储容量为maxsize,则栈内的元素个数为( A )。
- 4.若二叉树采用顺序存储结构,且树根存储在1号存储单元(0号存储单元未用),则存储在i号存储单元的结点的左孩子若存在,其存储单元为( C )。
- 5.图的广度优先搜索遍历类似于树的( D )遍历的过程。
- 6.以下排序方法中,( A )是对直接插入排序算法进行改进得到的一种插入排序算法。
- 7.下面关于算法说法正确的是( D )。
- 8.假设push(1)代表数据元素1入栈,pop代表出栈,在操作序列push(1)、pop、push(2)、push(5)、push(7)、pop、push(6)、pop之后,栈中还有几个元素,栈顶元素和栈底元素分别是什么?( A )
- 9.设有一个顺序表Sq的存储空间为0~m-1,用length表示表长,用listsize表示容量,则顺序表Sq满的条件是( B )。
- 10.采用二叉链表存储的二叉树中若有n个结点,那么有( A )个非空指针域。
- 11.一个有n个顶点的无向图最多有( C )条边。
- 12.二叉排序树中,键值最小的结点一定( A )。
- 13.下面程序段的时间复杂度是(C )。
- 14. 判断一个循环队列Q(最多n个元素)为满的条件是( C )。
- 15.设SUBSTR(S,i,k)是求S中从第i个字符开始的连续k个字符组成的子串的操作,则对于S=’Beijing&Nanjing’,SUBSTR(S,4,5)=(B )。
- 16. 深度为k的完全二叉树,至少具有( D )个结点,若对这些结点按自上而下,从左到右次序给结点编号(从1开始),则编号最小的叶子结点的编号是( D )。
- 17.带权有向图G用邻接矩阵A存储,则顶点i的入度为A中:( D )。
- 18. 有一个有序表为 {3,7,9,22,36,43,50,62,75,77,79,95,99},当折半查找值为82的结点时,( C )次比较后查找成功。
- 三、分析解答题
- 1. 假设二维数组A的每个元素是由8个字符组成的串(行下标的范围从1到6,列下标的范围从1到8)。已知A的基地址为1000,则
- 2. 已知一棵二叉树的中序遍历和后序遍历序列分别为DBFEGAC和DFGEBCA,请画出此二叉树示意图,再画出其对应的二叉树二叉链表存储结构,并写出其先序遍历序列。
- 3. 甲乙两方出于保密使用Huffman编码进行电文通信。假设用于通信的电文由abcdefg7种字符组成,且它们在电文中出现的百分比依次为7%、16%、2%、9%、35%、11%、20%,请将百分比化作小数作为权值,按权值小者为左孩子构造Huffman树的规则,画出哈夫曼树,写出各字符的哈夫曼编码,并计算WPL。
- 4.无向图G的顶点集为V={A,B,C,D,E,F},边集为S={(A,B),(A,D),(A,E),(B,D),(D,E),(C,F)},画出该图的邻接矩阵存储结构,写出从A出发的一个广度优先搜索序列,并画出该图的连通分量。
- 5. 网通公司要在某镇周边的6个村庄铺设光纤网络,为使光纤造价最低,对几个村庄的连通情况进行了测量,如下图所示,单位为千米。请采用prim算法从顶点A开始构造最小生成树。画出最小生成树的最终形态,并写出在构造过程中辅助数组中各分量值的变化。
- 6. 序列(08,58,19,23,40,36,28,66,35,87,25,100)是不是堆?如果是,属于何类型?如果不是,请将它调整为交换记录最少的堆,说出其类型,并且输出其经过一趟堆排序后的元素序列。
- 7.对于一个具有n个结点的单链表,在已知p所指结点后插入一个新结点的时间复杂度是?在给定值为x的结点后插入一个新结点的时间复杂度是?若删除p所指结点的后继结点,则应执行什么操作?需要分配较大空间,插入和删除不需要移动元素的线性表,采用哪种存储结构更合适?
- 8.已知二叉树的中序序列为DGBAEHCF,后序序列为GDBHEFCA,画出这棵二叉树,写出二叉树的顺序存储结构,并将其转换为森林。
- 9.已知某文档中只可能出现ABCDEFG七种字符,且它们的出现的次数依次为81,44,23,51,36,97,22,现要将这个文档通过网络传输出去,请按照传输码长最短的原则,建立一种二进制前缀编码方案,并求出码长。
- 10.如下所示的无向图是非连通图,请画出它的所有连通分量,以及生成森林,并写出从A点出发的深度优先遍历序列和广度优先遍历序列。
- 11.假设想在8个城市之间修建高速路,施工人员经过测算,各个可能修建的道路和需要花费的代价如下图所示,请设计一种方案能够在最节省成本的前提下将8个城市连通起来,画出选取步骤,并写出最后方案的邻接矩阵。
- 12.请采用快速排序法和直接插入排序法对该序列{60,56,86,23,16,46}进行升序排序,写出每种方法前三趟排序结果,并分析这两种排序方法的稳定性。
- 13.现有矩阵A如下图所示,若A[2][3]地址为2018,元素值是“1”,每个元素占24个存储单元,则数组A在什么位置存放?假设A为稀疏矩阵,请给出它的三元组表。
- 14.已知某二叉树如下所示,试画出它转换成森林,并请写出该二叉树的先序、中序、后序遍历的序列。
- 15.军事演习中蓝军要发送由abcdef 六种字符组成的密文(其频率为44,11,25,30,5,7),要求使用二进制前缀编码传送,设计一种编码方式可以使报文总长最短,给出每个字符的码值并求出编码的总长度。
- 16. 如下所示的有向图,回答下面问题:
- 17.吉林市松花湖上有7座小岛11条航线,旅行团从码头V0出发想要游遍所有小岛,请提出2种遍历方案并给出每个方案的游岛顺序。若想花费最少代价规划一条航线,请给出航线的生成过程。
- 18.设散列表的长度为8,散列函数H(k)=k mod 7,初始记录关键字序列为(25,31,8,27,13,68),要求分别计算出用线性探测法和链地址法作为解决冲突方法的平均查找长度。
- 四、算法设计题
- 1. 学校办公设备数据按型号不同存放在顺序表L中,现有某个型号的设备全部报废,且该型号元素在顺序表中处于第i(1≤i≤n)个位置,请完成以下删除顺序表第i个元素的算法。
- 2. 采用二叉链表结构存储的二叉树,其指针域lchild和rchild分别指向当前结点的左右子树,请在空格上填写适当语句,实现在二叉链表存储结构上计算二叉树叶子结点个数的算法。
- 3. 某文具超市为提高检索效率及方便插入删除商品信息,将每种文具信息以货号为主关键字存储在二叉排序树中。设每种文具商品(RedType为文具类型名)包含货号(Sid)、商品名(Sname)、单价(Sprice)及库存数量(Snum)等信息。
- 4.工商银行江北支行为到达该行办理业务的储户提供自动排队服务,储户要办理业务需到叫号机前领取号码,等待叫号后到窗口办理业务。叫号机允许同时排队等待的最大人数为100人,按照先来先服务的原则,请在空格上填写适当的语句,完成窗口叫号业务的算法。
- 5.请在空格上填写适当的语句,完成二叉树的层次遍历算法。
- 6.某网店有m种商品,每种商品的价格为h元,库存量为n个,销量为s个,各种商品的信息已存储在一个按商品名ASCII码值由高到低排列的顺序表中,现店主想要了解商品的库存量情况,随机输入想查看的商品名称,请你用折半查找法帮助店主找到该商品的库存量。
- 7.计算机学院17级学生接到维护通讯录系统的任务,由于文档丢失仅发现删除功能的部分代码,通过分析以下代码将这一函数的算法补充完整。
- 8. 在构成哈夫曼树之后,为求编码需从叶子结点出发逆向走一条从叶子到根的路径以求的每个字符的Huffman编码,请将这一段算法补充完整。
- 9.吉林乌拉手工品商城有num种商品,id是商品的标识号,每种商品的价格为price元,库存量为stocknum,销量为salenum个,各种商品的信息存储在顺序表中,现商城经理想要了解商品的销量情况(由高到低排序)。
一、填空题
1.算法应该具备的5个重要特性有___有穷性___、确定性、可行性、输入和输出。
2.非空单链表L中*p是头结点的条件是 P==L___ 。
3.深度为10的满二叉树共含有 1023___ 个结点。
4.当无向图是稠密图时,更适合采用__邻接矩阵_____ 作为其存储结构。
5.对含有8个元素的一组关键字进行哈希检索,若给定装填因子为0.8,则哈希表的表长应设定为 10 。
6.抽象数据类型可用三元组(D,S,P)表示,其中,D是数据对象,S是D上的关系集,P是对D的基本 操作 集。
7.设有一个二维数组A,行下标的范围从0 ~ 5,列下标的范围是从0 ~ 7,若A按列优先方式存储,元素A[3][5]的起始地址与当A按行优先方式存储时_A[4][1]_____ 元素的起始地址一致。
8.一棵有255个叶子结点的完全二叉树,最多有 510__ 个结点。
9.在一个有向图中,所有顶点的入度之和等于所有顶点的出度之和的__1__倍。
10.给定关键码序列:{22,41,53,46,30},哈希函数为:H(key)=key mod 6,基本表长度为6,用链地址法解决冲突构建哈希表,则此哈希表在等概率情况下查找成功的平均查找长度是 7/5__ 。
11.数据的逻辑结构分为集合、线性结构、树形结构和 图状结构 4种。
12. 设栈S和队列Q的初始状态为空,元素e1,e2,e3,e4,e5,e6依次通过栈S,一个元素出栈后即进入队列Q,若6个元素出队的序列是e2,e4,e3,e6,e5,e1,则栈的容量至少应该是 3 。
13.用顺序存储的方法,将完全二叉树中所有结点按层逐个从左到右的顺序存放在一维数组R[1…N]中,若结点R[i]有右孩子,则其右孩子是 R[2i]__ 。
14.一个具有n个顶点的有向图最多有 _n(n-1)__条边。
15.一个无序序列可以通过构造一棵 _二叉排序_树而变成一个有序序列,构造树的过程即为对无序序列进行排序的过程。
二、单项选择题
1.下面程序段的时间复杂度为( B )
i=1; j=0;
while(i+j<=n)
{ if (i>j) j++;
else i++;}
A. O(1) B. O(n) C. O(n2) D. O(2n)
2.线性表的链式存储有利于( A )运算的实现。
A. 插入 B. 读元素 C. 查找 D. 定位
3.设栈S初始为空时S.top == S.base(base为栈底指针,top为栈顶指针),最大存储容量为maxsize,则栈内的元素个数为( A )。
A.S.top-S.base B. S.top-S.base+maxsize
C. S.top D. S.base+maxsize-S.top
4.若二叉树采用顺序存储结构,且树根存储在1号存储单元(0号存储单元未用),则存储在i号存储单元的结点的左孩子若存在,其存储单元为( C )。
A. i B. 2i-1 C. 2i D. 2i+1
5.图的广度优先搜索遍历类似于树的( D )遍历的过程。
A. 先序 B. 中序 C. 后序 D. 按层次
6.以下排序方法中,( A )是对直接插入排序算法进行改进得到的一种插入排序算法。
A. 希尔排序 B. 快速排序 C. 锦标赛排序 D. 堆排序
7.下面关于算法说法正确的是( D )。
A.算法的时间复杂度一般与空间复杂度成正比
B.解决某问题的算法可能有多种,但肯定采用相同的数据结构
C.算法的可行性是指算法的指令不能有二义性
D.算法是指令的有限序列
8.假设push(1)代表数据元素1入栈,pop代表出栈,在操作序列push(1)、pop、push(2)、push(5)、push(7)、pop、push(6)、pop之后,栈中还有几个元素,栈顶元素和栈底元素分别是什么?( A )
A.2,5,2 B.3,5,2 C.2,7,2 D.3,6,2
9.设有一个顺序表Sq的存储空间为0~m-1,用length表示表长,用listsize表示容量,则顺序表Sq满的条件是( B )。
A.Sq.length>=m-1 B.Sq.length>=m
C.Sq.listsize>=m-1 D.Sq.listsize>=m
10.采用二叉链表存储的二叉树中若有n个结点,那么有( A )个非空指针域。
A.n-1 B.n+1 C.2n-1 D.2n+1
在采用二叉链表存储的二叉树中,每个节点都有一个左孩子指针和一个右孩子指针。对于n个节点的二叉树,总共有2n个指针域(因为每个节点有两个指针域)。
然而,并不是所有的指针域都是非空的。在二叉树中,除了根节点外,每个节点都是另一个节点的子节点,这意味着至少有一个指针指向它。因此,对于n个节点的二叉树,会有n-1个节点作为子节点被其他节点的指针指向。根节点没有父节点指向它,所以它不计入被指向的节点数。
因此,对于n个节点的二叉树,非空指针域的数量等于节点数减去根节点,即n-1个。这是因为除了根节点外,每个节点都有一个指针指向它。
11.一个有n个顶点的无向图最多有( C )条边。
A.n B.n(n-1) C.n(n-1)/2 D.2n
12.二叉排序树中,键值最小的结点一定( A )。
A.左指针为空 B.右指针为空
C.左右指针均为空 D.左右指针均为非空
13.下面程序段的时间复杂度是(C )。
s =0;
for(i =0; i<n; i++)
for(j=0;j<n;j++)
s +=B[i][j];
sum = s ;
A. O(1) B. O(n) C. O(n2) D. O(2n)
14. 判断一个循环队列Q(最多n个元素)为满的条件是( C )。
A. Q->rear= =Q->front B. Q->rear= =Q->front+1
C. Q->front==(Q->rear+1)%n D. Q->front==(Q->rear-1)%n
15.设SUBSTR(S,i,k)是求S中从第i个字符开始的连续k个字符组成的子串的操作,则对于S=’Beijing&Nanjing’,SUBSTR(S,4,5)=(B )。
A. ‘ijing’ B. ‘jing&’ C. ‘ingNa’ D. ‘ing&N’
16. 深度为k的完全二叉树,至少具有( D )个结点,若对这些结点按自上而下,从左到右次序给结点编号(从1开始),则编号最小的叶子结点的编号是( D )。
A.2^ k -1 2 ^ k-1 B.2^ (k-1) 2^ (k-1) C.2^ (k-1) 2^ (k-1)+1 D.2^(k-1) 2 ^(k-2)+1
对于深度为k的完全二叉树,编号最小的叶子节点的编号是2^(k-2)+1。这是因为:
在完全二叉树中,除了最后一层外,所有层都是满的。
第k-1层是满的,因此它包含了2^(k-2)个节点。
最后一层的节点编号从2^(k-2)+1开始。
所以,编号最小的叶子节点的编号是2^(k-2)+1。
因此,填空题的正确答案是:
深度为k的完全二叉树,至少具有2^(k-1)个结点,若对这些结点按自上而下,从左到右次序给结点编号(从1开始),则编号最小的叶子结点的编号是 2 ^(k-2)+1。
17.带权有向图G用邻接矩阵A存储,则顶点i的入度为A中:( D )。
A. 第i行非的元素之和 B. 第i列非的元素之和
C. 第i行非且非0的元素个数 D. 第i列非且非0的元素个数
18. 有一个有序表为 {3,7,9,22,36,43,50,62,75,77,79,95,99},当折半查找值为82的结点时,( C )次比较后查找成功。
A.1 B.2 C.4 D.8
三、分析解答题
1. 假设二维数组A的每个元素是由8个字符组成的串(行下标的范围从1到6,列下标的范围从1到8)。已知A的基地址为1000,则
(1)存放A至少需要多少个字节?
(2)若按行优先存储,元素a[6][4]的首地址是多少?
(3)若按列优先存储,元素a[4][6]的首地址是多少?
(4)按列优先存储的元素a[4][6]的首地址与按行优先存储的哪个元素首地址相一致?
(1) 8x6x8=384
(2) 8*(58+3)+1000=1344
(3) 8(5*6+3)+1000=1266
(4) (6-1)*6+(4-1)=(i-1)*8+(j-1) ,即8i+j=42 ,所以A[5][2]
2. 已知一棵二叉树的中序遍历和后序遍历序列分别为DBFEGAC和DFGEBCA,请画出此二叉树示意图,再画出其对应的二叉树二叉链表存储结构,并写出其先序遍历序列。
解题思路:
中序(左根右):DBFEGAC
后序(左右根):DFGEBCA
由于后序遍历最后一个节点A为根,所以A为这颗二叉树的根,在中序遍历序列以A为轴区分左右,
中序(左根右):DBFEG(左)A(根)C(右)
并且后序序列DFGEBCA的倒数第三(B)、倒数第二©分别来自左右,所以B和C分别为左右的根
在中序序列中 D(左)B(根)FEG (右) 以及C(根)
在后序序列还剩下FGE分别为左根右
到此,二叉树就画好了
根据二叉树可以知道先序序列为:ABDEFGC
3. 甲乙两方出于保密使用Huffman编码进行电文通信。假设用于通信的电文由abcdefg7种字符组成,且它们在电文中出现的百分比依次为7%、16%、2%、9%、35%、11%、20%,请将百分比化作小数作为权值,按权值小者为左孩子构造Huffman树的规则,画出哈夫曼树,写出各字符的哈夫曼编码,并计算WPL。
4.无向图G的顶点集为V={A,B,C,D,E,F},边集为S={(A,B),(A,D),(A,E),(B,D),(D,E),(C,F)},画出该图的邻接矩阵存储结构,写出从A出发的一个广度优先搜索序列,并画出该图的连通分量。
5. 网通公司要在某镇周边的6个村庄铺设光纤网络,为使光纤造价最低,对几个村庄的连通情况进行了测量,如下图所示,单位为千米。请采用prim算法从顶点A开始构造最小生成树。画出最小生成树的最终形态,并写出在构造过程中辅助数组中各分量值的变化。
6. 序列(08,58,19,23,40,36,28,66,35,87,25,100)是不是堆?如果是,属于何类型?如果不是,请将它调整为交换记录最少的堆,说出其类型,并且输出其经过一趟堆排序后的元素序列。
因为观察整棵树基本上小的在堆顶大的在堆底,所以调整为交换记录最少的堆是小根堆,小根堆构造方法:从根开始与左右相比,三者最小的换成根
7.对于一个具有n个结点的单链表,在已知p所指结点后插入一个新结点的时间复杂度是?在给定值为x的结点后插入一个新结点的时间复杂度是?若删除p所指结点的后继结点,则应执行什么操作?需要分配较大空间,插入和删除不需要移动元素的线性表,采用哪种存储结构更合适?
O(1),O(n),p->next=p->next->next,静态链表
时间复杂度是 O(1)。这是因为我们已经有了一个指向特定节点的指针 p,我们只需要进行几个基本操作来插入新节点,例如更新指针。
时间复杂度是 O(n)。这是因为我们需要遍历整个链表来找到值为 x 的节点。在最坏的情况下,这个节点可能是链表的最后一个节点,或者根本不存在,这将需要遍历整个链表。
应执行的操作是 p->next = p->next->next;。这个操作会跳过 p 结点的后继结点,从而将其从链表中删除。
静态链表更合适。静态链表在数组中模拟链表的行为,它允许插入和删除操作不需要移动元素,因为元素是通过数组索引(类似于指针)连接的,而不是物理上连续的。
8.已知二叉树的中序序列为DGBAEHCF,后序序列为GDBHEFCA,画出这棵二叉树,写出二叉树的顺序存储结构,并将其转换为森林。
解题思路:
中序(左根右)序列为DGBAEHCF
后序(左右根)序列为GDBHEFCA
由于后序遍历最后一个节点A为根,所以A为这颗二叉树的根,在中序遍历序列以A为轴区分左右
中序:DGB(左)A(根)EHCF(右)
此时后序:GDB(左)HEFC(右)A(根)
后序序列的左的最后一个(B)为左的根,右的最后一个©为右的根
此时中序 DG(左)B(根) 和 EH(左)C(根)F(右)
看后序剩下元素能为什么关系(一定要含根),在中序找到唯一对应且正确的关系,把关系带回后序,注意:这只是判断根是谁,这会的左右不一定是左右(左右要在判完根之后在中序看)
中序:先D后G,关系不是左根就是根右,后序:先G后D,关系:左根,所以把关系左根带回后序进行判断,GD为左根,也就是根为D左为G,EF同理
9.已知某文档中只可能出现ABCDEFG七种字符,且它们的出现的次数依次为81,44,23,51,36,97,22,现要将这个文档通过网络传输出去,请按照传输码长最短的原则,建立一种二进制前缀编码方案,并求出码长。
10.如下所示的无向图是非连通图,请画出它的所有连通分量,以及生成森林,并写出从A点出发的深度优先遍历序列和广度优先遍历序列。
深度优先遍历序列:ACEGDBEFHI
广度优先遍历序列:ACDGEBEFHI![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/4767adee471345b19740175b1aebf95d.png
11.假设想在8个城市之间修建高速路,施工人员经过测算,各个可能修建的道路和需要花费的代价如下图所示,请设计一种方案能够在最节省成本的前提下将8个城市连通起来,画出选取步骤,并写出最后方案的邻接矩阵。
答:
注意:
普里姆算法(Prim’s Algorithm):
基本思想:普里姆算法从图中的一个顶点开始,逐步增加新的边和顶点,直到包含图中的所有顶点。
步骤:
选择一个起始顶点,将其加入最小生成树。
在已加入最小生成树的顶点和未加入最小生成树的顶点之间,寻找权值最小的边,并将这条边及其对应的顶点加入最小生成树。
重复步骤2,直到所有顶点都被加入最小生成树。
数据结构:通常使用优先队列(例如最小堆)来高效地找出当前最小的边。
克鲁斯卡尔算法(Kruskal’s Algorithm):
基本思想:克鲁斯卡尔算法按照边的权值顺序(从小到大)来选择边,并确保选择的边不会与已经选择的边形成环,直到形成最小生成树。
步骤:
将图中的所有边按权值从小到大排序。
初始化最小生成树为空。
按顺序遍历每条边,如果这条边加入最小生成树后不会形成环,则将其加入最小生成树。
重复步骤3,直到最小生成树中的边数等于顶点数减1。
数据结构:通常使用并查集数据结构来高效地检测加入一条边是否会产生环。
两种算法各有优缺点,适用于不同的情况。普里姆算法适合于稠密图,而克鲁斯卡尔算法适合于稀疏图。在具体实现时,可以根据图的特性选择合适的算法。
12.请采用快速排序法和直接插入排序法对该序列{60,56,86,23,16,46}进行升序排序,写出每种方法前三趟排序结果,并分析这两种排序方法的稳定性。
注意:
冒泡排序(Bubble Sort):
稳定性:稳定
原因:相同元素在排序过程中不会交换位置。
选择排序(Selection Sort):
稳定性:不稳定
原因:在选择最小(或最大)元素进行交换时,可能会改变相同元素的相对顺序。
插入排序(Insertion Sort):
稳定性:稳定
原因:插入元素时,总是保持原有顺序,不会改变相同元素的相对位置。
希尔排序(Shell Sort):
稳定性:不稳定
原因:由于跳跃式的比较和交换,可能会改变相同元素的相对顺序。
快速排序(Quick Sort):
稳定性:不稳定
原因:在划分过程中,可能会将相同元素交换到不同分区。
归并排序(Merge Sort):
稳定性:稳定
原因:合并过程中,总是先复制左半部分的元素,再复制右半部分的元素,保持原有顺序。
堆排序(Heap Sort):
稳定性:不稳定
原因:在构建堆和调整堆的过程中,可能会改变相同元素的相对顺序。
基数排序(Radix Sort):
稳定性:稳定
原因:在按位排序时,总是保持原有顺序。
计数排序(Counting Sort):
稳定性:稳定
原因:计数过程中,相同元素的相对顺序被保留。
13.现有矩阵A如下图所示,若A[2][3]地址为2018,元素值是“1”,每个元素占24个存储单元,则数组A在什么位置存放?假设A为稀疏矩阵,请给出它的三元组表。
答:2018-(2*4+3)*24= 2018 - (11 * 24) = 2018 - 264 = 1754
14.已知某二叉树如下所示,试画出它转换成森林,并请写出该二叉树的先序、中序、后序遍历的序列。
二叉树变成森林方法:
1.将右节点断掉:对于二叉树中的每个节点,将其与右子节点的连接断开。这样,每个节点只保留其左子节点,如果有的话。
2.如果某个节点原本有一个左子节点,而该左子节点又有一个右子节点,那么在断开所有右子节点连接之后,我们需要将原本的父节点与原本左子节点的右子节点连接起来。
15.军事演习中蓝军要发送由abcdef 六种字符组成的密文(其频率为44,11,25,30,5,7),要求使用二进制前缀编码传送,设计一种编码方式可以使报文总长最短,给出每个字符的码值并求出编码的总长度。
16. 如下所示的有向图,回答下面问题:
(1)该图是强连通的吗?若不是,给出强连通分量。
(2)请给出图的邻接矩阵和邻接表表示。
17.吉林市松花湖上有7座小岛11条航线,旅行团从码头V0出发想要游遍所有小岛,请提出2种遍历方案并给出每个方案的游岛顺序。若想花费最少代价规划一条航线,请给出航线的生成过程。
18.设散列表的长度为8,散列函数H(k)=k mod 7,初始记录关键字序列为(25,31,8,27,13,68),要求分别计算出用线性探测法和链地址法作为解决冲突方法的平均查找长度。
ASL1=7/6,ASL2=4/3
四、算法设计题
1. 学校办公设备数据按型号不同存放在顺序表L中,现有某个型号的设备全部报废,且该型号元素在顺序表中处于第i(1≤i≤n)个位置,请完成以下删除顺序表第i个元素的算法。
typedef struct Status ListDelete_Sq ( &L, int i)
{ {if ( i<1|| i>L.length) return ERROR;
Citems *elem; p=& ( ) ;//p指向第i个元素
//设Citems为设备数据类型 q=L.elem + ;//q指向表尾
int length ; for( ; p<=q; ++p )
int listsize; *(p-1)=*p;//元素前移
} SqList; ;
return OK;
}
typedef struct {Citems *elem; // 指向顺序表元素的指针int length; // 顺序表当前长度int listsize; // 顺序表分配的存储容量
} SqList;// 设备数据类型Citems的定义应在此处或之前给出// 删除顺序表第i个元素的函数
Status ListDelete_Sq(SqList *L, int i) {if (i < 1 || i > L->length) return ERROR; // i值不合法Citems *p = &(L->elem[i - 1]); // p指向第i个元素,注意数组下标从0开始,所以是i-1Citems *q = L->elem + L->length - 1; // q指向表尾for (++p; p <= q; ++p) {*(p - 1) = *p; // 元素前移}L->length--; // 顺序表长度减1return OK; // 删除成功
}
2. 采用二叉链表结构存储的二叉树,其指针域lchild和rchild分别指向当前结点的左右子树,请在空格上填写适当语句,实现在二叉链表存储结构上计算二叉树叶子结点个数的算法。
CountLeaf (BiTree T){
if ( T ) {
if ( )// T指向叶子结点
return ;
else
return ;
}
else return ;
} // CountLeaf
CountLeaf (BiTree T){if ( T ) { if (T->lchild == NULL && T->rchild == NULL) // T指向叶子结点return 1; else return CountLeaf(T->lchild) + CountLeaf(T->rchild); } else return 0;
} // CountLeaf
3. 某文具超市为提高检索效率及方便插入删除商品信息,将每种文具信息以货号为主关键字存储在二叉排序树中。设每种文具商品(RedType为文具类型名)包含货号(Sid)、商品名(Sname)、单价(Sprice)及库存数量(Snum)等信息。
(1)根据给定的商品描述为商品定义二叉排序树类型(BiTree);
(2)现有某种商品已售完,指针p已经指向二叉排序树中表示该种商品的结点,请编写算法删除该结点并重接它的左右子树。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 商品信息结构体
typedef struct {char Sid[20]; // 货号char Sname[50]; // 商品名float Sprice; // 单价int Snum; // 库存数量
} RedType;// 二叉排序树的结点结构体
typedef struct BiTNode {RedType data; // 数据域struct BiTNode *lchild, *rchild; // 左右孩子指针
} BiTNode, *BiTree;// (1)商品信息结构体和二叉排序树结点类型已经定义// (2)删除二叉排序树中指定结点p的算法
int DeleteNode(BiTree *T, BiTNode *p) {BiTNode *q, *s;// 情况1:p结点为叶子结点if (p->lchild == NULL && p->rchild == NULL) {q = p;}// 情况2:p结点只有左子树else if (p->lchild != NULL && p->rchild == NULL) {q = p;p = p->lchild;}// 情况3:p结点只有右子树else if (p->lchild == NULL && p->rchild != NULL) {q = p;p = p->rchild;}// 情况4:p结点有左右子树else {// 找到p的中序后继,即右子树中的最小元素q = p;s = p->rchild;while (s->lchild != NULL) {q = s;s = s->lchild;}// 将s的数据复制到p中p->data = s->data;// 修改p指针指向sp = s;}// 将p指向的结点替换为q指向的结点if (q != *T) {if (q == q->parent->lchild)q->parent->lchild = p;elseq->parent->rchild = p;} else {*T = p;}// 释放q指向的结点free(q);return 1;
}// 注意:上述代码没有维护父指针,实际使用时可能需要调整。
4.工商银行江北支行为到达该行办理业务的储户提供自动排队服务,储户要办理业务需到叫号机前领取号码,等待叫号后到窗口办理业务。叫号机允许同时排队等待的最大人数为100人,按照先来先服务的原则,请在空格上填写适当的语句,完成窗口叫号业务的算法。
#define MAXQAIZE ①__________;
typedef struct LNode{ Status DeQueue_Sq (SqQueue &Q, int &e){ {
int *base; if (②___________= = ③____________) return ERROR;
int front; e =④_________________;
int rear; Q.front = ⑤__________________________ ;
}SqQueue; return OK;
}// DeQueue_Sq
#define MAXQAIZE 100; // ① 最大排队人数为100typedef struct LNode {// ... 其他结构体成员定义 ...
} LNode;typedef struct {int *base; // 动态分配数组空间int front; // 队头指针int rear; // 队尾指针
} SqQueue;// 出队操作
Status DeQueue_Sq(SqQueue &Q, int &e) {if (Q.front == Q.rear) // ② 队头指针等于队尾指针时队列为空return ERROR; // ③ 返回ERROR表示队列为空,无法出队e = Q.base[Q.front]; // ④ 获取队头元素Q.front = (Q.front + 1) % MAXQAIZE; // ⑤ 队头指针后移,并循环使用队列空间return OK; // 出队成功
}
5.请在空格上填写适当的语句,完成二叉树的层次遍历算法。
typedef struct BiTNode { Status LevelOrderTraverse ( BiTree T , Status (*Visit) (TElemType e))
TElemType data; { InitQueue (Q); ①__________________;
struct BiTNode *lchild; while(②_________________) {
struct BiTNode *rchild; ③__________________
}BiTNode,*BiTree; if (!p) return ERROR;
if (!Visit(p->data)) return ERROR;
if (p->lchild) ④_________________ ;
if (p->lchild) ⑤_________________ ;}
return OK;
}
typedef struct BiTNode {TElemType data;struct BiTNode *lchild;struct BiTNode *rchild;
} BiTNode, *BiTree;Status LevelOrderTraverse(BiTree T, Status (*Visit)(TElemType e)) {LinkQueue Q; // 假设LinkQueue是队列类型,这里需要定义或声明队列结构体BiTNode *p;InitQueue(Q); // ① 初始化队列if (T) EnQueue(Q, T); // 如果树不为空,将根节点入队while (!QueueEmpty(Q)) { // ② 当队列不为空时继续循环DeQueue(Q, p); // 出队,将队头元素赋值给pif (!p) return ERROR;if (!Visit(p->data)) return ERROR; // 访问当前节点if (p->lchild) EnQueue(Q, p->lchild); // ④ 如果左孩子存在,左孩子入队if (p->rchild) EnQueue(Q, p->rchild); // ⑤ 如果右孩子存在,右孩子入队}return OK;
}
6.某网店有m种商品,每种商品的价格为h元,库存量为n个,销量为s个,各种商品的信息已存储在一个按商品名ASCII码值由高到低排列的顺序表中,现店主想要了解商品的库存量情况,随机输入想查看的商品名称,请你用折半查找法帮助店主找到该商品的库存量。
1)定义商品的顺序表存储结构。
2)写出折半查找输出库存量的算法。
#include <stdio.h>
#include <string.h>// 定义商品信息结构体
typedef struct {char name[50]; // 商品名称int price; // 商品价格(单位:元)int stock; // 商品库存量int sales; // 商品销量
} Product;// 定义顺序表结构体
typedef struct {Product *array; // 指向动态分配的数组int length; // 顺序表当前长度
} SeqList;// 折半查找算法,返回商品的库存量
int BinarySearch(SeqList list, char *target) {int low = 0; // 查找区间的下界int high = list.length - 1; // 查找区间的上界int mid;int compareResult;while (low <= high) {mid = (low + high) / 2; // 计算中间位置compareResult = strcmp(list.array[mid].name, target); // 比较中间位置的商品名称和目标商品名称if (compareResult == 0) {// 找到目标商品,返回库存量return list.array[mid].stock;} else if (compareResult < 0) {// 目标商品在右侧区间low = mid + 1;} else {// 目标商品在左侧区间high = mid - 1;}}// 未找到目标商品,返回-1表示失败return -1;
}
7.计算机学院17级学生接到维护通讯录系统的任务,由于文档丢失仅发现删除功能的部分代码,通过分析以下代码将这一函数的算法补充完整。
int AdressListInsert(AdressLinkList L,int i,ElemType e){
LNode *p,*s;int j;
p=L;j=0;
while((p!=NULL)&&(1) ){
p=p->next;j++;
}
if((2) ||j>i-1) return ERROR;
s= (3) (sizeof(LNode));
s->data=e;
(4) ;
(5) ;
return OK;
}/AdressListInsert/
#include <stdlib.h> // 为了使用malloc函数#define ERROR -1
#define OK 1typedef struct LNode {ElemType data; // 假设ElemType已经被定义struct LNode *next;
} LNode, *AdressLinkList;int AdressListInsert(AdressLinkList L, int i, ElemType e) {LNode *p, *s;int j;p = L;j = 0;// (1) 应该是循环的条件,用于找到第i-1个节点while ((p != NULL) && (j < i - 1)) { p = p->next;j++;}// (2) 应该是检查是否找到了第i-1个节点if ((p == NULL) || (j > i - 1)) return ERROR;// (3) 分配新节点s = (LNode *)malloc(sizeof(LNode)); if (s == NULL) { // 检查内存分配是否成功return ERROR;}s->data = e;// (4) 将新节点插入到链表中s->next = p->next; // (5) 将前一个节点的next指向新节点p->next = s; return OK;
}/*AdressListInsert*/
以下是每个步骤的解释:
(1) 条件j < i - 1确保我们找到第i-1个节点,因为我们需要在第i个位置插入新节点。
(2) 检查是否成功找到了第i-1个节点,如果p为NULL或者j大于i-1,则返回错误。
(3) 使用malloc分配一个新节点s。
(4) 将新节点s的next指针指向当前第i个节点(即p->next)。
(5) 将第i-1个节点的next指针指向新节点s,完成插入操作。
请注意,这段代码假设ElemType已经被定义,且ERROR和OK是错误和成功状态的宏定义。
8. 在构成哈夫曼树之后,为求编码需从叶子结点出发逆向走一条从叶子到根的路径以求的每个字符的Huffman编码,请将这一段算法补充完整。
HC=(HuffmanCode)malloc((n+1)sizeof(char))
cd = (char )malloc(nsizeof(char));
cd[n-1] =”\0”;
for (i=1; (1) ++i) { // 逐个字符求赫夫曼编码
start = n-1;
for (c=i, f=HT[i].parent; f!=0; c=f, (2) )
if (HT[f].lchild==c) (3) ;
else cd[–start] = ‘1’;
HC[i] = (4) ; // 为第i个字符编码分配空间
strcpy(HC[i], &cd[start]);
}
(5) ; // 释放工作空间
HC = (HuffmanCode)malloc((n+1)*sizeof(char*)); // 分配n个字符编码的头指针向量
cd = (char *)malloc(n*sizeof(char)); // 分配临时存放编码的工作空间
cd[n-1] = '\0'; // 编码结束符for (i = 1; i <= m; ++i) { // 逐个字符求赫夫曼编码start = n-1; // start开始时指向编码数组最后一个位置for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent) { // 从叶子到根逆向求编码if (HT[f].lchild == c) cd[--start] = '0'; // 如果是左孩子,则编码为'0'else cd[--start] = '1'; // 如果是右孩子,则编码为'1'}HC[i] = (char *)malloc((n-start)*sizeof(char)); // 为第i个字符编码分配空间strcpy(HC[i], &cd[start]); // 从cd复制编码到HC
}free(cd); // 释放工作空间
9.吉林乌拉手工品商城有num种商品,id是商品的标识号,每种商品的价格为price元,库存量为stocknum,销量为salenum个,各种商品的信息存储在顺序表中,现商城经理想要了解商品的销量情况(由高到低排序)。
1)定义商品的顺序表存储结构。
2)写出采用直接插入排序法输出销量的算法。
#include <stdio.h>#define MAX_NUM 100 // 假设商城最多有100种商品// 商品的顺序表存储结构
typedef struct {int id; // 商品的标识号float price; // 商品的价格int stocknum; // 商品的库存量int salenum; // 商品的销量
} Commodity;// 商品的顺序表
typedef struct {Commodity goods[MAX_NUM]; // 商品数组int length; // 当前商品数量
} SeqList;
// 直接插入排序,按照销量由高到低排序
void InsertSort(SeqList *list) {int i, j;Commodity temp;for (i = 1; i < list->length; i++) {temp = list->goods[i];// 从已排序序列的最后一个元素开始,向前比较for (j = i; j > 0 && list->goods[j - 1].salenum < temp.salenum; j--) {list->goods[j] = list->goods[j - 1]; // 如果销量小于待插入的商品,则向后移动}list->goods[j] = temp; // 插入到正确的位置}
}// 打印商品销量
void PrintSales(SeqList *list) {for (int i = 0; i < list->length; i++) {printf("商品ID: %d, 销量: %d\n", list->goods[i].id, list->goods[i].salenum);}
}// 主函数,用于测试
int main() {SeqList list = {.goods = {{1, 99.9, 100, 150},{2, 199.9, 50, 200},{3, 299.9, 30, 300},// ... 其他商品信息},.length = 3 // 假设有3种商品};// 排序前打印销量printf("排序前销量:\n");PrintSales(&list);// 对商品销量进行排序InsertSort(&list);// 排序后打印销量printf("\n排序后销量:\n");PrintSales(&list);return 0;
}