过了一段时间了,还是记录一下,最近感觉记忆力下降的很快啊。
大小堆的构造
首先得知道大小堆是个什么,大小堆是一种二叉树,它的要求比起平衡树来说是简单一些的,只有一个,就是所有父节点必须大于自己的子节点,但是没有什么左孩子必须小于右孩子这种。到这里其实大小堆的作用很容易看出,最大堆就是根节点最大,最小堆就是根节点最小,可以用于排序。
作为测试,这里使用整形数组作为初始化数据,二叉树可以直接使用c++单循环实现二叉树的前,中,后序,层次遍历中的结构,现在我们的任务是将一个无序的数组转为大小堆。如何做呢,首先我们将这个数组先按层次遍历顺序映射到一棵二叉树上,然后再进行排序。
层次遍历这里就不说了,前面也有,当有了一棵无序的二叉树时,这里有一个效率比较高的排序方式,这里就把遍历那篇的图拿过来说明一下
这里的数字我们既把它看做序号也把它看做节点值,很容易看出这是一个最小堆,我们现在要将其变为最大堆。我们很容易想到,肯定是需要将子节点与父节点进行比较,然后交换,但是如果是从根节点开始向下比较的话明显是不明智的。因为其并不能知道底下哪个是最大,而二叉树的特性是父子节点比较是容易的,兄弟比较是比较复杂的,而刚才的方案必定需要左右子树最大值比较。所以这里使用自底向上的方案,我们使用一个栈来存放所有父节点,刚好我们又是层次遍历生成树,所以出栈的顺序正好是从最后一个父节点往根节点。
这里的情况是4号节点第一个出栈,与左孩子比较,交换,4号节点此时为8,再与右孩子比较,交换,此时4号节点为9,结束。此时489这棵子树已经是最大堆了,3号节点出栈,和刚才一样,然后2号节点出栈,与左孩子比较,交换,这时4号节点为2,这时递归4号节点也就是左孩子,4号节点与其左孩子比较,交换,此时4号节点为4,4号节点再与右孩子比较,交换,此时4号节点值为8,最后2号节点与右孩子比较,不动,至此2号节点的子树按层次遍历为98524,这棵子树现在也是最大堆了。然后当最后一个节点也就是根节点出栈,再执行一遍刚才的递归,整棵树就是最大堆了。我们可以算算一共进行了几次比较,大概是14次的样子,这已经是很坏的情况了,所以我们可以认为时间复杂度为线性的,当然复杂度不是这么分析的。
enum SWAPMODE
{
MAX,
MIN
};
//根据数组建立堆,flag使用枚举值MIN或者MAX
BinaryTreeNode<int> * InitHeap(std::vector<int> v, int flag);
//交换两个节点的值
void Swap(BinaryTreeNode<int> *p1, BinaryTreeNode<int> *p2);
//递归排序
void Swap(BinaryTreeNode<int> *node, int flag);
//插入节点
void InsertHeap(BinaryTreeNode<int> *root, int dat