关于完全二叉树的一道面试题
题目描述
存在一棵完全二叉树,从键盘输入一组数据,并将数据从二叉树的根结点顺序存入每个结点 ,输出从根结点到叶结点最大的路径长度。
输入描述:
输入第一行为完全二叉树的结点数 n。
输入第二行为对应的的所有整数,用空格隔开。
输出描述:
输出最大的路径长度
示例:
输入:
7
5 4 3 10 5 9 2
输出:
19
解题思路
1、该题目实际上是有一定难度的,需要边建立二叉树一边赋值,而且数值并不是已经存好的数值,需要在程序运行时手动输入,如果用递归的方法建树,结点赋值就会出现一个很大的问题,所以,本题目不考虑递归方法。
2、可以动态创立一组长度为nnn的二叉树类型数组,可以一边创建结点,一边为从键盘上为结点赋值,再通过完全二叉树的性质,更改父结点左右指针的指向即可创建二叉树,这样就为动态的为结点插入数据提供了便利。
3、本题目要求返回二叉树的最大带权路径长度(区别于哈夫曼树中的带权路径长度(WPL)的定义,该问题不乘路径长度值),即二叉树中结点数值之和最大的路径,思路可以是一边在父结点指针指向左右孩子结点,一边用一个数组记录父结点与其孩子结点的权值累加,这样在创建二叉树结束后,数组中就可以记录每一个叶子结点到父结点的路径之和,返回最大值即可。
4、搞懂本题目的同学可以清楚地知道,只要建立一个int类型的数组,然后通过完全二叉树的性质,用另一个数组记录叶子结点到父结点的权值之和即可,完全没有必要建立二叉树结点这一系列工作。对,你的想法是正确的,我之所以这么写,是为了让你了解二叉树的相关知识而已。
相关代码
#define _CRT_SECURE_NO_WARNINGS // 也可以将该宏定义放入到VS项目的属性中 #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct BITNODE { int data; struct BiTNode *left, *right; }BiTNode, *BiTree; BiTree CreateBiTree(int n,int* arr) // 创建结点数为n的完全二叉树 { BiTree biTreeArr = (BiTree)malloc(sizeof(BiTNode)* n);// 创建个数为n的二叉树结点 if (biTreeArr == NULL) { printf("创建二叉树类型的数组失败!\n"); return NULL; } printf("请依次输入%d个整数:\n", n); int num = 0; // 用于存放键盘中输入的数据 for (int i = 0; i < n; i++) // 将n个整数存放在了BiTree类型的数组中,即每个结点已经存放好数据 { scanf("%d", &num); arr[i] = num; // 将数值赋给arr数组中 (*(biTreeArr + i)).data = num; // 注意(*(biTreeArr + i))为BiTNode类型 //biTreeArr[i].data = num; // 该语法等同于上一个语法 数组类型 就是指针类型的语法糖 } for (int i = 0; i <= n / 2 - 1; i++)//循环建立完全二叉树 { if (2 * i + 1 <= n - 1) // 这里还是写出判断语句比较好 { arr[2 * i + 1] += arr[i]; // 依次累加 最终可得到根结点到该结点的权值路径之和 (*(biTreeArr + i)).left = biTreeArr + 2 * i + 1;// 当父结点指针为i,左孩子是2i 右孩子是2i+1 //biTreeArr[i].left = &(biTreeArr[2 * i + 1]); // 也是与上句功能相同 该句是上句的语法糖 } if (2 * i + 2 <= n - 1) { arr[2 * i + 2] += arr[i];// 依次累加 最终可得到根结点到该结点的权值路径之和 (*(biTreeArr + i)).right = biTreeArr + 2 * i + 2; //biTreeArr[i].right = &(biTreeArr[2 * i + 2]);// 也是与上句功能相同 该句是上句的语法糖 } } return biTreeArr; // 返回二叉树头结点 } int MaxLength(int* arr,int n) // 返回数组中的最大值 { int maxLength = 0; for (int i = 0; i < n; i++) { if (maxLength < arr[i]) //将数组中的最大值 赋值给maxLength变量 { maxLength = arr[i]; } } return maxLength; // 返回数组中的最大值 即为二叉树最大路径长度 } int main() { int n = 0; int maxLength = 0; BiTree biTree = NULL; printf("请输入完全二叉树的结点数:\n"); scanf("%d", &n); if (n <= 0) { printf("输入的结点数目非法!\n"); return -1; } int* arr = (int *)malloc(sizeof(int)* n); // 可以用malloc开辟数组长度 但a 是错误的语法 biTree = CreateBiTree(n, arr); //创建结点为n的完全二叉树 用arr数组记录根结点到任意结点的路径长度 maxLength = MaxLength(arr, n); // 返回路径长度的最大值 printf("该完全二叉树的最大路径长度是:%d\n", maxLength); system("pause"); return 0; }
用递归的方法如下,是不提倡的
// 这种方法不利于本题目的求解 void CreateBiTree(BiTree biTree,int n) // 创建结点数为n的完全二叉树 { static int i = 0; // 定义静态变量 寓意建立n个结点 biTree = (BiTree)malloc(sizeof(BiTNode)); if (biTree == NULL) { return NULL; } i++; if (i == n) { return; } CreateBiTree(biTree->left, n); CreateBiTree(biTree->right, n); }
有关问题
1、用二级指针开辟结点数组
BiTree* biTreeArr = (BiTree*)malloc(sizeof(BiTree)* n);
用这种方法建立的是n个指向二叉树结点类型的指针变量,如果用每一个指针指向其余结点是完全没问题的,但对于本题目,不合适,这样做没有建立结点,不能执行赋值等其他操作。
2、如何一边插入数值一边建立结点是本题的难点,所以我认为本题目不适合用递归方法来解答。
3、曾经看过一本名叫《征服C指针》一书,其中作者将数组类型叫做指针类型的语法糖,具体含义就是用指针定义数组,寻找数组中的值对于C语言来说速度更快,但用[ ]来寻找数组中的值对于人类来说更好理解,所以数组类型可以是指针类型的升华,名为语法糖。
int a[10]; for(int i = 0; i < 10; i++) scanf("%d ", &a[i]); // 需要取地址 for(int i = 0;i < 10; i++) printf("%d ", a[i]); int* a = (int*)malloc(sizeof(int) * 10); // 与 a[10]; 等同 for(int i = 0;i < 10;i++) scanf("%d", (a + i)); // 是指针类型 for(int i = 0;i < 10;i++) printf("%d ", *(a + i)); // 与 a[i] 等同
上面两者的实现效果是一样的。
4、本题目原本是上机考试,使用的是OJ系统,所以答案不会这么复杂,我这样写的目的是更好的掌握每一个知识点。通过main函数调用api函数,模块化设计,也是C语言的灵魂所在。
- 点赞
- 收藏
- 分享
- 文章举报
- 关于索引的一道经典面试题
- 关于 parseInt 的一道有意思的面试题
- 一道关于实例化顺序的C#面试题
- 关于global和$GLOBALS[]的一道经典面试题
- 一道关于杀猪的面试题
- 一道关于php变量引用的面试题
- java-关于int和Integer的一道面试题
- 记一道关于链表的面试题
- 记一道关于链表逆序的面试题
- 一道SQL语句面试题,关于group by的
- 一道关于静态构造函数与抽象类构造函数的面试题引发的思考
- 一道关于计算机如何做加法的面试题
- 关于索引的一道经典面试题
- 一道关于截取字符串的java面试题
- 2016-08-25-java-关于都有谁继承了collection接口的一道面试题
- 关于华为一道面试题 ( ++a )和( a++ )
- 关于运算符问题的一道面试题
- 关于二叉树的一道面试题
- 关于global和$GLOBALS[]的一道经典面试题
- 关于一道老微软面试题的新解