南邮811代码题及答案

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

四、算法设计题

  1. (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

五、算法设计题

  1. 设二叉树采用二叉链表存储,每个结点有三个域: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

四、算法设计题

  1. 编程实现利用队列将栈中元素逆置的算法
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

三、程序设计题

  1. 运用数据结构中所学知识,设计一个算法求树的带权路径长度。
#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;
}

这段代码创建了一棵示例树,计算了它的带权路径长度,并释放了动态分配的内存,以确保不发生内存泄漏。

  1. 运用数据结构中所学知识,设计一个算法求二叉树中指定结点的深度。
    要求二叉树中指定节点的深度,可以使用递归算法来实现。深度是从根节点开始的,因此需要从根节点出发递归地搜索指定节点,并记录搜索的深度。以下是一个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. 如何使用两个栈,使实现一个队列的功能。

答:
1)创建两个栈结构,一个用于入队操作(通常称为栈A),另一个用于出队操作(通常称为栈B)。
2)初始化两个栈,并确保它们的容量足够满足队列的需求。
3)对于入队操作,直接将元素压入栈A。
4)对于出队操作,首先检查栈B是否为空。如果栈B为空,将栈A的元素逐个出栈并压入栈B,然后从栈B出栈,以确保队列的FIFO行为。
5)确保在出队操作时,栈B不为空。

2016

四、算法设计题

  1. 设计一个递归算法,求 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

三、

  1. 设计将两个有序链表合并为一个有序链表的算法,假设有序链表的元素按照非递减排列。数据域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;
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值