美文网首页
数据结构第三次作业

数据结构第三次作业

作者: XXX_f47c | 来源:发表于2019-05-24 14:19 被阅读0次

    第一题:二叉树的基础算法

    题目

    先根据二叉树的先序、中序遍历序列还原该二叉树,求出这棵二叉树的高度和宽度,以及其叶节点的个数。再将这棵二叉树在内存当中镜像克隆一份,输出克隆的这棵树的层次遍历序列,最后再释放掉这两棵树所占的内存空间。

    你需要实现以下几个函数:

    • Node* createTree(int preOrder[], int inOrder[], int N);

      • 二叉树的先序、中序遍历序列分别存放在preOrderinOrder数组当中,这两个数组存放元素的个数都为N。
      • 函数返回创建好的二叉树的根节点指针
    • int getTreeHeight(Node* root);

      • 约定:空树的高度为0,一棵树如果只有1个节点(根节点)其高度为1
    • int getTreeWidth(Node* root);

      • 树的宽度是指:拥有节点数最多的那一层的节点数。
    • int countLeafNode(Node* root);

      • 返回二叉树中叶节点的个数,这个没什么好解释的。
    • Node* mirrorCloneTree(Node* root);

      • 镜像克隆的含义是你需要在内存中新创建一颗二叉树(不修改原来的树),新创建的树与原来的树为镜像关系。例如:

               原来的树               镜像克隆的树                            
                 1                       1                      
              /      \                /      \               
             2        5              5        2                                         
          /     \                          /     \                             
         3       4                        4       3                            
        
      • 函数返回新创建树的根节点指针

    • void lavelOrderTraversal(Node* root);

      • 输出其层次遍历序列,以空格分割,行末应输出一个换行符\n
    • void destoryTree(Node* root);

      • 释放树所占的内存空间

    代码框架如下:

    允许你对框架进行适量修改,比如你想使用全局数组。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct Node {
        int data;
        Node *lchild, *rchild;
    }Node;
    
    Node* createNode(int data) {
        Node* temp = (Node*)malloc(sizeof(Node));
        temp->data = data;
        temp->lchild = temp->rchild = NULL;
        return temp;
    }
    
    Node* createTree(int preOrder[], int inOrder[], int N);
    int getTreeHeight(Node* root);
    int getTreeWidth(Node* root);
    int countLeafNode(Node* root);
    Node* mirrorCloneTree(Node* root);
    void lavelOrderTraversal(Node* root);
    void destoryTree(Node* root);
    
    int main() {
        int N;
        scanf("%d", &N);
    
        int* preOrder = (int*)malloc(N * sizeof(int));
        int* inOrder = (int*)malloc(N * sizeof(int));
        for (int i = 0; i < N; i++) {
            scanf("%d", &preOrder[i]);
        }
        for (int i = 0; i < N; i++) {
            scanf("%d", &inOrder[i]);
        }
    
        Node* root = createTree(preOrder, inOrder, N);
    
        printf("该树的高度是: %d\n", getTreeHeight(root));
        printf("该树的宽度是: %d\n", getTreeWidth(root));
        printf("该树的叶节点个数是: %d\n", countLeafNode(root));
    
        Node* newTreeRoot = mirrorCloneTree(root);
    
        printf("该树的镜像树的层次遍历序列为:\n");
        lavelOrderTraversal(newTreeRoot);
    
        destoryTree(root);
        destoryTree(newTreeRoot);
    
        return 0;
    }
    

    样例输入:

    7
    4 1 3 2 6 5 7
    1 2 3 4 5 6 7
    

    其对应的二叉树为:

                     4                             
                  /     \                         
                1         6                        
                  \     /    \                      
                   3   5      7                     
                  /                              
                 2                  
    

    样例输出:

    该树的高度是: 4
    该树的宽度是: 3
    该树的叶节点个数是: 3
    该树的镜像树的层次遍历序列为:
    4 6 1 7 5 3 2
    

    温馨提示:

    1. 函数的接口不允许修改,如果你觉得实现起来不方便,你可以自己重新写一个函数,然后直接调用你自己写的函数。比如createTree 函数你想使用递归来实现,但我给你的函数接口很难写成递归函数,那么你可以自己另外写一个递归函数,然后在createTree函数中直接调用你写的递归函数。

    参考代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct Node {
        int data;
        Node *lchild, *rchild;
    }Node;
    
    Node* createNode(int data) {
        Node* temp = (Node*)malloc(sizeof(Node));
        temp->data = data;
        temp->lchild = temp->rchild = NULL;
        return temp;
    }
    
    Node* createTree(int preOrder[], int inOrder[], int N);
    int getTreeHeight(Node* root);
    int getTreeWidth(Node* root);
    int countLeafNode(Node* root);
    Node* mirrorCloneTree(Node* root);
    void lavelOrderTraversal(Node* root);
    void destoryTree(Node* root);
    
    Node* _createTree(int preOrder[], int inOrder[], int preL, int preR, int inL, int inR);
    void traverseTreeForWidth(Node* root, int currentlayerNum, int layerNodeCount[]);
    
    int main() {
        int N;
        scanf("%d", &N);
    
        int* preOrder = (int*)malloc(N * sizeof(int));
        int* inOrder = (int*)malloc(N * sizeof(int));
        for (int i = 0; i < N; i++) {
            scanf("%d", &preOrder[i]);
        }
        for (int i = 0; i < N; i++) {
            scanf("%d", &inOrder[i]);
        }
    
        Node* root = createTree(preOrder, inOrder, N);
    
        printf("该树的高度是: %d\n", getTreeHeight(root));
        printf("该树的宽度是: %d\n", getTreeWidth(root));
        printf("该树的叶节点个数是: %d\n", countLeafNode(root));
    
        Node* newTreeRoot = mirrorCloneTree(root);
    
        printf("该树的镜像树的层次遍历序列为:\n");
        lavelOrderTraversal(newTreeRoot);
    
        destoryTree(root);
        destoryTree(newTreeRoot);
    
        return 0;
    }
    
    Node* createTree(int preOrder[], int inOrder[], int N) {
        return _createTree(preOrder, inOrder, 0, N - 1, 0, N - 1);
    }
    
    Node* _createTree(int preOrder[], int inOrder[], int preL, int preR, int inL, int inR) {
        if (preL > preR) return NULL;
        Node* root = createNode(preOrder[preL]);
        int k = inL;
        while (inOrder[k] != preOrder[preL]) k++;
        int leftTreeNum = k - inL;
        root->lchild = _createTree(preOrder, inOrder, preL + 1, preL + leftTreeNum, inL, k - 1);
        root->rchild = _createTree(preOrder, inOrder, preL + leftTreeNum + 1, preR, k + 1, inR);
        return root;
    }
    
    int getTreeHeight(Node* root) {
        if (root == NULL) return 0;
        int left_high = getTreeHeight(root->lchild);
        int right_high = getTreeHeight(root->rchild);
        return __max(left_high, right_high) + 1;
    }
    
    int getTreeWidth(Node* root) {
        int treeHeight = getTreeHeight(root);
        int* layerNodeCount = (int*)malloc(treeHeight * sizeof(int));
        memset(layerNodeCount, 0, treeHeight * sizeof(int));
    
        traverseTreeForWidth(root, 0, layerNodeCount);
    
        int maxWidth = -1;
        for (int i = 0; i < treeHeight; i++) {
            if (layerNodeCount[i] > maxWidth) maxWidth = layerNodeCount[i];
        }
        return maxWidth;
    }
    
    void traverseTreeForWidth(Node* root, int currentlayerNum, int layerNodeCount[]) {
        if (root == NULL) return;
        layerNodeCount[currentlayerNum]++;
        traverseTreeForWidth(root->lchild, currentlayerNum + 1, layerNodeCount);
        traverseTreeForWidth(root->rchild, currentlayerNum + 1, layerNodeCount);
    }
    
    int countLeafNode(Node* root) {
        if (root == NULL) return 0;
        if (root->lchild == NULL && root->rchild == NULL) return 1;
        int left = countLeafNode(root->lchild);
        int right = countLeafNode(root->rchild);
        return left + right;
    }
    
    Node* mirrorCloneTree(Node* root) {
        if (root == NULL) return NULL;
        Node* temp = createNode(root->data);
        temp->lchild = mirrorCloneTree(root->rchild);
        temp->rchild = mirrorCloneTree(root->lchild);
        return temp;
    }
    
    void lavelOrderTraversal(Node* root) {
        if (root == NULL) return;
        Node* Queue[1000];
        int front = 0, rear = 0;
        Queue[rear++] = root;   //根节点入队
        while (rear != front) { //只要队列不为空
            Node* t = Queue[front++];   //出队
            printf("%d ", t->data);
            if (t->lchild != NULL) Queue[rear++] = t->lchild;   //入队
            if (t->rchild != NULL) Queue[rear++] = t->rchild;
        }
        printf("\n");
    }
    
    void destoryTree(Node* root) {
        if (root == NULL) return;
        destoryTree(root->lchild);
        destoryTree(root->rchild);
        free(root);
    }
    
    

    对于求树的宽度,还可以借助层次遍历

    该代码用了C++ STL容器,可参考:https://www.cnblogs.com/skyfsm/p/6934246.htmlhttps://www.cnblogs.com/mfryf/archive/2012/08/09/2629992.html

    //该方法不需要对Node结构体修改,也不需要额外的数组记录每一层的节点数
    int getTreeWidth_2(Node* root) {
        if (root == NULL) return 0;
        queue<Node*> Q;
        Q.push(root);
        int currentLayerWidth = 1;  //根节点入队,此时当前这一层(第0层)的宽度是1
        int treeWidth;  //记录整棵树的宽度
        while (Q.empty() == false) {    //只要队列不为空
            treeWidth = max(currentLayerWidth, treeWidth);  //更新这棵树的最大宽度
            while (currentLayerWidth--) {   //把当前这一层的节点全部弹出
                Node* p = Q.front(); Q.pop();   //弹出队首元素
                if (p->lchild != NULL) {
                    Q.push(p->lchild);
                }
                if (p->rchild != NULL) {
                    Q.push(p->rchild);
                }
            }
            //现在队列中存放的节点全部都是下一层的节点
            currentLayerWidth = Q.size();   //进入下一层时更新该变量
        }
        return treeWidth;
    }
    

    第二题:后序遍历的第k个节点

    题目

    (这道题是清华大学的考研真题)

    假设二叉树的节点定义如下:

    其中节点的size成员表示:当前节点以及其孩子节点的总数,也可以理解为以该节点为根的子树当中,所有的节点个数。

    struct BinNode{ 
        int size;   //当前节点以及其孩子节点的总数
        BinNode *lchild,*rchild; 
    }; 
    

    编写一个算法:返回后序遍历的第 K 个(K从1开始计数)节点的<u>指针</u>(该节点记为x),要求时间复杂度不超过该节点的深度,即Ο(depth(x))

    BinNode *rank(BinNode* t,int k){ 
        //有效代码行数不超过12行
        //不要尝试模拟后序遍历,时间复杂度会超时(按照清华的评分标准这题直接得0分) 
    } 
    

    这道题的代码的框架如下:

    <u>只需要实现</u>rankInPostordergenerateEachNodeSize这两个函数。

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct Node {
        int data;
        struct Node* lchild, * rchild;
        int size;
    }Node;
    
    Node* createNode(int data) {
        Node* temp = (Node*)malloc(sizeof(Node));
        temp->data = data;
        temp->lchild = temp->rchild = NULL;
        return temp;
    }
    
    void setNodeChild(Node* root, Node* lchild, Node* rchild) {
        root->lchild = lchild;
        root->rchild = rchild;
    }
    
    //返回后序遍历的第K个(K从1开始计数)节点的指针
    Node* rankInPostorder(Node* t, int k) {
    
    }
    
    //计算每个节点的size的值
    //需要的话你可以把该函数的返回值改为int类型
    void generateEachNodeSize(Node* root) {
    
    }
    
    int main() {
        Node* root = createNode(1);
        Node* node2 = createNode(2);
        Node* node3 = createNode(3);
        Node* node4 = createNode(4);
        Node* node5 = createNode(5);
        Node* node6 = createNode(6);
        Node* node7 = createNode(7);
        Node* node8 = createNode(8);
    
        setNodeChild(root, node2, node3);
        setNodeChild(node2, node4, node5);
        setNodeChild(node3, NULL, node7);
        setNodeChild(node5, node6, NULL);
        setNodeChild(node4, NULL, node8);
    
        generateEachNodeSize(root);
    
        for (int i = 1; i <= 8; i++) {
            Node* p = rankInPostorder(root, i);
            printf("%d ", p->data);
        }
        printf("\n");
        return 0;
    }
    

    如果你写的算法正确,程序应当输出:

    8 4 6 5 2 7 3 1
    

    该二叉树的结构为:

                  1                           
               /      \                     
             2          3                   
          /     \         \               
         4       5          7             
          \     /                                
           8   6                                                                           
    

    参考代码

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct Node {
        int data;
        struct Node* lchild, * rchild;
        int size;
    }Node;
    
    Node* createNode(int data) {
        Node* temp = (Node*)malloc(sizeof(Node));
        temp->data = data;
        temp->lchild = temp->rchild = NULL;
        return temp;
    }
    
    void setNodeChild(Node* root, Node* lchild, Node* rchild) {
        root->lchild = lchild;
        root->rchild = rchild;
    }
    
    //返回后序遍历的第K个(K从1开始计数)节点的指针
    Node* rankInPostorder(Node* root, int k) {
        //检查参数是否合法
        if (root == NULL || root->size < k) return NULL;
    
        if (root->size == k) return root;
    
        if (root->lchild == NULL) {
            //如果没有左子树,则直接进入右子树搜索
            return rankInPostorder(root->rchild, k);
        }
    
        int leftSize = root->lchild->size;
        if (k <= leftSize) {
            //左子树不为空,且根据左子树的size判断出目标在左子树,则进入左子树搜索
            return rankInPostorder(root->lchild, k);
        }
        else {
            //否则进入右子树,且需要更新k
            return rankInPostorder(root->rchild, k - leftSize);
        }
    }
    
    //计算每个节点的size的值
    //需要的话你可以把该函数的返回值改为int类型
    int generateEachNodeSize(Node* root) {
        if (root == NULL) return 0;
        int l = generateEachNodeSize(root->lchild);
        int r = generateEachNodeSize(root->rchild);
        root->size = l + r + 1;
        return root->size;
    }
    
    int main() {
        Node* root = createNode(1);
        Node* node2 = createNode(2);
        Node* node3 = createNode(3);
        Node* node4 = createNode(4);
        Node* node5 = createNode(5);
        Node* node6 = createNode(6);
        Node* node7 = createNode(7);
        Node* node8 = createNode(8);
    
        setNodeChild(root, node2, node3);
        setNodeChild(node2, node4, node5);
        setNodeChild(node3, NULL, node7);
        setNodeChild(node5, node6, NULL);
        setNodeChild(node4, NULL, node8);
    
        generateEachNodeSize(root);
    
        for (int i = 1; i <= 8; i++) {
            Node* p = rankInPostorder(root, i);
            printf("%d ", p->data);
        }
        printf("\n");
        return 0;
    }
    

    参考资料

    (请先将该代码弄懂再做作业)

    C语言实现二叉树的遍历算法,参考代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    #define MAXN 1000
    
    typedef struct Node {
        int data;
        struct Node* lchild, * rchild;
    }Node;
    
    Node* createNode(int data) {
        Node* temp = (Node*)malloc(sizeof(Node));
        temp->data = data;
        temp->lchild = temp->rchild = NULL;
        return temp;
    }
    
    void setNodeChild(Node* root, Node* lchild, Node* rchild) {
        root->lchild = lchild;
        root->rchild = rchild;
    }
    
    void preorderTrav(Node* root) { //先序遍历
        if (root == NULL) return;
        printf("%d ", root->data);  //最先访问根节点
        preorderTrav(root->lchild);
        preorderTrav(root->rchild);
    }
    
    void inorderTrav(Node * root) { //中序遍历
        if (root == NULL) return;
        inorderTrav(root->lchild);
        printf("%d ", root->data);  //中间的时候访问根节点
        inorderTrav(root->rchild);
    }
    
    void postorderTrav(Node * root) {   //后序遍历
        if (root == NULL) return;
        postorderTrav(root->lchild);
        postorderTrav(root->rchild);
        printf("%d ", root->data);  //最后访问根节点
    }
    
    void levelTrav(Node * root) {   //层次遍历
        if (root == NULL) return;
        Node * Queue[MAXN];
        int front = 0, rear = 0;
        Queue[rear++] = root;   //根节点入队
        while (rear != front) { //只要队列不为空
            Node* t = Queue[front++];   //出队
            printf("%d ", t->data);
            if (t->lchild != NULL) Queue[rear++] = t->lchild;   //入队
            if (t->rchild != NULL) Queue[rear++] = t->rchild;
        }
        printf("\n");
    }
    
    int getTreeHeight(Node * root) {
        if (root == NULL) return 0;
        int left_high = getTreeHeight(root->lchild);
        int right_high = getTreeHeight(root->rchild);
        return max(left_high, right_high) + 1;
    }
    
    int main() {
        Node* root = createNode(1);
        Node* node2 = createNode(2);
        Node* node3 = createNode(3);
        Node* node4 = createNode(4);
        Node* node5 = createNode(5);
        Node* node6 = createNode(6);
        Node* node7 = createNode(7);
        Node* node8 = createNode(8);
    
        setNodeChild(root, node2, node3);
        setNodeChild(node2, node4, node5);
        setNodeChild(node3, NULL, node7);
        setNodeChild(node5, node6, NULL);
        setNodeChild(node4, NULL, node8);
    
        preorderTrav(root);
        printf("\n");
    
        inorderTrav(root);
        printf("\n");
    
        postorderTrav(root);
        printf("\n");
    
        levelTrav(root);
    
        printf("Tree Height: %d\n", getTreeHeight(root));
    
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:数据结构第三次作业

          本文链接:https://www.haomeiwen.com/subject/wkmgzqtx.html