以下内容全部来自ChatGPT和Microsoft bing ai解答,正确率为85%左右,仅参考,本人对本页答案概不负责

一、选择题

  1. 对于数据结构的描述,下列说法中不正确的是( )。

相同的逻辑结构对应的存储结构也必相同

数据结构由逻辑结构、存储结构和基本操作三方面组成

对数据结构基本操作的实现与存储结构有关

数据的存储结构是数据的逻辑结构的机内实现

选项 A 是不正确的。相同的逻辑结构并不意味着存储结构也必须相同。逻辑结构是数据对象之间的抽象关系,而存储结构是这些关系在计算机内部的具体表示。例如,线性表的逻辑结构可以通过数组(顺序存储结构)或链表(链式存储结构)来实现,这两种存储结构有着不同的特性和操作复杂性。因此,即使逻辑结构相同,存储结构也可以不同。其他选项 BCD 都是正确的。数据结构确实由逻辑结构、存储结构和基本操作三方面组成(B),对数据结构基本操作的实现确实与存储结构有关(C),数据的存储结构是数据的逻辑结构的机内实现(D)。

  1. 顺序存储结构中数据元素之间的逻辑关系是由( )表示的。

线性结构

非线性结构

存储位置

指针

在顺序存储结构中,数据元素之间的逻辑关系是由存储位置表示的。所以正确答案是选项 C。在顺序存储结构中,元素之间的逻辑关系(例如线性关系)通过它们在内存中的物理位置来表示。相邻的元素在内存中也是相邻的。这与链式存储结构不同,在链式存储结构中,元素之间的逻辑关系是通过指针表示的。选项 AB 描述的是数据结构的类型,而不是数据元素之间的逻辑关系如何表示。选项 D 是链式存储结构中数据元素之间逻辑关系的表示方式,而不是顺序存储结构。

  1. 链接存储结构中数据元素之间的逻辑关系是由( )表示的。

线性结构

非线性结构

存储位置

指针

在链接存储结构中,数据元素之间的逻辑关系是由指针表示的。指针指向了下一个数据元素的位置,从而建立了数据元素之间的联系。

因此,选项 D 是正确的。

  1. 算法指的是( )。

对特定问题求解步骤的一种描述,是指令的有限序列

计算机程序

解决问题的计算方法

数据处理

算法指的是对特定问题求解步骤的一种描述,是指令的有限序列。它是解决问题或执行任务的明确指令集合,旨在通过一系列定义明确的步骤来完成特定任务。算法通常是一系列可执行的操作,能够从初始状态转移到所需的最终状态。

因此,选项 A 是正确的。

  1. 假设时间复杂度为O(n^2)的算法在有200个元素的数组上运行需要3.1 ms,则有400个元素的数组上运行需要( )ms。

3.1

6.2

12.4

9.61

根据时间复杂度为 O(n^2) 的算法特点,当数组元素的数量增加一倍时,运行时间将增加为原来的平方倍。因此,200 个元素变为 400 个元素,相当于增加了一倍。根据这个关系,我们可以预计运行时间将是原来的 2^2 = 4 倍。即 3.1 ms * 4 = 12.4 ms。

因此,有 400 个元素的数组上运行时间将是 12.4 ms。选项 C 中的 12.4 是正确的。

  1. 算法分析的两个主要方面是( )。

空间性能和时间性能

正确性和简明性

可读性和文档性

数据复杂性和程序复杂性

算法分析的两个主要方面是空间性能和时间性能。在算法设计和评估过程中,我们通常关注算法所需的内存空间以及它执行所需的时间。这些指标可以帮助我们评估算法的效率和可行性,从而选择最适合特定问题的算法。

因此,选项 A 是正确的。

  1. 下面( )不是算法所必须具备的特性。

有穷性

确切性

高效性

可行性

