说在开头
- 下面给出的是函数,具体的可执行程序,会在这一系列的所有博客完结后上传到CSDN。
- 函数也是可执行的程序,对于这一章的建树的程序没有贴上,是因为和前面的博客【二叉树的遍历】中的建树程序是一样的,需要的话,大家可以自行去参考。
头文件定义
#include <iostream>
#include <algorithm>
#include <string>
数据结构定义
typedef char ElemType;
typedef struct bitnode{
ElemType data;
struct bitnode *right, *left;
}BitNode, *PBitNode;
第六题
题目描述
判断给定的二叉树是否是二叉排序树。
题目分析
二叉排序树的中序遍历序列是有序序列,所以按照中序遍历一遍,符合大小规则的就是二叉排序树。
代码
// 判断这棵二叉树是不是二叉排序树 辅助程序
void midOrder(PBitNode tree, PBitNode &pre, bool &res)
{
if (tree)
{
midOrder(tree->left, pre, res);
if (pre){
if (pre->data > tree->data) res = false;
}
pre = tree;
midOrder(tree->right, pre, res);
}
}
// 判断这棵二叉树是不是二叉排序树 主程序
bool judgeIsBST(PBitNode tree)
{
PBitNode pre = NULL;
bool res = true;
midOrder(tree, pre, res);
return res;
}
第七题
题目描述
求出指定结点在给定二叉排序树中的层次。
题目描述
二叉排序树中的左孩子中的所有节点都小于当前结点,右孩子结点都大于当前节点。
所以我们找目标值时,可以确定目标值出现在左孩子还是右孩子。
所以我们判断了几次就相当于像下走了几层。判断的次数即层数。
代码
// 求指定结点在二叉排序树中的层次
int countLevel(PBitNode tree, ElemType e)
{
if (!tree) return 0;
int res = 1;
while (tree)
{
if (tree->data == e) return res;
res++;
if (tree->data < e) tree = tree->right;
else tree = tree->left;
}
return -1; // 未找到
}
第八题
题目描述
利用二叉树遍历的思想编写一个判断二叉树是否是平衡二叉树的算法。
题目分析
只需要在计算二叉树的高度的时候,每次在结点判断当前结点是否满足平衡二叉树的要求即可。
什么是平衡二叉树?
对
任
意
一
节
点
,
a
b
s
(
左
子
树
的
高
度
−
右
子
树
的
高
度
)
<
2
对任意一节点,abs(左子树的高度-右子树的高度) < 2
对任意一节点,abs(左子树的高度−右子树的高度)<2
代码
// 判断一个二叉树是否为平衡二叉树 辅助程序
int judge(PBitNode tree, bool &res)
{
if (!tree) return 0;
int hl = judge(tree->left, res) + 1;
int hr = judge(tree->right, res) + 1;
if (abs(hl - hr) >= 2) res = false;
return max(hl, hr);
}
// 判断二叉树是否为平衡二叉树 主程序
bool isBBT(PBitNode tree)
{
bool res = true;
judge(tree, res);
return res;
}
第九题
题目描述
求出给定二叉排序树中最大和最小的关键字。
题目描述
左孩子小于当前结点,右孩子大于当前节点。
所以按照递归的思想,左孩子走到头就是最小的键值。右孩子走到头就是最大的键值。
代码
// 得到二叉排序树中的最小关键字
ElemType minKey(PBitNode tree)
{
if (!tree) return ElemType(-1);
while (tree->left) tree = tree->left;
return tree->data;
}
// 得到二叉排序树中的最大关键字
ElemType maxKey(PBitNode tree)
{
if (!tree) return ElemType(-1);
while (tree->right) tree = tree->right;
return tree->data;
}
第十题
题目描述
从大到小输出二叉排序树中所有值不小于k的关键字。
题目描述
中序遍历一遍就结束了。
- 正着中序遍历的话,再利用栈,就可以实现从大到小输出了。
- 也可以直接到着中序遍历。和正着中序遍历相比,只需要把遍历左右子树的顺序交换一下即可。
代码
// 从大大小输出二叉排序树中的所有值不小于k的关键字
void printMoreThanKInBST(PBitNode tree, ElemType k)
{
if (tree)
{
printMoreThanKInBST(tree->right, k);
if (tree->data >= k) cout << tree->data << " ";
printMoreThanKInBST(tree->left, k);
}
return;
}
第十一题
题目描述
给定一个权集w,构造出权集上的哈夫曼树,并求出这棵树的WPL。
代码思路
不了解优先队列(priority_queue)的同学看代码之前,先看优先队列的用法。
懒得看的同学,听我一句话介绍一下优先队列。优先队列里面的元素,会按照你定义的优先级顺序自动排列好。其插入和查找的复杂度都是Log(n)级别的。
Huffman树构造方法:
- 利用优先队列每次从权集集合中取出两个权值最小结点。
- 给两个最小权值的结点分配一个父节点,父节点的权值是两个子结点的权值之和,再将父节点加入队列。
- 循环操作至优先队列中只剩下一个节点,这个节点就是Huffman树的根节点。
关于求WPL的算法很简单了,先序遍历一遍,遍历的过程中记录一下结点的深度,到叶节点时统计WPL即可。
代码
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
using namespace std;
typedef int ElemType;
typedef struct bitnode{
ElemType weight;
struct bitnode *right, *left;
friend bool operator<(struct bitnode n1, struct bitnode n2)
{
return n1.weight < n2.weight;
}
}BitNode, *PBitNode;
/* 优先队列存放 PBitNode 时优先级的比较方法 */
class Compare_Node_Pointer
{
public:
/* PBitNode::weight 小的优先 */
bool operator () (PBitNode &a, PBitNode &b) const
{
return a->weight > b->weight;
}
};
// 给定权集w,构造一棵哈夫曼树
PBitNode creatHuffmanTree(vector<int> w)
{
if (!w.size()) return NULL;
priority_queue<PBitNode, vector<PBitNode>, Compare_Node_Pointer> que;
for (int i = 0; i < w.size(); i++)
{
PBitNode p = new BitNode();
p->weight = w[i];
p->left = p->right = NULL;
que.push(p);
}
while (que.size() > 1)
{
PBitNode node1 = que.top(); que.pop();
PBitNode node2 = que.top(); que.pop();
PBitNode node = new BitNode();
node->left = node1;
node->right = node2;
node->weight = node1->weight + node2->weight;
que.push(node);
}
return que.top();
}
// 求哈夫曼树的WPL 辅助程序
int dfsTree(PBitNode tree, int h)
{
static int wpl = 0;
if (tree)
{
if (!tree->left && !tree->right) wpl += h * tree->weight;
dfsTree(tree->left, h + 1);
dfsTree(tree->right, h + 1);
}
return wpl;
}
// 求哈夫曼树的WPL 主程序
int huffmanTreeWPL(PBitNode tree)
{
return dfsTree(tree, 0);
}
int main()
{
vector<int> w{ 5, 7, 2, 3, 6, 8, 9 };
PBitNode hft = creatHuffmanTree(w);
cout << "这棵哈夫曼树的WPL为:" << endl;
cout << huffmanTreeWPL(hft) << endl;
return 0;
}
第十二题
题目简述
再原有的二叉树结点中增加Count值,表示子树结点的个数。
设计递归算法,求出二叉排序树的第k个结点。
题目思路
个人认为,11题比12题重要,所以大家还是掌握11题的代码,12题重思路。
对于12题来说,知道二分的同学,应该很轻松做出来这道题目。
题目中中很明确的指出,结构体中加上count值,表示子结点的个数,所以我们可以利用count值,每次排除掉左子树或者右子树,如果这棵树是平衡二叉树,那么查找的时间复杂度是lg(n)级别的,但是题目中并没有指明这棵树是平衡二叉树,还要求我们必须达到Lg(n)级别,这题目就不是很严谨了,大家明白我的意思即可,不喜勿喷,欢迎评论讨论/哈哈。