数据结构 机考真题
循环链表表示队列
题干
假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素结点(注意不设头指针),请完成下列任务:
- 队列初始化,成功返回真,否则返回假:
1
| bool init_queue(LinkQueue *LQ);
|
- 入队列,成功返回真,否则返回假:
1
| bool enter_queue(LinkQueue *LQ, ElemType x);
|
- 出队列,成功返回真,且*x为出队的值,否则返回假
1
| bool leave_queue(LinkQueue *LQ, ElemType *x);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| typedef struct _QueueNode { ElemType data; struct _QueueNode *next; } LinkQueueNode, *LinkQueue;
#include <stdio.h> #include <stdlib.h>
bool init_queue(LinkQueue *LQ) {
}
bool enter_queue(LinkQueue *LQ, ElemType x) {
}
bool leave_queue(LinkQueue *LQ, ElemType *x) {
}
|
题解
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 41 42 43 44 45
| bool init_queue(LinkQueue *LQ) { (*LQ) = (LinkQueue)malloc(sizeof(LinkQueueNode)); if ((*LQ) == NULL) return false; (*LQ)->data = 0; (*LQ)->next = (*LQ);
return true; }
bool enter_queue(LinkQueue *LQ, ElemType x) { LinkQueue NewNode = (LinkQueue)malloc(sizeof(LinkQueueNode)); if (NewNode == NULL || (*LQ) == NULL) return false;
NewNode->data = x; NewNode->next = (*LQ)->next; (*LQ)->next = NewNode; (*LQ) = NewNode;
return true; }
bool leave_queue(LinkQueue *LQ, ElemType *x) { if ((*LQ) == NULL) return false; if ((*LQ)->next == (*LQ)) return false;
LinkQueue HeadNode = (*LQ)->next; LinkQueue LeaveNode = HeadNode->next;
HeadNode->next = LeaveNode->next; *x = LeaveNode->data; if ((*LQ) == LeaveNode) (*LQ) = HeadNode; free(LeaveNode);
return true; }
|
非递归先序遍历
题干
已知二叉树按照二叉链表方式存储,利用栈的基本操作写出先序遍历非递归形式的算法:
void pre_order(BiTree root);
在遍历过程中,pre_order
函数需要调用 visit_node
函数来实现对结点的访问,该函数声明如下:
void visit_node(BiTNode *node);
二叉树的相关定义如下:
1 2 3 4 5 6 7
| typedef int DataType;
typedef struct Node{ DataType data; struct Node* left; struct Node* right; }BiTNode, *BiTree;
|
遍历所使用栈的相关操作如下:
1 2 3 4 5 6 7 8 9 10 11 12
| #define Stack_Size 50 typedef BiTNode* ElemType; typedef struct{ ElemType elem[Stack_Size]; int top; }Stack;
void init_stack(Stack *S); bool push(Stack* S, ElemType x); bool pop(Stack* S, ElemType *px); bool top(Stack* S, ElemType *px); bool is_empty(Stack* S);
|
请在下方编写代码:
1 2 3 4 5
| #include <stdlib.h>
void pre_order(BiTree root) { }
|
题解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void pre_order(BiTree root) { if (!root) return false; Stack S; init_stack(&S);
BiTree CurrNode = root; while (!is_empty(&S) || !CurrNode) { if (CurrNode) { visit_node(CurrNode); push(&S, CurrNode); CurrNode = CurrNode->left; } else { pop(&S, &CurrNode); CurrNode = CurrNode->right; } } }
|
特地赠送中序遍历和后序遍历大礼包!
中序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void in_order(BiTree root) { if (!root) return;
Stack S; init_stack(&S);
BiTree CurrNode = root;
while (!is_empty(&S) || CurrNode) { if (CurrNode) { push(&S, CurrNode); CurrNode = CurrNode->left; } else { pop(&S, &CurrNode); visit_node(CurrNode); CurrNode = CurrNode->right; } } }
|
后序遍历
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
| void post_order(BiTree root) { if (!root) return;
Stack S1, S2; init_stack(&S1); init_stack(&S2);
BiTree CurrNode = root; push(&S1, CurrNode);
while (!is_empty(&S1)) { pop(&S1, &CurrNode); push(&S2, CurrNode);
if (CurrNode->left) push(&S1, CurrNode->left); if (CurrNode->right) push(&S1, CurrNode->right); }
while (!is_empty(&S2)) { pop(&S2, &CurrNode); visit_node(CurrNode); } }
|
邻接矩阵
题干
试在邻接矩阵存储结构上实现图的基本操作matrix_insert_vertex
和 matrix_insert_arc
,相关定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| typedef int VertexType;
typedef enum{ DG, UDG }GraphType;
typedef struct{ VertexType vertex[MAX_VERTEX_NUM]; int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; int vexnum, arcnum; GraphType type; }MatrixGraph;
int matrix_locate_vertex(MatrixGraph *MG, VertexType vex); bool matrix_insert_vertex(MatrixGraph *G, VertexType v); bool matrix_insert_arc(MatrixGraph *G, VertexType v, VertexType w);
|
当成功插入顶点或边时,函数返回true,否则(如顶点或边已存在、插入边时顶点v或w不存在)返回false。
请在下方编写代码
1 2 3 4 5 6 7
| bool matrix_insert_vertex(MatrixGraph *G, VertexType v){
}
bool matrix_insert_arc(MatrixGraph *G, VertexType v, VertexType w){ }
|
题解
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 41 42 43 44 45 46
| bool matrix_insert_vertex(MatrixGraph *G, VertexType v){ if (G == NULL) return false; if (G->vexnum >= MAX_VERTEX_NUM || matrix_locate_vertex(G, v) != -1) return false; G->vertex[G->vexnum] = v; for (int i = 0; i <= G->vexnum; i++) { G->arcs[G->vexnum][i] = 0; G->arcs[i][G->vexnum] = 0; } G->vexnum++;
return true; }
bool matrix_insert_arc(MatrixGraph *G, VertexType v, VertexType w){ if (G == NULL) return false; int v_index = matrix_locate_vertex(G, v); int w_index = matrix_locate_vertex(G, w);
if (v_index == -1 || w_index == -1) return false;
if (G->type == DG) { if (G->arcs[v_index][w_index] != 0) return false; G->arcs[v_index][w_index] = 1; G->arcnum++; } else { if (G->arcs[v_index][w_index] != 0 || G->arcs[w_index][v_index] != 0) return false;
G->arcs[v_index][w_index] = 1; G->arcs[w_index][v_index] = 1; G->arcnum++; } return true; }
|
顺序表
题干
顺序表相关定义及辅助函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #define MAXSIZE 100 #define OK 1 #define ERROR 0
typedef struct{ int elem[MAXSIZE]; int last; }SeqList;
void print_num(char* format, int num);
void read_num(char* format, int* pnum);
|
请按要求实现非递减顺序表合并的相关函数
1 2 3 4 5
| void initList(SeqList *L); void printList(SeqList *L); void inputData(SeqList *L); void merge(SeqList *LA, SeqList *LB, SeqList *LC);
|
其中,
initList
函数初始化 L
的 last
域为 -1
;
printList
函数调用print_num
实现在屏幕上显示顺序表L的元素值;
inputData
函数调用read_num
实现顺序表L的初始化,当读到的数为负数时停止读取数据;
(要求:printList
必须调用print_num
函数,inputData
必须调用调用read_num
,否则检查不通过);
merge
函数合并非递减顺序表LA
和LB
,结果放入非递减顺序表LC
中,示例如下:
1 2 3
| La=(1 3 5 7 9 11 ) Lb=(2 4 6 8 10 ) Lc(La+Lb)=(1 2 3 4 5 6 7 8 9 10 11 )
|
题解
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| void initList(SeqList *L) { L->last = -1; }
void printList(SeqList *L) { if (L == NULL) return;
for (int i = 0; i <= L->last; i++) { print_num("%d", L->elem[i]); } }
void inputData(SeqList *L) { if (!L) return;
int CurrInputNum; read_num("%d", &CurrInputNum); while (CurrInputNum >= 0) { L->elem[++L->last] = CurrInputNum; read_num("%d", &CurrInputNum); } }
void merge(SeqList *LA, SeqList *LB, SeqList *LC) { if (LA == NULL || LA->last == -1) { LC = LB; return; }
if (LB == NULL || LB->last == -1 ) { LC = LA; return; }
int AIndex = 0; int BIndex = 0; int CIndex = 0;
while (AIndex <= LA->last && BIndex <= LB->last) { if (LA->elem[AIndex] <= LB->elem[BIndex]) { LC->elem[CIndex] = LA->elem[AIndex]; AIndex++; CIndex++; } else { LC->elem[CIndex] = LB->elem[BIndex]; CIndex++; BIndex++; } }
if (AIndex <= LA->last) { while (AIndex <= LA->last) { LC->elem[CIndex] = LA->elem[AIndex]; CIndex++; AIndex++; } }
if (BIndex < LB->last) { while (BIndex <= LB->last) { LC->elem[CIndex] = LB->elem[BIndex]; CIndex++; BIndex++; } }
LC->last = CIndex - 1; }
|
树的层序遍历
题干
已知树的定义如下:
1 2 3 4
| typedef struct node{ int data; struct node *left, *right; }node, *tree;
|
实现函数:
1
| void check_tree_level_visit(int keys[], int n);
|
- 根据 keys 中输入的顺序,生成一棵二叉排序树。
- 再按层次遍历方式访问,将访问所得的关键字按顺序保存至keys数组中。
- n 为 keys 数组的长度(1 ≤ n ≤ 100)。
- 可以有辅助函数。
样例输入:[36,53,28,68,9,33]
样例输出:[36,28,53,9,33,68]
题解
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| node* CreateNode(int data) { node* New = (tree)malloc(sizeof(node)); if (!New) return NULL; New->data = data; New->left = New->right = NULL;
return New; }
void InsertBST(tree* root, int data) { if (!root) { *root = CreateNode(data); } else { if ((*root)->data < data) { InsertBST(&(*root)->right, data); } else { InsertBST(&(*root)->left, data); } } }
void LevelOrder(tree T, int keys[], int* index) { if (T == NULL) return; tree queue[1000]; int Front = 0, Rear = 0;
queue[Rear++] = T;
while (Front < Rear) { tree Curr = queue[Front++];
keys[*index++] = Curr->data;
if (Curr->left != NULL) queue[Rear++] = Curr->left; if (Curr->right != NULL) queue[Rear++] = Curr->right; } }
void check_tree_level_visit(int keys[], int n) { tree T = NULL;
for (int i = 0; i < n; i++) { InsertBST(&T, keys[i]); }
int index = 0; LevelOrder(T, keys, &index); }
|
线性探测法
题干
线性哈希是一种简单的哈希方法,其中哈希函数为 H(key) = key \mod m
,其中 m
是哈希表的长度。当发生冲突时,线性探测法会寻找下一个空闲位置来存储关键字。具体来说,如果位置 H(key)
被占用,则检查 H(key) + 1
,然后是 H(key) + 2
,依此类推,直到找到一个空位。
函数 void print_hash_array(int arr[],int n);
应该实现以下功能:
- 创建一个大小为 13 的哈希表(保证输入数据为13个)。
- 遍历给定的关键字数组,对每个关键字应用哈希函数。
- 如果哈希位置已被占用,则使用线性探测法找到下一个空闲位置。
- 在找到的位置存储关键字。
- 打印哈希表的内容,以验证关键字是否正确存储。
样例输入:[1,5,21,26,39,14,15,16,17,18,19,20,111]
样例输出:[26,1,39,14,15,5,16,17,21,18,19,20,111]
题解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #define TABLE_SIZE 13 void print_hash_array(int arr[],int n) { int HashTable[TABLE_SIZE];
memset(HashTable, -1, sizeof(HashTable));
for (int i = 0; i < n; i++) { int key = arr[i]; int hash = key % TABLE_SIZE;
while(HashTable[hash] != -1) { hash = (hash + 1) % TABLE_SIZE; }
HashTable[hash] = key; }
for (int i = 0; i < TABLE_SIZE; i++) { if (HashTable[i] != -1) { printf("%d ", HashTable[i]); } } printf("\n"); }
|
整数移除
题干
有线性表的存储结构表示如下:
1 2 3 4 5
| #define MAXLEN 128 typedef struct { int elem[MAXLEN]; unsigned len; } list;
|
请设计一个算法,其功能是:
在一个给定的线性表中,移除所有能被指定正整数整除的元素
操作完成后的线性表中保留的元素呈连续存储的状态
算法函数原型:
void remove_elem(list \*L, unsigned f);
功能:在线性表 L 中移除所有能被 f 整除的元素。
参数:
L:指向线性表的指针。线性表可能为空。
f:整除因子。测试用例保证 f 不小于 2。 返回值:无
编码约束
时间复杂度:O(L->len)
空间复杂度:O(1)
题解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void remove_elem(list *L, unsigned f) { if (!L) return; int SearchIndex = 0; int NewIndex = 0;
while (SearchIndex < L->len) { if (L->elem[SearchIndex] % f != 0) { L->elem[NewIndex] = L->elem[SearchIndex]; NewIndex++; } SearchIndex++; }
L->len = NewIndex; }
|
共享结点
题干
有单链表表示的线性表结构定义如下:
1 2 3 4 5 6 7 8 9 10 11
| typedef struct _node { int data; struct _node *next; } node;
typedef struct { node *head; unsigned len; } list;
|
现已知有两个上述类型的线性表 La 和 Lb,二者在某个结点处融合在一起。请设计一个算法,计算两个链表共享结点的数量。
算法函数原型
int list_shared(list *La, list *Lb);
- 功能:计算并返回线性表 La 和 Lb 的共享结点的数量
- 参数:La 和 Lb 都是指向线性表的指针
- 返回值:La 和 Lb 共享结点的数目
编码约束
- 时间复杂度:
O(max(La->len, Lb->len))
- 空间复杂度:
O(1)
题解
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 41 42 43 44 45 46 47 48 49 50 51 52
| int list_shared(list *La, list *Lb) { int count = 0; if (La->head == NULL || Lb->head == NULL) return count;
node* PtrA = La->head; node* PtrB = Lb->head; int Len_A = 0; int Len_B = 0;
while (PtrA != NULL) { Len_A++; PtrA = PtrA->next; } while (PtrB != NULL) { Len_B++; PtrB = PtrB->next; } if (PtrA != PtrB) return count;
PtrA = La->head; PtrB = Lb->head; while (Len_A > Len_B) { PtrA = PtrA->next; Len_A--; } while (Len_A < Len_B) { PtrB = PtrB->next; Len_B--; }
while (PtrA != PtrB && PtrA && PtrB) { PtrA = PtrA->next; PtrB = PtrB->next; }
while (PtrA) { PtrA = PtrA->next; count++; } return count; }
|
反转字符串
题干
有一个递归函数如下:
1 2 3 4 5 6 7 8
| void reverse() { char c = getchar(); if (c == '.') return;
reverse(); putchar(c);
}
|
其功能是将输入的字符序列(以’.’结尾)倒序输出(不包括’.’)。例如:
输入:abc123.
输出:321cba
另有可用的栈接口函数如下:
1 2 3
| void push(stack *S, char x); char pop(stack *S); bool empty(stack * S);
|
请设计一个算法,利用栈,消除 reverse()中的递归,但功能不变。
算法函数原型:
void reverse(stack *S);
功能:将输入的字符序列倒序输出。输入以’.’结尾。
参数:S 是指向栈的指针。栈 S 已经初始化。
返回值:无
编码约束:
时间复杂度:无特别要求
空间复杂度:O(1)(不计栈空间)
提示:常量空间复杂度意味着,除了使用栈和单个变量,你不能定义类似于数组这样的辅助存储。
题解
1 2 3 4 5 6 7 8 9 10 11 12
| void reverse(stack *S) { char c = getchar(); while (c != '.') { push(S, c) c = getchar(); }
while (!empty(S)) { c = pop(S); putchar(c); } }
|
镜像二叉树
题干
设有两棵二叉树t1和t2。如果t2是t1左右翻转得到,那么称二叉树t1和t2互为镜像。
图像链接
二叉树的存储结构如下:
1 2 3 4
| typedef struct _btree_node { char tag; struct _btree_node *left, *right; } btree_node, *btree;
|
请设计一个算法,实现一棵二叉树的镜像翻转。
算法函数原型
btree mirror(btree tree);
功能:生成二叉树tree的镜像二叉树,返回镜像二叉树的根结点指针。
参数:tree是指向源二叉树根结点的指针
返回值:指向二叉树tree的镜像二叉树根结点的指针
编码约束
时间复杂度和空间复杂度均无要求
题解
1 2 3 4 5 6 7 8
| btree mirror(btree tree) { if (!tree) return NULL; btree t = (btree) malloc(sizeof(btree_node)); t->tag = tree->tag; t->left = mirror(tree->right); t->right = mirror(tree->left); return t; }
|