从定义上讲,算法必须具备“有穷性”、“确切性”和“可行性”,因为算法必须是能够在有限步骤内完成的、每个步骤都必须确切且无歧义,并且必须是可行实施的。因此,这些特性是算法的基本要求。

然而,“高效性”并非是算法必须具备的特性。尽管我们通常希望算法是高效的,但并非所有算法都需要是最高效的。因此,选项 C 中的“高效性”是不是算法所必须具备的特性。

  1. 链表不具有的特点是( )。

可随机访问任一元素

插入删除不需要移动元素

不必事先估计存储空间

所需空间与线性表长度成正比

链表不具备的特点是可随机访问任一元素。链表中的元素并非按照其在内存中的物理位置顺序存储,因此不能像数组那样通过下标直接访问特定位置的元素。如果要访问链表中的某个特定元素,需要从头节点开始遍历链表直到找到该元素。

因此,选项 A 中的“可随机访问任一元素”是链表不具备的特点。

  1. 线性表采用链接存储时,其地址( )。

必须是连续的

部分地址必须是连续的

一定是不连续的

连续与否均可以

线性表采用链接存储时,其地址可以是不连续的。在链接存储结构中,元素之间并不要求在物理内存中是连续存储的,相邻元素之间通过指针进行连接。这使得链表结构能够动态地分配和释放内存,避免了因为插入或删除操作导致的大量数据移动。

因此,选项 D 中的“连续与否均可以”是正确的。

10.循环单链表的主要优点是( )。

不再需要头指针了

从表中任一结点出发都能扫描到整个链表

已知某个结点的位置后,能够容易找到它的直接前趋

在进行插入、删除操作时,能更好地保证链表不断开

循环单链表的主要优点是在进行插入、删除操作时,能更好地保证链表不断开。循环单链表的尾节点指向头节点,形成一个闭环,这使得在进行插入和删除操作时更加方便,因为不需要处理头尾节点的特殊情况。

因此,选项 D 中的“在进行插入、删除操作时,能更好地保证链表不断开”是循环单链表的主要优点。

11.若线性表中最常用的操作是在最后一个结点之后插入一个节点和删除最后一个结点,则采用( )存储方法最节省时间。

单链表

循环双链表

单循环链表

带尾指针的单循环链表

循环单链表的主要优点是从表中任一结点出发都能扫描到整个链表。所以,正确答案是选项 B。在循环单链表中,最后一个元素的指针字段指向链表的第一个元素,形成一个闭环。这意味着我们可以从任何一个元素开始,通过顺序访问每个元素的指针字段,遍历整个链表。然而,循环单链表仍然需要头指针来标识链表的起始位置(选项 A 是错误的)。已知某个结点的位置后,找到它的直接前趋在单链表(包括循环单链表)中并不容易,因为我们只能从头开始遍历链表(选项 C 是错误的)。在进行插入、删除操作时,无论是单链表还是循环单链表,我们都需要确保操作后链表不会断开(选项 D 是错误的)。

12.从栈顶指针为top的链栈中删除一个结点 ,用x保存被删除结点的值,则执行( )。

x=top; top=top-> next;

x=top-> data;

top=top-> next; x= top-> data;

x=top-> data; top= top-> next;

在从栈顶指针为top的链栈中删除一个节点时,我们首先需要保存被删除节点的值,然后更新栈顶指针。栈顶指针需要指向被删除节点的下一个节点,因为栈是先进后出的数据结构,所以删除的是栈顶元素。

因此,正确的操作是:

1
2
x = top->data; // 保存被删除节点的值
top = top->next; // 更新栈顶指针

所以选项是D。

13.设计一个判别表达式中左右扩号是否配对的算法,采用( )数据结构最佳。

顺序表

队列

链表

对于判别表达式中左右括号是否配对的算法,最适合使用的数据结构是栈。栈是一种后进先出(LIFO)的数据结构,可以用来检查括号是否匹配。具体的算法可以使用栈来存储左括号,并在遇到右括号时弹出相应的左括号进行匹配。

