2002
四、设计一个算法将一个带表头结点的单链表Y,连接在另一个带表头结点单链表X之后。单链表的每个结点有两个域:data和link。算法可用Pascal语言或C语言描述,要求写出类型说明。
#include <stdio.h>
#include <stdlib.h>
// 定义单链表节点结构
typedef struct Node {
int data;
struct Node* link;
} Node;
// 定义带表头结点的单链表结构
typedef struct LinkedList {
Node* head;
} LinkedList;
// 初始化带表头结点的单链表
void initializeList(LinkedList* L) {
L->head = (Node*)malloc(sizeof(Node));
L->head->link = NULL;
}
// 插入一个新节点到单链表尾部
void insertNode(LinkedList* L, int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->link = NULL;
Node* current = L->head;
while (current->link != NULL) {
current = current->link;
}
current->link = newNode;
}
// 连接两个带表头结点的单链表X和Y
void connectLists(LinkedList* X, LinkedList* Y) {
Node* current = X->head;
while (current->link != NULL) {
current = current->link;
}
current->link = Y->head->link; // 将Y的头节点的下一个节点连接到X的尾部
free(Y->head); // 释放Y的头节点,但保留Y的数据节点
}
// 打印单链表的内容
void printList(LinkedList* L) {
Node* current = L->head->link;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->link;
}
printf("NULL\n");
}
int main() {
LinkedList X, Y;
initializeList(&X);
initializeList(&Y);
// 向X和Y中插入一些数据
for (int i = 1; i <= 5; i++) {
insertNode(&X, i);
insertNode(&Y, i + 5);
}
printf("X: ");
printList(&X);
printf("Y: ");
printList(&Y);
connectLists(&X, &Y);
printf("Connected List: ");
printList(&X);
return 0;
}
}
2003
2006
四、算法设计题
- (16 分)设一棵 n 个结点的完全二叉树采用顺序存储结构,保存在一维数组 A中。试设计一个递归算法,复制该完全二叉树,得到一棵新的采用普通二叉链表存储的二叉树。二叉链表的每个结点有三个域:lchild,rchild 和 element。算法返回所构造的新二叉树的根结点地址。
#include <stdio.h>
#include <stdlib.h>
// 定义二叉树结点结构
struct TreeNode {
int element;
struct TreeNode *lchild; // 左子树指针
struct TreeNode *rchild; // 右子树指针
};
// 递归函数:复制完全二叉树并转换为二叉链表
struct TreeNode* copyTree(int A[], int n, int index) {
// 递归结束条件:如果当前索引超出数组长度,则返回空指针
if (index >= n) {
return NULL;
}
// 创建一个新结点
struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));
newNode->element = A[index]; // 设置结点的元素值
newNode->lchild = NULL; // 初始化左子树指针
newNode->rchild = NULL; // 初始化右子树指针
// 递归复制左子树,左子树的索引是当前索引的 2 倍加 1
newNode->lchild = copyTree(A, n, 2 * index + 1);
// 递归复制右子树,右子树的索引是当前索引的 2 倍加 2
newNode->rchild = copyTree(A, n, 2 * index + 2);
// 返回当前结点的指针
return newNode;
}
// 递归函数:释放二叉树结点的内存
void freeBinaryTree(struct TreeNode* root) {
// 递归结束条件:如果根结点为空,无需释放内存
if (root == NULL) {
return;
}
// 递归释放左子树和右子树的内存
freeBinaryTree(root->lchild);
freeBinaryTree(root->rchild);
// 释放当前结点的内存,释放整个二叉树的内存是为了防止内存泄漏。
//在C语言中,动态分配的内存需要手动释放,否则在程序运行过程中,这些内存将一直占用系统资源,直到程序结束才会被释放。
//如果你不释放二叉树的内存,特别是在涉及大量结点的情况下,程序将不断占用更多内存,最终可能导致内存耗尽。
free(root);
}
int main() {
int A[] = {1, 2, 3, 4, 5, 6, 7};
int n = sizeof(A) / sizeof(A[0]); // 计算数组 A 的大小
// 复制并转换二叉树,从根结点开始复制
struct TreeNode* root = copyTree(A, n, 0);
// 在这里可以执行其他操作...
// 释放二叉树内存,包括所有结点
freeBinaryTree(root);
return 0;
}
2010
五、算法设计题
- 设二叉树采用二叉链表存储,每个结点有三个域:element,lchild 和 rchild。试编写算法,判别两棵二叉树是否相等,并同时统计二叉树中结点数目。分析你所设计的算法的时间复杂度。注:两棵二叉树相等是指它们的树形相同,且元素值一一对应相等。
#include <stdio.h>
#include <stdlib.h>
// 定义二叉树结点结构
struct TreeNode {
int element;
struct TreeNode *lchild; // 左子树指针
struct TreeNode *rchild; // 右子树指针
};
// 递归函数:判别两棵二叉树是否相等,同时统计节点数
int areEqualAndCount(struct TreeNode *root1, struct TreeNode *root2, int *count) {
// 递归结束条件:如果两个节点都为空,它们相等且不计入节点数
if (root1 == NULL && root2 == NULL) {
return 1;
}
// 递归结束条件:如果只有一个节点为空,它们不相等
if (root1 == NULL || root2 == NULL) {
return 0;
}
// 比较当前节点的值
if (root1->element != root2->element) {
return 0;
}
// 递归比较左子树和右子树
int leftEqual = areEqualAndCount(root1->lchild, root2->lchild, count);
int rightEqual = areEqualAndCount(root1->rchild, root2->rchild, count);
// 如果左右子树都相等,增加节点计数
if (leftEqual && rightEqual) {
// *count 表示获取指针 count 指向的整数的值,然后 (*count)++ 表示将该整数的值自增1。这是一种通常用于通过指针来修改传递给函数的变量值的方法。
(*count)++;
}
// 返回结果,判断左子树和右子树是否都相等,如果是,整棵树就被认为是相等的,返回 1;否则,返回 0 表示不相等。
return leftEqual && rightEqual;
}
int main() {
struct TreeNode *root1 = NULL; // 创建第一棵二叉树
struct TreeNode *root2 = NULL; // 创建第二棵二叉树
int count = 0; // 初始化节点计数器
// 调用函数来判断两棵二叉树是否相等,同时统计节点数
int result = areEqualAndCount(root1, root2, &count);
// 输出结果
if (result && count > 0) {
printf("两棵二叉树相等,共有 %d 个节点.\n", count);
} else {
printf("两棵二叉树不相等.\n");
}
return 0;
}
这个算法的时间复杂度取决于二叉树的大小,是 O(n),其中 n 表示二叉树的节点数。
2015
四、算法设计题
- 编程实现利用队列将栈中元素逆置的算法
template <class T>
void invertStack(SeqStack<T>& s) {
// 创建一个队列 q 来辅助逆置操作
SeqQueue<T> q(20);
// 将栈 s 中的元素逐个出栈并入队到队列 q 中
while (!s.IsEmpty()) {
q.EnQueue(s.Top()); // 出栈并入队
s.Pop();
}
// 将队列 q 中的元素逐个出队并入栈到栈 s 中
while (!q.IsEmpty()) {
s.Push(q.Front()); // 出队并入栈
q.DeQueue();
}
}
2017
三、程序设计题
- 运用数据结构中所学知识,设计一个算法求树的带权路径长度。
#include <stdio.h>
#include <stdlib.h>
// 树节点结构
struct TreeNode {
int value;
struct TreeNode* left;
struct TreeNode* right;
};
typedef struct TreeNode TreeNode;
// 创建一个新的树节点
TreeNode* createNode(int value) {
TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode)); // 分配内存来创建新的节点
newNode->value = value; // 设置节点的值
newNode->left = NULL; // 初始化左子树指针为NULL
newNode->right = NULL; // 初始化右子树指针为NULL
return newNode;
}
// 计算树的带权路径长度
int weightedPathLength(TreeNode* root, int depth) {
if (root == NULL) {
return 0; // 如果根节点为空,返回0
}
if (root->left == NULL && root->right == NULL) {
return depth * root->value; // 如果是叶子节点,返回叶子节点的值乘以深度
}
int leftPathLength = weightedPathLength(root->left, depth + 1); // 递归计算左子树的带权路径长度
int rightPathLength = weightedPathLength(root->right, depth + 1); // 递归计算右子树的带权路径长度
return leftPathLength + rightPathLength; // 返回左右子树的带权路径长度之和
}
int main() {
// 创建一棵树
TreeNode* root = createNode(5);
root->left = createNode(2);
root->right = createNode(8);
root->left->left = createNode(1);
root->left->right = createNode(3);
int wpl = weightedPathLength(root, 0); // 调用函数计算树的带权路径长度
printf("树的带权路径长度: %d\n", wpl); // 打印结果
// 释放内存以避免内存泄漏
free(root->left->left);
free(root->left->right);
free(root->left);
free(root->right);
free(root);
return 0;
}
这段代码创建了一棵示例树,计算了它的带权路径长度,并释放了动态分配的内存,以确保不发生内存泄漏。
- 运用数据结构中所学知识,设计一个算法求二叉树中指定结点的深度。
要求二叉树中指定节点的深度,可以使用递归算法来实现。深度是从根节点开始的,因此需要从根节点出发递归地搜索指定节点,并记录搜索的深度。以下是一个C语言的示例算法:
#include <stdio.h>
#include <stdlib.h>
// 二叉树节点结构
struct TreeNode {
int value;
struct TreeNode* left;
struct TreeNode* right;
};
typedef struct TreeNode TreeNode;
// 创建一个新的二叉树节点
TreeNode* createNode(int value) {
TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
newNode->value = value;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
// 在二叉树中搜索指定节点的深度
int findDepth(TreeNode* root, int target, int depth) {
if (root == NULL) {
return -1; // 如果根节点为空,返回-1表示未找到
}
if (root->value == target) {
return depth; // 找到目标节点,返回当前深度
}
int leftDepth = findDepth(root->left, target, depth + 1); // 在左子树中查找
if (leftDepth != -1) {
return leftDepth; // 如果在左子树中找到,返回左子树中的深度
}
int rightDepth = findDepth(root->right, target, depth + 1); // 在右子树中查找
return rightDepth; // 返回右子树中的深度
}
int main() {
// 创建一棵示例二叉树
TreeNode* root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
root->right->left = createNode(6);
root->right->right = createNode(7);
int targetValue = 5; // 要查找的目标节点值
int depth = findDepth(root, targetValue, 0); // 调用函数查找深度
if (depth != -1) {
printf("节点 %d 的深度是: %d\n", targetValue, depth);
} else {
printf("未找到节点 %d\n", targetValue);
}
// 释放内存以避免内存泄漏
free(root->left->left);
free(root->left->right);
free(root->left);
free(root->right->left);
free(root->right->right);
free(root->right);
free(root);
return 0;
}
上述代码会找到指定节点的深度,并在找到节点时返回深度,未找到节点时返回-1。
2018
三、算法题
2. 以二叉链表为存储结构,求二叉树高度。
算法思想:递归地计算每个节点的左子树和右子树的高度,并返回较大的那个高度加1。递归终止条件是节点为空(null)或是叶子节点。
#include <stdio.h>
#include <stdlib.h>
// 计算二叉树的高度,tree表示二叉树的数组,index 表示当前节点的索引,size 表示数组的大小。
int treeHeight(int tree[], int index, int size) {
// 递归终止条件:
// 1. 如果当前节点的索引超过数组大小或当前节点为空
if (index >= size || tree[index] == -1) {
return 0;
}
// 2. 递归计算左子树的高度
int leftHeight = treeHeight(tree, 2 * index + 1, size);
// 3. 递归计算右子树的高度
int rightHeight = treeHeight(tree, 2 * index + 2, size);
// 4. 返回左子树和右子树中较大的高度加1,表示当前节点的高度
return 1 + (leftHeight > rightHeight ? leftHeight : rightHeight);
}
int main() {
int binaryTree[] = {1, 2, 3, 4, -1, 6, 7}; // 示例二叉树,-1表示空节点
int size = sizeof(binaryTree) / sizeof(binaryTree[0]);
int height = treeHeight(binaryTree, 0, size);
printf("二叉树的高度: %d\n", height);
return 0;
}
2020
二、简答题
- 如何使用两个栈,使实现一个队列的功能。
答:
1)创建两个栈结构,一个用于入队操作(通常称为栈A),另一个用于出队操作(通常称为栈B)。
2)初始化两个栈,并确保它们的容量足够满足队列的需求。
3)对于入队操作,直接将元素压入栈A。
4)对于出队操作,首先检查栈B是否为空。如果栈B为空,将栈A的元素逐个出栈并压入栈B,然后从栈B出栈,以确保队列的FIFO行为。
5)确保在出队操作时,栈B不为空。
2016
四、算法设计题
- 设计一个递归算法,求 n 个不同数字的所有全排列。
#include <stdio.h>
void swap(char *a, char *b) {
// 交换两个字符的值
char temp = *a;
*a = *b;
*b = temp;
}
void permute(char *list, int k, int m) {
if (k == m) {
// 当 k 和 m 相等时,表示一个全排列生成完毕,输出它
for (int i = 0; i <= m; i++) {
putchar(list[i]); // 打印当前排列
}
putchar('\n'); // 换行以分隔排列
} else {
// 生成排列的递归函数
for (int i = k; i <= m; i++) {
swap(&list[k], &list[i]); // 交换第 k 个和第 i 个字符
permute(list, k + 1, m); // 递归生成其余部分的排列
swap(&list[k], &list[i]); // 恢复原始状态,以便生成下一个排列
}
}
}
int main() {
char input[] = "123"; // 用不同数字替换这个数组
int n = strlen(input) - 1; // 获取数组长度
// 调用全排列函数生成排列
permute(input, 0, n);
return 0;
}
结果
2021
三、
- 设计将两个有序链表合并为一个有序链表的算法,假设有序链表的元素按照非递减排列。数据域data,指针域link。
#include <stdio.h>
#include <stdlib.h>
// 定义链表结点
struct Node {
int data;
struct Node* link;
};
// 将两个有序链表合并为一个有序链表
struct Node* mergeLists(struct Node* head1, struct Node* head2) {
// 如果一个链表为空,直接返回另一个链表
if (head1 == NULL) {
return head2;
}
if (head2 == NULL) {
return head1;
}
// 新建一个头结点用于存储合并后的链表
struct Node* head = NULL;
if (head1->data <= head2->data) {
head = head1;
head1 = head1->link;
} else {
head = head2;
head2 = head2->link;
}
struct Node* current = head;
// 遍历两个链表进行合并
while (head1 != NULL && head2 != NULL) {
if (head1->data <= head2->data) {
current->link = head1;
head1 = head1->link;
} else {
current->link = head2;
head2 = head2->link;
}
current = current->link;
}
// 将剩余的结点链接到合并后的链表
if (head1 != NULL) {
current->link = head1;
} else {
current->link = head2;
}
return head;
}
// 测试
int main() {
// 创建有序链表1
struct Node* head1 = (struct Node*)malloc(sizeof(struct Node));
head1->data = 1;
head1->link = (struct Node*)malloc(sizeof(struct Node));
head1->link->data = 3;
head1->link->link = NULL;
// 创建有序链表2
struct Node* head2 = (struct Node*)malloc(sizeof(struct Node));
head2->data = 2;
head2->link = (struct Node*)malloc(sizeof(struct Node));
head2->link->data = 4;
head2->link->link = NULL;
// 合并两个有序链表
struct Node* merged = mergeLists(head1, head2);
// 打印合并后的链表
printf("Merged List: ");
struct Node* current = merged;
while (current != NULL) {
printf("%d ", current->data);
current = current->link;
}
printf("\n");
// 释放内存
free(head1->link);
free(head1);
free(head2->link);
free(head2);
return 0;
}