概述
二叉树相关
1、完全二叉树:若二叉树的深度为h,则除第h层外,其他层的结点全部达到最大值,且第h层的所有结点都集中在左子树。
2、满二叉树:满二叉树是一种特殊的的完全二叉树,所有层的结点都是最大值,即每层都是满节点状态。
堆
1、堆是一颗完全二叉树;
2、堆中的某个结点的值总是大于等于(最大堆)或小于等于(最小堆)其孩子结点的值。
3、堆中每个结点的子树都是堆树。
4、每个堆的堆顶元素必然是堆中所有元素中最大值(最大堆)或最小值(最小堆)
下图所示为最小堆:
因为是完全二叉树结构,我们把堆顶下标置为1,后面的节点依次标号,可以发现这样一个规律:
左子节点的下标=父节点下标*2
右子节点的下标=父子节点下标*2+1
我们可以利用这样的规律利用数组来实现一个抽象的完全二叉树,从而形成一个堆
插入元素演示:
插入元素结果:
删除堆顶元素演示:
删除后:
详细原理见代码注释:
代码
#ifndef _HEAP_H
#define _HEAP_H
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
// ************* 输出堆 *************
void output_impl(int n, bool left, string const& indent, vector<int>& vec)
{
if (n * 2 + 1 < (int)vec.size())
{
output_impl(n * 2 + 1, false, indent + (left ? "| " : " "), vec);
}
cout << indent;
cout << (left ? '\\' : '/');
cout << "-----";
cout << vec[n] << endl;
if (n * 2 < (int)vec.size())
{
output_impl(n * 2, true, indent + (left ? " " : "| "), vec);
}
}
void output(vector<int>& v)
{
if (v.size() <= 1)
return;
if (v.size() >= 4)
{
output_impl(3, false, "", v);
}
cout << v[1] << endl;
if (v.size() >= 3)
{
output_impl(2, true, "", v);
}
}
// ***************************************
//指定最小堆
template<typename T>
class Less
{
public:
bool operator()(const T& a, const T& b)const
{
return a < b;
}
};
//指定最大堆
template<typename T>
class Greater
{
public:
bool operator()(const T& a, const T& b)const
{
return a > b;
}
};
//堆,默认最小堆less排序
template<class T, class Compare = Less<T> >
class Heap
{
private:
int lastIndex; //数组下标,从1开始计数
Compare cmp; //排序类,判断最大堆还是最小堆
vector<T> vec; //存储数组,vec[1]是堆顶
public:
Heap() :lastIndex(1)
{
vec.push_back(T()); //预先分配空间,因为要用下标1作为堆顶
}
~Heap() {};
//堆插入元素
void push(T value)
{
vec.push_back(value); //先插入尾部
int curIndex = lastIndex; //获取当前下标
//插入元素上浮
while (curIndex / 2)
{
if (cmp(vec[curIndex], vec[curIndex / 2])) //cmp类来比较确定是最小堆还是最大堆
{
//需要上浮,说明插入元素比父节点更大(更小)
swap(vec[curIndex], vec[curIndex / 2]);
curIndex /= 2;
}
else
break;
}
lastIndex++;
}
//获取堆中所有元素
int size() { return lastIndex - 1; };
//获取堆顶元素
T top() { return empty() ? T() : vec[1]; };
//判断是否为空堆
bool empty() { return vec.size() <= 1; }
//删除堆顶元素
T pop()
{
if (lastIndex <= 1)
return T();
int curIndex = 1;
T res = vec[1];
vec[1] = vec[lastIndex - 1]; //为保证完全二叉树结构,把最后一个元素移到堆顶,然后执行下沉操作
vec.pop_back();
lastIndex--;
//下沉操作
while (curIndex * 2 <= lastIndex - 1) //不要越界
{
int child = curIndex * 2;
if (child + 1 <= lastIndex - 1 && cmp(vec[child + 1], vec[child])) //找子节点合适值替换,比如最小堆就找两个子节点中最小的那个和父节点比较
{
child++; //右子节点更小(更大)
}
if (cmp(vec[child], vec[curIndex])) //子节点是否比父节点更大(更小)
{
swap(vec[child], vec[curIndex]);
}
else
break;
curIndex = child;
}
return res; //返回删除堆顶元素
}
//打印堆元素
void printHeap()
{
output(vec);
}
};
int main()
{
Heap<int, Greater<int>> hp; //默认为最小堆,现在Greater<int>设为最大堆
hp.push(3);
hp.push(2);
hp.push(1);
hp.push(10);
hp.push(20);
hp.push(6);
hp.printHeap();
cout << "--------------pop()---------------" << endl << endl;
hp.pop();
hp.printHeap();
cout << "--------------pop()---------------" << endl << endl;
hp.pop();
hp.printHeap();
cout << "--------------top()---------------" << endl;
cout << hp.top() << endl;
cout << "--------------pop()---------------" << endl << endl;
hp.pop();
hp.printHeap();
cout << "--------------pop()---------------" << endl << endl;
hp.pop();
hp.printHeap();
}
#endif // !MINHEAP_H
图形化输出堆
寻找数组中第k大的数(堆排序应用)
#include <iostream>
#include <string>
#include<vector>
using namespace std;
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int n = nums.size();
//建立小根堆
for (int i = 0; i < k; i++)
swim(nums, i);
for (int i = k; i < n; i++)
{
if (nums[i] > nums[0])
{
swap(nums[i], nums[0]);
sink(nums, 0, k);
}
}
return nums[0];
}
//上浮操作
void swim(vector<int>& nums, int i)
{
while (i > 0 && nums[i] < nums[(i - 1) / 2])
{
swap(nums[(i - 1) / 2], nums[i]);
i = (i - 1) / 2;
}
}
//下沉操作
void sink(vector<int>& nums, int i, int n)
{
int j = 0;
while (i * 2 + 1 < n)
{
j = i * 2 + 1;
if (j + 1 < n && nums[j + 1] < nums[j])
j++;
if (nums[i] < nums[j])
return;
swap(nums[i], nums[j]);
i = j;
}
}
};
int main()
{
vector<int> v{ 2,22,45,4,2,6,99,77 };
Solution s;
cout << s.findKthLargest(v, 3); //找第三大的数
}