因此,选项 B 中的栈是最佳的数据结构。

14.将数组称为随机存取结构是因为( )。

数组元素是随机的

对数组任意元素的存取时间是相等的

随时可以对数组进行访问

数组的存储结构是不定的

将数组称为随机存取结构是因为对数组任意元素的存取时间是相等的。这是因为数组在内存中是连续存储的,每个元素都可以通过偏移量直接计算出其地址,因此可以在 O(1) 的时间复杂度内访问任意索引处的元素。

因此,选项 B 中的“对数组任意元素的存取时间是相等的”是描述数组作为随机存取结构的原因。

15.设有两个字符串p和q,求p在q中首次出现的位置的运算称作( )。

连接

模式匹配

求字串

求串长

求p在q中首次出现的位置的运算称为模式匹配。模式匹配是计算机科学中的一个重要概念,用于确定一个字符串是否包含另一个字符串作为子字符串,并返回其出现的位置。在这种情况下,给定字符串p和q,我们试图找到q中第一次出现p的位置。

因此,选项 B 中的“模式匹配”是描述这种运算的术语。

16.设栈S和队列Q的初始状态为空,元素e1,e2,e3,e4,e5,e6依次通过栈S,一个元素出栈后即进入队列Q。若6个元素出队列的顺序是e2,e4,e3,e6,e5,e1,则栈S的容量至少应该是( )。

6

4

3

2

根据题意,元素首先通过栈 S,然后一个一个地出栈并进入队列 Q。最后出队列的元素顺序是 e2,e4,e3,e6,e5,e1。这意味着栈 S 中的元素在被进入队列 Q 之前必须按照逆序排列。

因此,栈 S 的最小容量应至少是 6,因为栈 S 需要依次容纳 e1,e5,e6,e3,e4,e2 这 6 个元素。

因此,选项 A 中的 6 是正确的。

17.一个栈的入栈序列是1,2,3,4,5,则栈的不可能的输出序列是( )。

54321

45321

43512

12345

对于给定的入栈序列1,2,3,4,5,栈的不可能的输出序列是 43512。这是因为在一个栈中,要取出一个元素,需要将位于栈顶的元素弹出,然后才能取出下一个元素。因此,输出序列中的第一个数字应该是栈中元素的最底部元素,然后逐渐依次向上取出。所以,顺序 4、3、5、1、2 不可能是给定入栈序列的输出序列。

其他选项中的序列都是可能的栈输出序列,但 43512 不是。

  1. 栈和队的主要区别在于( )。

它们的逻辑结构不同

它们的存储结构不同

所包含的运算不同

插入、删除运算的限定不一样

栈和队列的主要区别在于它们的插入和删除运算的限定不同。栈是一种后进先出(LIFO)的数据结构,只允许在一端进行插入和删除操作,而队列是一种先进先出(FIFO)的数据结构,只允许在一端插入,在另一端删除。

因此,选项 D 中的“插入、删除运算的限定不一样”是栈和队列的主要区别。

  1. 设模式T=“abcabc",则该模式的next值为( )。

{-1,0,0,1,2,3}

{-1,0,0,0,1,2}

{-1,0,0,1,1,2}

{1,0,0,0,2,3}

自己算算就行了,这题原本错了

  1. 若一个栈的输入序列是1,2,3,… ,n,输出序列的第一个元素是n,则第 i个输出元素是( )。

不确定

n-i

n-i-1

n-i+1

对于一个栈的输入序列是1,2,3,…,n,输出序列的第一个元素是n,则第 i 个输出元素是 n-i+1。这是因为栈是一种后进先出(LIFO)的数据结构,所以最后一个进入栈的元素会最先被弹出,倒数第二个进入栈的元素会第二个被弹出,以此类推。

因此,选项 D 中的 n-i+1 是第 i 个输出元素的正确表示。

