您的位置:首页 > 职场人生

关于完全二叉树的一道面试题

2020-03-31 19:08 591 查看

题目描述

存在一棵完全二叉树,从键盘输入一组数据,并将数据从二叉树的根结点顺序存入每个结点 ,输出从根结点到叶结点最大的路径长度。

输入描述:

输入第一行为完全二叉树的结点数 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语言的灵魂所在。

  • 点赞
  • 收藏
  • 分享
  • 文章举报
bwqiang 发布了49 篇原创文章 · 获赞 3 · 访问量 742 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: