(四十三)第 6 章 树和二叉树(树的二叉链表(孩子-兄弟)存储)

1. 背景说明

2. 示例代码

1) errorRecord.h

// 记录错误宏定义头文件
 
#ifndef ERROR_RECORD_H
#define ERROR_RECORD_H
 
#include <stdio.h>
#include <string.h>
#include <stdint.h>
 
// 从文件路径中提取文件名
#define FILE_NAME(X) strrchr(X, '\\') ? strrchr(X, '\\') + 1 : X
 
// 定义用于启用调试模式的 DEBUG 宏
#define DEBUG
 
// 打印错误消息
#ifdef DEBUG
#define ERR_RECORD(ERR_CODE, ...) do { \
    printf(ANSI_COLOR_BRIGHT_CYAN \
        "\n\nFile: %-25s Func: %-20s Line: %-10d ErrorCode: %-8d ErrorInfo: ", \
        FILE_NAME(__FILE__), __func__, __LINE__, (ERR_CODE)); \
    printf(""__VA_ARGS__); \
    printf("\n" ANSI_COLOR_RESET); \
    PrintErrorCodeInfo(ERR_CODE); \
} while (0)
#else
#define ERR_RECORD(ERR_CODE, ...)
#endi
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 一棵二叉树的顺序存储情况如下: 中,度为2的结点数为( )。 A.1 B.2 C.3 D.4 2. 一棵“完全二叉树”结点数为25,高度为( )。 A.4 B.5 C.6 D.不确定 3.下列说法中,( )是正确的。 A. 二叉树就是度为2的 B. 二叉树中不存在度大于2的结点 C. 二叉树是有序 D. 二叉树中每个结点的度均为2 4.一棵二叉树的前序遍历序列为ABCDEFG,它的中序遍历序列可能是( )。 A. CABDEFG B. BCDAEFG C. DACEFBG D. ADBCFEG 5.线索二叉树中的线索指的是( )。 A.左孩子 B.遍历 C.指针 D.标志 6. 建立线索二叉树的目的是( )。 A. 方便查找某结点的前驱或后继 B. 方便二叉树的插入与删除 C. 方便查找某结点的双亲 D. 使二叉树的遍历结果唯一 7. 有abc三个结点的右单枝二叉树的顺序存储结构应该用( )示意。 A. a b c B. a b ^ c C. a b ^ ^ c D. a ^ b ^ ^ ^ c 8. 一颗有2046个结点的完全二叉树的第10层上共有( )个结点。 A. 511 B. 512 C. 1023 D. 1024 9. 一棵完全二叉树一定是一棵( )。 A. 平衡二叉树 B. 二叉排序 C. 堆 D. 哈夫曼 10.某二叉树的中序遍历序列和后序遍历序列正好相反,则该二叉树一定是( )的二叉树。 A.空或只有一个结点 B.高度等于其结点数 C.任一结点无左孩子 D.任一结点无右孩子 11.一棵二叉树的顺序存储情况如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 A B C D E 0 F 0 0 G H 0 0 0 X 结点D的左孩子结点为( )。 A.E B.C C.F D.没有 12.一棵“完全二叉树”结点数为25,高度为( )。 A.4 B.5 C.6 D.不确定 二、填空题(每空3分,共18分)。 1. 的路径长度:是从根到每个结点的路径长度之和。对结点数相同的来说,路径长度最短的是 完全 二叉树。 2. 在有n个叶子结点的哈夫曼中,总结点数是 2n-1 。 3. 在有n个结点的二叉链表中,值为非空的链域的个数为 n-1 。 4. 某二叉树的中序遍历序列和后序遍历序列正好相反,则该二叉树一定是 任一结点无左孩子二叉树。 5. 深度为 k 的二叉树最多有 个结点,最少有 k 个结点。 三、综合题(共58分)。 1. 假定字符集{a,b,c,d,e,f }中的字符在电码中出现的次数如下: 字符 a b c d e f 频度 9 12 20 23 15 5 构造一棵哈夫曼(6分),给出每个字符的哈夫曼编码(4分),并计算哈夫曼的加权路径长度WPL(2分)。 (符合WPL最小的均为哈夫曼,答案不唯一) 哈夫曼编码: 2. 假设用于通信的电文由字符集{a,b,c,d,e,f,g}中的字符构成,它们在电文中出现的频率分别为{0.31,0.16,0.10,0.08,0.11,0.20,0.04}。要求: (1)为这7个字符设计哈夫曼(6分)。 (2)据此哈夫曼设计哈夫曼编码(4分)。 (3)假设电文的长度为100字符,使用哈夫曼编码比使用3位二进制数等长编码使电文总长压缩多少?(4分) (1) 为这7个字符设计哈夫曼为(符合WPL最小的均为哈夫曼,答案不唯一): (2) 哈夫曼编码为: a:01;b:001;c:100;d:0001;e:101;f:11;g:0000 (3) 假设电文的长度为100字符,使用哈夫曼编码比使用3位二进制数等长编码使电文总长压缩多少? 采用等长码,100个字符需要300位二进制数,采用哈夫曼编码发送这100个字符需要261二进制位,压缩了300-261=39个字符。压缩比为39/300=13%。 3. 二叉数T的(双亲到孩子的)边集为: { <A,B>, <A,C>, <D,A>, <D,E>, <E,F>, <F,G> } 请回答下列问题: (1)T的根结点(2分): (2)T的叶结点(2分): (3)T的深度(2分): (4)如果上述列出边集中,某个结点只有一个孩子时,均为其左孩子;某个结点有两个孩子时,则先列出了连接左孩子的边后列出了连接右孩子的边。画出该二叉树其及前序线索(6分)。 (1)T的根结点 (2)T的叶结点 : (3)T的深度 : (4)该二叉树其及前序线索为: 4.现有以下按前序和中序遍历二叉树的结果: 前序:ABCEDFGHI 中序:CEBGFHDAI 画出该二叉树的逻辑结构图(5分),并在图中加入中序线索(5分)。 5.有电文:ABCDBCDCBDDBACBCCFCDBBBEBB。 用Huffman构造电文中每一字符的最优通讯编码。画出构造的哈夫曼,并给出每个字符的哈夫曼编码方案。(符合WPL最小的均为哈夫曼,答案不唯一) (1)构造哈夫曼(6分): (2)哈夫曼编码方案(4分):
### 回答1: 如果使用二叉链表作为储存结构,那么每个结点应该包含三个域:左孩子指针、右孩子指针和双亲指针。因此,如果要获取某个结点x的双亲,只需要访问x的双亲指针即可。 假设我们已经定义了二叉树结点的结构体如下: ``` struct BinaryTreeNode { int value; // 结点的值 BinaryTreeNode* left; // 左孩子指针 BinaryTreeNode* right; // 右孩子指针 BinaryTreeNode* parent; // 双亲指针 }; ``` 那么获取结点x的双亲代码如下: ``` BinaryTreeNode* getParent(BinaryTreeNode* x) { if (x == nullptr || x->parent == nullptr) { // 如果x为空或x没有双亲,返回空指针 return nullptr; } else { // 返回x的双亲指针 return x->parent; } } ``` 调用该函数,传入结点x,即可获取x的双亲。例如,假设我们已经构建好了一棵二叉树,其中结点A是根节点,结点B和结点C是它的左右孩子,结点D是结点B的左孩子,结点E是结点C的右孩子。如果我们要获取结点D的双亲,可以这样调用函数: ``` BinaryTreeNode* root = ...; // 根节点A BinaryTreeNode* d = ...; // 结点D BinaryTreeNode* parent = getParent(d); if (parent != nullptr) { cout << "结点D的双亲是:" << parent->value << endl; } else { cout << "结点D没有双亲或者输入的结点为空" << endl; } ``` ### 回答2: 二叉链表是一种常用的二叉树存储结构。在二叉链表中,每个结点除了包含数据元素外,还包含了指向其左孩子和右孩子的指针。而结点的双亲可以通过在结点结构中添加一个指向父结点的指针来表示。 具体实现时,可以在结点结构中添加一个指针变量parent,用于指向结点的父结点。当需要访问结点x的双亲时,可以通过访问x的parent指针来获取。 例如,下面是一个二叉链表结点的定义: ```c typedef struct Node { int data; // 结点中存储的数据元素 struct Node* left; // 指向左孩子的指针 struct Node* right; // 指向右孩子的指针 struct Node* parent; // 指向父结点的指针 } Node; ``` 假设有一个指向二叉树根结点的指针root,要访问结点x的双亲,可以使用以下代码: ```c Node* getParent(Node* root, Node* x) { if (root == NULL || root == x) { return NULL; // 根结点或目标结点为空时,返回NULL } if (root->left == x || root->right == x) { return root; // 如果目标结点是当前结点的左孩子或右孩子,则当前结点就是目标结点的双亲 } Node* parent = getParent(root->left, x); if (parent != NULL) { return parent; // 如果在左子中找到双亲,直接返回 } return getParent(root->right, x); // 否则在右子中找双亲 } ``` 以上代码使用递归方式实现了获取结点x的双亲的功能。当根结点为空或根结点就是目标结点x时,返回NULL。在每个结点中,分别判断左孩子和右孩子是否为目标结点x,如果是,则返回当前结点;如果不是,则递归地在左子和右子中继续寻找。这样,就可以通过二叉链表来实现获取二叉树中任意结点双亲的功能。 ### 回答3: 在二叉链表中,每个结点都有一个指针指向其双亲结点。假设我们有一个二叉树二叉链表储存结构如下: ```c typedef struct BiTNode { ElemType data; // 结点数据 struct BiTNode *lchild, *rchild; // 左子结点和右子结点指针 struct BiTNode *parent; // 双亲结点指针 } BiTNode, *BiTree; ``` 为了找到结点x的双亲,我们可以进行如下操作: 1. 判断二叉树是否为空,如果为空则返回空。 2. 从根结点开始,从上至下按层遍历二叉树。 3. 在遍历的过程中,判断当前结点的左子结点和右子结点是否为x,如果是则返回该结点作为x的双亲。 4. 如果当前结点的左子结点和右子结点不是x,则将当前结点入队,并依次遍历其左子结点和右子结点。 5. 重复步骤3和4,直到找到结点x的双亲或者遍历完整个二叉树。 要实现上述操作,我们可以使用队列作为辅助数据结构,即在操作过程中将结点依次入队,然后依次出队。 以下是一种可能的C语言实现: ```c BiTNode* FindParent(BiTree root, BiTNode* x) { if (root == NULL || x == NULL) { return NULL; } queue<BiTNode*> q; // 辅助队列 q.push(root); // 根结点入队 while (!q.empty()) { BiTNode *curNode = q.front(); // 取出队列头结点 q.pop(); // 出队 // 判断左子结点或右子结点是否为x,是则返回当前结点 if (curNode->lchild == x || curNode->rchild == x) { return curNode; } // 将左子结点和右子结点入队 if (curNode->lchild) { q.push(curNode->lchild); } if (curNode->rchild) { q.push(curNode->rchild); } } return NULL; // 遍历完整个二叉树都没找到x的双亲,则返回NULL } ``` 通过以上实现,我们可以找到任意一个二叉树结点x的双亲结点。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值