21.设线性表有n个元素,以下操作中,( )在顺序表上实现比在单链表上实现的效率更高。

输出第i(1≤i≤n)个元素值

交换第1个和第2个元素的值

顺序输出所有n个元素

查找与给定值x相等的元素在线性表中的序号

在顺序表和单链表上实现的效率比较如下:

  • 输出第i(1≤i≤n)个元素值:在顺序表上实现的效率更高。因为顺序表可以直接通过索引访问任何位置的元素,时间复杂度为O(1)。而在单链表中,我们需要从头开始遍历到第i个元素,时间复杂度为O(n)。
  • 交换第1个和第2个元素的值:在单链表上实现的效率更高。因为在单链表中,我们可以直接改变节点的链接,而不需要移动元素本身。而在顺序表中,我们需要移动元素本身,这可能涉及到大量的数据复制。
  • 顺序输出所有n个元素:在顺序表和单链表上实现的效率相同。因为无论是顺序表还是单链表,我们都需要遍历所有的元素,时间复杂度都是O(n)。
  • 查找与给定值x相等的元素在线性表中的序号:在顺序表和单链表上实现的效率相同。因为无论是顺序表还是单链表,我们都需要遍历所有的元素来查找给定值,时间复杂度都是O(n)。

所以,在这些操作中,只有输出第i(1≤i≤n)个元素值这个操作在顺序表上实现比在单链表上实现的效率更高。

22.对于n个元素组成的线性表,建立一个有序单链表的时间复杂度是( )。

建立一个有序单链表的时间复杂度是O(n^2)。

在一个有序单链表中插入一个元素需要在链表中找到合适的位置,这可能需要从头开始遍历链表,直到找到合适的位置为止。插入一个元素的平均时间复杂度为O(n)。如果要建立一个有序单链表,需要将n个元素一个个插入,因此总的时间复杂度为O(n) * O(n) = O(n^2)。

23.设数组S[n]作为两个栈S1和S2的存储空间,对任何一个栈只有当S[n]全满时才不能进行进栈操作。为这两个栈分配空间的最佳方案是( )。

S1的栈底位置为0,S2的栈底位置为n-1

S1的栈底位置为0,S2的栈底位置为n/2

S1的栈底位置为0,S2的栈底位置为n

S1的栈底位置为0,S2的栈底位置为1

为了最大限度地利用存储空间,我们应该将S1的栈底位置设置为0,将S2的栈底位置设置为n-1。这样可以使两个栈的空间分配在整个数组的两端,最大化利用数组的空间。所以最佳方案是:

S1的栈底位置为0,S2的栈底位置为n-1。

24.一个队列的入队顺序是1、2、3和4,则队列的输出顺序是( )。

4321

1234

1432

3241

一个队列的特点是先进先出(FIFO),即最先进入队列的元素最先出队列。根据题目给出的入队顺序,元素1首先进入队列,然后是2、3、4。因此,出队顺序应为1234。

所以,队列的输出顺序是1234。

25.对特殊矩阵采用压缩存储的目的主要是为了( )。

表达变得简单

对矩阵元素的存取变得简单

去掉矩阵中的多余元素

减少不必要的存储空间

对特殊矩阵采用压缩存储的主要目的是为了减少不必要的存储空间。通过识别和利用矩阵中的特殊结构或特殊规律,可以使用更少的存储空间来表示矩阵,从而减少存储开销。这样可以节省存储空间,并降低存储和传输成本。

26.在解决计算机主机与打印机之间速度不匹配问题时通常设置一个打印缓冲区,该缓冲区应该是一个( )结构。

队列

数组

线性表

在解决计算机主机与打印机之间速度不匹配问题时,通常设置一个打印缓冲区,该缓冲区应该是一个队列结构。

使用队列结构可以保证打印作业按照先来先服务的原则进行处理。当打印机的处理速度慢于计算机主机的传输速度时,打印缓冲区可以暂时存储待打印的作业,然后按照顺序逐一传输到打印机进行打印。

