创建一个最大堆的两种方法
方法一:逐个插入来实现
(在插入数据的规程中一边插入一边调整顺序使之成为最大堆)
复杂度: O(Nlog(n))
第一步:创建堆的结构体
constexpr int Maxsize = 20;
struct Theap {
int a[Maxsize];// 用数组来存储数据
int size;//显示数据的大小
int capacity;// 当前堆的容量
};
第二步: 把堆进行初始化
Theap* creatHeap() {
Theap* temp = new Theap;//为新建的堆分配内存
temp->capacity = Maxsize;//初始化容量
temp->size = 0;// 初始化大小
temp->a[0] = INT_MAX;//把数组0号位置作为哨兵
return temp;
}
第三步:把初始化完的堆进行插入操作
(插入新元素后,新元素新元素可能回破坏最大堆的结构,每插入一次对堆进行调整一次,保证每次调整之后,这个堆都是最大堆)
// 判断树是否已满
bool If_full(Theap* T) {
if (T->capacity == T->size) {
return true;
}
else {
return false;
}
}
//实现树的插入
void Tinsert(Theap* H, int num) {
int i = 0;
if (If_full(H)) {//判断堆是否已满,比较size 和 capacity 的大小关系
cout << "堆已满" << endl;
}
i = ++H->size;//指向堆中最后一个元素的位置,假设先把数字插入到最后一个叶节点后边
// 同时插入之后给size执行+1操作
for (; H->a[i / 2] < num&& i>1; i /= 2) {
//父节点小于插入的子节点,且当前节点不为根节点;
H->a[i] = H->a[i / 2];//把父节点的值赋值给子节点
}
// 找到当前该插入的节点
H->a[i] = num;
}
方法二: 分两步走,先把数据组成完全二叉树,再把组成的完全二叉树调整成为最大树
复杂度:O(N)
第一步:批量将数据读入,并且创建成完全二叉树
创建结构体: 见法一
初始化结构体: 见法一
将数据读入并且创建成完全二叉树
// 读入数组构成满二叉树
Theap* heap_in(int arr[], int len) {// arr为传入的数组名,len为传入的数组长度
Theap* H = new Theap;
H = creatHeap();//初始化
if (len > H->capacity- H->size) {// 检测容量
cout << "容量不足" << endl;
}
for (int i = 0; i < len; i++) {
H->a[++H->size] = arr[i];//顺序将数组中的元素传入二叉树中,对size进行加加操作
}
return H;
}
第二步:将创建好的二叉树进行节点顺序调整,使之成为最大堆
//将读入的满二叉树进行排序
void rand_heap(Theap* H) {
if (If_empty(H)) {
cout << "堆为空" << endl;
}
int i = H->size / 2;//倒数第一个有孩子的节点
while (i >= 1) {//对每一个有孩子的节点都进行操作
int j = i;
int temp = H->a[j];
while (j * 2 < H->size && (H->a[j] < H->a[2 * j] || H->a[2*j+1])) {
//在当前节点所形成的树上进行比较
//进入循环的条件为当前节点有子节点,且当前节点比其中一个子节点小
H->a[j] = H->a[2 * j] > H->a[2 * j + 1] ? H->a[2 * j] : H->a[2 * j + 1];
//如果满足条件,将当前节点和大的一个节点进行交换
j = H->a[2 * j] > H->a[2 * j + 1] ? 2 * j : 2 * j + 1;//更新当前节点
}
H->a[j] = temp;
i--;//移动一个节点;
}
}
补充:最大堆的pop
问题:输入一个最大堆,根节点为最大值,但是pop出来之后,最大堆的样子就被破坏,所以,pop出根节点之后得,重新排序,使根节点变成当前树中的最大值
int T_pop(Theap* H) {
if (If_empty(H)) {
cout << "堆为空" << endl;
}
//记录根节点的值
int res = H->a[1];
//将最后一个叶子节点移动到堆根 size-1
H->a[1] = H->a[H->size--];
//从根堆开始把节点进行排序
int i = 1;
while (2 * i + 1 <= H->size) {//当当前节点的右儿子节点存在时
//记录当前节点
int temp = H->a[i];
//把当前节点和较大的子节点进行交换
H->a[i] = H->a[2 * i] < H->a[2 * i + 1]? H->a[2 * i + 1]: H->a[2 * i];
//把i更新
i = H->a[2 * i] < H->a[2 * i + 1] ? 2 * i + 1 : 2 * i;
//把交换后的值给当前的i
H->a[i] = temp;
}
return res;
}