27.若某线性表中最常用的操作是取第i个元素和找第i个元素的前驱,则采用( )存储方法最节省时间。

顺序表

单链表

双链表

单循环链表

若某线性表中最常用的操作是取第 i 个元素和找第 i 个元素的前驱,采用顺序表存储方法最节省时间。顺序表可以通过下标直接访问元素,时间复杂度为 O(1),而单链表、双链表以及单循环链表在取第 i 个元素的操作中需要遍历至第 i 个节点,时间复杂度为 O(i)。因此,在此情况下,采用顺序表存储方法可以最节省时间。

  1. 在一个单链表中,已知q所指结点是p所指结点的直接前驱,若在q和p之间插入s所指结点,则执行( )操作。

s->next=p->next; p-> next=s;

q->next=s; s->next=p;

p->next=s->next; s->next=p;

p->next=s; s->next=q;

在一个单链表中,已知 q 所指结点是 p 所指结点的直接前驱,若在 q 和 p 之间插入 s 所指结点,应执行以下操作:

q->next=s; s->next=p;

这样可以将 s 插入到 q 和 p 之间,完成链表的插入操作。

29.关于矩阵压缩存储,下面的说法中,不正确的是( )。

对称矩阵只需存放包括主对角线元素在内的下(或上)三角的元素即可

对角矩阵只需存放非零元素即可

稀疏矩阵中值为零的元素较多,因此可以采用三元组表方法存储

稀疏矩阵中大量值为零的元素分布有规律,因此可以采用三元组表方法存储

关于矩阵压缩存储,不正确的说法是:

稀疏矩阵中大量值为零的元素分布有规律,因此可以采用三元组表方法存储。

虽然稀疏矩阵中大量值为零的元素可以采用三元组表方法存储,但并不一定有规律。使用三元组表方法存储的目的是为了有效地表示稀疏矩阵,并且避免存储大量无效的零元素,而不是基于元素分布的规律。

30.关于数组,下面的说法中,不正确的是( )。

数组是一种线性结构

数组是一种定长的线性结构

除了插入与删除操作外,数组的基本操作还有存取、修改、检索和排序等

数组的基本操作有存取、修改、检索和排序等,没有插入与删除操作

关于数组,不正确的说法是:

数组的基本操作有存取、修改、检索和排序等,没有插入与删除操作。

实际上,数组是一种定长的线性结构,长度在创建时被固定。在插入和删除元素时,需要移动其他元素以保持数组的连续性,这会导致较高的时间复杂度。因此,数组的插入和删除操作相对效率较低。

二、判断题

31.稀疏矩阵压缩存储后,必会失去随机存取功能。

正确

错误

稀疏矩阵压缩存储后,并不一定会失去随机存取功能。虽然压缩存储可能会限制某些随机存取功能,但这取决于具体的压缩算法和数据结构。例如,使用三元组表等压缩方式仍然可以支持随机存取功能,只是在稀疏矩阵中的零元素可能不会占据存储空间。因此,这个说法是不正确的。

32.将数组称为随机存取结构是因为随时可以对数组进行存取访问。

正确

错误

将数组称为随机存取结构是因为可以通过下标直接随机访问数组中的元素,因此说法是正确的。数组允许按照元素的索引进行快速访问,这意味着可以通过指定元素的索引位置来直接访问或修改元素的值。这种随机访问的特性使得数组成为一种支持高效随机访问的数据结构。

33.有n个元素依次进栈,则出栈序列有(n-1)/2种。

正确

错误

这个说法是错误的。出栈序列的数量不一定是 (n-1)/2。实际上,对于给定的n个元素,有许多不同的出栈序列可能。出栈序列的数量取决于具体的排列组合情况,而不是简单地等于 (n-1)/2。具体的出栈序列数量需要根据出栈顺序的特定限制条件进行计算。

34.栈可以作为实现过程调用的一种数据结构。

正确

错误

栈可以作为实现过程调用的一种数据结构,因此这个说法是正确的。在程序执行过程中,当一个过程调用另一个过程时,会将返回地址、参数和局部变量等信息存储在栈中。这些信息以堆栈的形式保存,即后调用的函数压栈,先调用的函数出栈。栈的特点使得它非常适合用于实现过程调用和递归等计算机程序中。

35.在栈满的情况下不能做进栈操作,否则将产生“上溢”。

正确

错误

在栈满的情况下进行进栈操作将导致栈上溢,这会导致数据丢失或程序异常终止。因此,这个说法是正确的。栈有一个容量限制,当栈已满时,无法再进行进栈操作。如果强行进行进栈操作,将导致栈上溢(stack overflow),可能会损坏其他数据或引发程序异常。因此,在实现栈时,通常需要考虑栈上溢的情况并进行相应的处理。

36.在循环队列中,front指向队头元素的前一个位置rear指向队尾元素的位置,则队满的条件是front=rear。

正确

错误

在循环队列中,通常采用取模运算来实现循环。front 指向队头元素的位置,rear 指向队尾元素的下一个位置。因此,队满的条件是 (rear + 1) % n == front,其中 n 是队列的最大容量。

因此,说法是错误的。队满的条件不是 front = rear,而是 (rear + 1) % n == front

37.在单链表中,要取得某个元素,只要知道该元素所在结点的地址即可,因此单链表是随机存取结构。

正确

错误

在单链表中,虽然可以通过知道该元素所在结点的地址来访问该元素,但这种访问方式并不属于随机存取,因为单链表不支持通过下标或索引直接访问元素。单链表只能通过从头结点开始逐个遍历查找的方式来找到指定位置的元素,这导致了访问的时间复杂度是 O(n)。因此,单链表并不属于随机存取结构。

38.每种数据结构都具备三个基本操作:插入、删除和查找。

正确

错误

这个说法是不准确的。尽管许多数据结构确实具有插入、删除和查找等基本操作,但并不是每种数据结构都具备这三种基本操作。不同类型的数据结构可能有不同的设计目标和特定的操作。有些数据结构可能只支持其中一些操作,而另一些数据结构可能具有不同的基本操作。因此,不能将每种数据结构都简单地归纳为具有这三个基本操作。

39.线性结构的基本特征是:每个元素有且仅有一个直接前驱和一个直接后继。

正确

错误

线性结构的基本特征是每个元素最多只有一个直接前驱和一个直接后继,而不是有且仅有一个。这意味着某些元素可以没有直接前驱或直接后继(比如第一个元素和最后一个元素)。因此,说法是错误的。

40.算法的时间复杂度都要通过算法中的基本语句的执行次数来确定。

正确

错误

这个说法是正确的。算法的时间复杂度是通过对算法中的基本语句执行次数的分析来确定的。基本语句通常是指算法中执行最频繁的操作,例如赋值语句、比较语句、算术运算等。通过计算基本语句执行的次数,可以得出算法的时间复杂度,从而评估算法的执行效率。

三、简答题

  1. 试解释数据结构、数据类型、抽象数据类型的概念

  • 数据结构:数据结构是计算机科学中一种特殊的方式,它可以使我们在计算机中更有效地存储和组织数据。例如,我们可以使用数组、链表、栈、队列、图和树等数据结构来存储和管理数据。
  • 数据类型:数据类型是编程语言中的一个概念,它定义了一组数据的值的集合和这组数据上可进行的操作。例如,整数类型(int)定义了整数的集合,我们可以对这些整数进行加法、减法、乘法和除法等操作。
  • 抽象数据类型(ADT):抽象数据类型是一种逻辑描述,它定义了一组数据和在这组数据上可进行的操作,但并未指定这些操作的具体实现。例如,栈ADT定义了一组元素和两个基本操作:push(将元素添加到栈顶)和 pop(从栈顶移除元素)。然而,栈ADT并未指定这些操作应如何实现。我们可以使用数组或链表来实现栈ADT。
  1. 以下为单链表在指定位置插入元素的 C++代码,请将划线处代码补充完整。

    以下是将划线处代码补充完整的 C++ 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    template <typename DataType>
    void LinkList<DataType>::Insert(int i, DataType x)
    {
    Node<DataType> *p = first, *s = nullptr;
    int count = 0;
    while (p != nullptr && count < i - 1) // (1) 划线处
    {
    p = p->next;
    count++;
    }
    if (p == nullptr)
    throw "插入位置错误";
    else
    {
    s = new Node<DataType>(x);
    s->next = p->next; // (2) 划线处
    p->next = s; // (3) 划线处
    if (p == last) // (4) 划线处
    last = s;
    length++; // (5) 划线处
    }
    }

    在这段代码中:

    1. 划线处 (1) 是 while 循环的条件,用于寻找指定位置的插入点。
    2. 划线处 (2) 将新节点 s 的 next 指针指向 p 后面的节点。
    3. 划线处 (3) 将 p 的 next 指针指向新节点 s。
    4. 划线处 (4) 检查是否是在链表末尾插入,如果是,则更新 last 指针。
    5. 划线处 (5) 增加链表的长度。
  2. 如下为循环队列的实现代码,给出了类定义、构造函数、入队和出队函数,请 补充完整划线处代码。

    以下是补充完整划线处代码的实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    const int QueueSize = 100;
    template <typename DataType>
    class CirQueue
    {
    public:
    CirQueue();
    ~CirQueue();
    void EnQueue(DataType x);
    DataType DeQueue();
    DataType GetHead();
    int Empty();

    private:
    DataType data[QueueSize];
    int front, rear;
    };

    template <typename DataType>
    CirQueue<DataType>::CirQueue()
    {
    front = rear = 0; // (1) 划线处
    }

    template <typename DataType>
    void CirQueue<DataType>::EnQueue(DataType x)
    {
    if ((rear + 1) % QueueSize == front) // (2) 划线处
    throw "队满,上溢出";
    rear = (rear + 1) % QueueSize; // (3) 划线处
    data[rear] = x;
    }

    template <typename DataType>
    DataType CirQueue<DataType>::DeQueue()
    {
    if (front == rear) // (4) 划线处
    throw "下溢";
    front = (front + 1) % QueueSize; // (5) 划线处
    return data[front];
    }

    在代码中:

    1. 划线处 (1) 完成了循环队列的构造函数,将 front 和 rear 初始化为 0。
    2. 划线处 (2) 是判断队列是否已满的条件。
    3. 划线处 (3) 更新 rear 的位置,使其指向下一个入队元素应该存放的位置。
    4. 划线处 (4) 是判断队列是否为空的条件。
    5. 划线处 (5) 更新 front 的位置,使其指向下一个出队元素的位置。
  3. 如下代码为顺序表和单链表的 C++类定义,请补充划线处缺失的代码,并对 含义进行注释。

    <1> 顺序表:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    const int MaxSize = 100;
    template <typename DataType>
    class SeqList
    {
    public:
    SeqList();
    SeqList(DataType a[], int n);
    ~SeqList();
    int Length();
    int Empty();
    void PrintList();
    DataType Get(int i);
    int Locate(DataType x);
    void Insert(int i, DataType x);
    DataType Delete(int i);

    private:
    DataType data[MaxSize]; // (1) 顺序表的数据存储数组
    int length; // (2) 顺序表的当前长度
    };

    <2> 单链表:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    template <typename DataType>
    struct Node
    {
    DataType data; // (3) 节点中存储的数据
    Node<DataType> *next; // (4) 指向下一个节点的指针
    };

    template <typename DataType>
    class LinkList
    {
    public:
    LinkList();
    LinkList(DataType a[], int n);
    ~LinkList();
    void PrintList();
    int Length();
    DataType Get(int i);
    int Locate(DataType x);
    void Insert(int i, DataType x);
    DataType Delete(int i);

    private:
    Node<DataType> *first; // (5) 单链表的头指针
    };

    在代码中:

    1. 划线处 (1) 是顺序表的数据存储数组。
    2. 划线处 (2) 是顺序表的当前长度。
    3. 划线处 (3) 是单链表节点中存储的数据。
    4. 划线处 (4) 是指向下一个节点的指针。
    5. 划线处 (5) 是单链表的头指针。
  4. 以下为顺序栈的定义、初始化和压栈操作的实现,请补充完整划线部分代码。

    以下是补充完整划线部分代码的实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    const int StackSize = 100;
    template <typename DataType>
    class SeqStack
    {
    public:
    SeqStack();
    ~SeqStack();
    void Push(DataType x);
    DataType Pop();
    DataType GetTop();

    private:
    DataType data[StackSize]; // (1) 划线处
    int top; // (2) 划线处
    };
    template <typename DataType>
    SeqStack<DataType>::SeqStack()
    {
    top = -1; // (3) 划线处
    }
    template <typename DataType>
    void SeqStack<DataType>::Push(DataType x)
    {
    if (top == StackSize - 1) // (4) 划线处
    {
    cout << "栈满" << endl;
    throw "上溢";
    }
    top++; // (5) 划线处
    data[top] = x;
    }

    在代码中:

    1. 划线处 (1) 定义了顺序栈的数据存储数组。
    2. 划线处 (2) 定义了顺序栈的栈顶指针。
    3. 划线处 (3) 是顺序栈的构造函数,初始化栈顶指针 top 为 -1。
    4. 划线处 (4) 是判断栈是否已满的条件。
    5. 划线处 (5) 是实现元素压栈操作,将栈顶指针 top 向上移动一个位置,并将元素 x 压入栈顶。
  5. 设目标主串为 S=“BBCABCDABABCDABD”,模式串为 T=“ABCDABD”

    1. 简述按 BF 算法对主串 S 进行模式匹配的过程;

      BF(Brute-Force)算法是一种简单直接的字符串匹配算法。其匹配过程为: 从主串 S 的第一个字符开始,依次和模式串 T 进行匹配。如果当前字符匹配成功,则继续比较下一个字符,直到模式串 T 完全匹配或者匹配失败。如果匹配失败,则将模式串向右移动一位,再次和主串进行匹配。这个过程会一直持续到找到匹配的子串或者主串遍历完毕。

    2. 手工计算模式串 T 的 next 值;

      手工计算模式串 T 的 next 数组的过程如下:

      T = “ABCDABD”

      首先,next[0] = -1,next[1] = 0(规定 next 数组下标从 0 开始)。

      依次计算 next 数组的值:

      对于第 i 个字符,如果 T[next[i]] == T[i-1],则 next[i+1] = next[i] + 1;

      否则,将 next[i+1] 更新为 0。

    3. 简述利用求得的 next 数组,按 KMP 算法对主串 S 进行模式匹配的过程。

      KMP 算法利用模式串 T 的 next 数组在匹配过程中避免不必要的回溯。匹配过程如下: 从主串 S 的第一个字符开始,同时从模式串 T 的第一个字符开始进行匹配。 如果当前字符匹配成功,则继续比较下一个字符。 如果匹配失败,根据 next 数组进行回溯操作,将模式串 T 向右移动相应的位数,使得模式串能够对齐主串中的下一个字符,继续匹配。 如果模式串完全匹配成功,则返回匹配的起始位置;否则,主串遍历完毕仍未找到匹配子串,则匹配失败。

    四、附加题

    请认真思考,谈一下你对数据结构课程的建议。(限 100 字以上,共 10 分)

    这题没什么好说的