首先说明堆数据结构和操作系统的堆区的结构是不同的,进行的操作也不同,详见操作系统内存管理的原理,基本原理是因为操作系统会维护一张空闲内存区的链表,对链表应用算法进行分配内存块
以大根堆为例:
建立大根堆:
step①:容器标准化(使得与完全二叉树逻辑上有相同性质)
step②:重构容器,建立堆结构:Bigheap_build
从最后一个非叶节点开始向整棵树的树根进行大根调整Bigheap_adjust
大根堆插入:
step①:先在堆后push,
step②:而后,新堆进行重构Bigheap_build
堆数据结构描述:
#pragma once
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
void print(int a)
{
cout << a << " ";
}
void swap(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
class Bigheap
{
public:
Bigheap(vector<int>&a)
{
this->heap.resize(a.size());//需提前开辟空间
this->heap = a;
}
vector<int>& getheap()
{
return this->heap;
}
//基于大根堆排序
void standardize();
void Bigheap_adjust(vector<int>::iterator k, vector<int>::iterator high);
void Bigheap_build(vector<int>::iterator high);
void Bigheap_sort();
//插入
void Bigheap_insert(int num);
//删除
void Bigheap_del(int bias);
private:
vector<int> heap;
};
void Bigheap::Bigheap_adjust(vector<int>::iterator k, vector<int>::iterator high)
{
*(this->heap.begin()) = *k;
int bias = k - this->heap.begin();
vector<int>::iterator i = this->heap.begin() + 2 * bias;//a.begin()相当于数组下标0
while (i <= high)
{
//k和bias同时修改方可用迭代器实现
//第一个判断的目的是找左右孩子中最大的孩子
if (i != high && *i < *(i + 1))
{ //若i==a,end()则一定没有右子树,故只有i!=a.end()-1才有可能有右子树,才有可能进行i++;
//如果*i >= *(i + 1)即左孩子大于右孩子那么就不必再向右子树找了,用左孩子和哨兵比较即可
i++;//左孩子小于根,考察右孩子或右子树
}
if (*(this->heap.begin()) >= *i)break;//i所指为k结点最大的孩子,左右孩子都小于根k(k==i/2),则该元素该放在k位置
else//k的最大的一个孩子比根大
{
//这里不能简单的认为swap(a,b)
*k = *i;//大的一个孩子i应该放在k位置
k = i;//在原来k位置的大孩子为顶的子树中继续考察,i指向该子树顶也就是k的大孩子
}
bias = i - this->heap.begin();//i指针代数化
if (2 * bias > this->heap.size() - 1)break;
i = this->heap.begin() + 2 * bias;//形式化
}
*k = *this->heap.begin();
}
void Bigheap::Bigheap_build(vector<int>::iterator high)
{
//a.begin()相当于数组下标0
//大根堆建立
vector<int>::iterator i = this->heap.begin() + (high - this->heap.begin()) / 2;
for (; i > this->heap.begin(); i--)
Bigheap_adjust(i, high);
}
void Bigheap::standardize()
{
//首先应该调整,使得i从1开始
this->heap.push_back(0);
for (vector<int>::iterator it = this->heap.end() - 1; it > this->heap.begin(); it--)
{
(*it) = *(it - 1);
}
(*(this->heap.begin())) = 0;//哨兵位置
}
void Bigheap::Bigheap_sort()
{
//每一趟将堆顶与待排序序列最后一个元素swap
for (vector<int>::iterator high = this->heap.end() - 1; high >= this->heap.begin() + 2; high--)
{
swap(*(this->heap.begin() + 1), *high);
Bigheap_build(high - 1);
}
}
void Bigheap::Bigheap_insert(int num)
{
this->heap.push_back(num);
Bigheap_build(this->heap.end() - 1);
}
void Bigheap::Bigheap_del(int bias)
{
//int bias;//输入i的编号
//cin>>bias;
//bias = 3;//比如输入位置i=3
vector<int>::iterator i = this->heap.begin() + bias;
swap(*i, *(this->heap.end() - 1));//将i位置和最后一个位置元素互换
//而后删除最后一个位置,将剩下的元素进行建立大根堆
this->heap.pop_back();
Bigheap_build(this->heap.end() - 1);
}
class smallheap
{
public:
smallheap(vector<int>&a)
{
this->heap.resize(a.size());//需提前开辟空间
this->heap = a;
}
vector<int>& getheap()
{
return this->heap;
}
//基于小根堆排序
void standardize();
void smallheap_adjust(vector<int>::iterator k, vector<int>::iterator high);
void smallheap_build(vector<int>::iterator high);
void smallheap_sort();
//插入
void smallheap_insert(int num);
//删除
void smallheap_del(int bias);
private:
vector<int> heap;
};
void smallheap::standardize()
{
//首先应该调整,使得i从1开始
this->heap.push_back(0);
for (vector<int>::iterator it = this->heap.end() - 1; it > this->heap.begin(); it--)
{
(*it) = *(it - 1);
}
(*(this->heap.begin())) = 0;//哨兵位置
}
void smallheap::smallheap_adjust(vector<int>::iterator k, vector<int>::iterator high)
{
*this->heap.begin() = *k;
int bias = k - this->heap.begin();
vector<int>::iterator i = this->heap.begin() + 2 * bias;//a.begin()相当于数组下标0
while (i <= high)
{
//k和bias同时修改方可用迭代器实现
//第一个判断的目的是找左右孩子中最小的孩子
if (i != high && *i > *(i + 1))
{ //若i==a,end()则一定没有右子树,故只有i!=a.end()-1才有可能有右子树,才有可能进行i++;
//如果*i >= *(i + 1)即左孩子大于右孩子那么就不必再向右子树找了,用左孩子和哨兵比较即可
i++;//左孩子小于根,考察右孩子或右子树
}
if (*this->heap.begin() <= *i)break;//i所指为k结点最小的孩子,左右孩子都大于根k(k==i/2),则该元素该放在k位置
else//k的最小的一个孩子比根小
{
//这里不能简单的认为swap(a,b)
*k = *i;//小的一个孩子i应该放在k位置
k = i;//在原来k的小孩子为顶的子树中继续考察,i指向该子树顶也就是k的小孩子
}
bias = i - this->heap.begin();//i指针代数化
if (2 * bias > this->heap.size() - 1)break;
i = this->heap.begin() + 2 * bias;//形式化
}
*k = *this->heap.begin();
}
void smallheap::smallheap_build(vector<int>::iterator high)
{
//a.begin()相当于数组下标0
//小根堆建立
vector<int>::iterator i = this->heap.begin() + this->heap.size() / 2;
for (; i > this->heap.begin(); i--)
smallheap_adjust( i, high);
}
void smallheap::smallheap_sort()
{
//每一趟将堆顶与待排序序列最后一个元素swap
for (vector<int>::iterator high = this->heap.end() - 1; high >= this->heap.begin() + 2; high--)
{
swap(*(this->heap.begin() + 1), *high);
smallheap_build( high - 1);
}
}
void smallheap::smallheap_insert(int num)
{
this->heap.push_back(num);
smallheap_build(this->heap.end() - 1);
}
void smallheap::smallheap_del(int bias)
{
//int bias;//输入i的编号
//cin>>bias;
//bias = 3;//比如输入位置i=3
vector<int>::iterator i = this->heap.begin() + bias;
swap(*i, *(this->heap.end() - 1));//将i位置和最后一个位置元素互换
//而后删除最后一个位置,将剩下的元素进行建立小根堆
this->heap.pop_back();
smallheap_build(this->heap.end() - 1);
}
main:
#define _CRT_SECURE_NO_WARNINGS
#include"class_heap.hpp"
int main()
{
vector<int> a = { 53,17,78,9,45,65,87,32 };
Bigheap big_heap1(a);
cout << "原容器:";
for_each(big_heap1.getheap().begin(), big_heap1.getheap().end(),print);
cout << endl;
big_heap1.standardize();//使得与完全二叉树结点号有对应关系
cout << "标准化:";
for_each(big_heap1.getheap().begin(), big_heap1.getheap().end(), print);//测试代码
cout << endl;
big_heap1.Bigheap_build(big_heap1.getheap().end() - 1);//传入的是逻辑上完全二叉树的最后一个结点的序号
cout << "容器重构为大根堆:";
for_each(big_heap1.getheap().begin()+1, big_heap1.getheap().end(), print);
cout << endl;
//在大根堆结构中插入与删除(原来是堆,插完后还是堆)
big_heap1.Bigheap_insert(39);
cout << "插入后:";
for_each(big_heap1.getheap().begin() + 1, big_heap1.getheap().end(), print);
cout << endl;
big_heap1.Bigheap_del(5);
cout << "删除后:";
for_each(big_heap1.getheap().begin() + 1, big_heap1.getheap().end(), print);
cout << endl;
//基于大根堆的堆排序(不再是大根堆数据结构)
big_heap1.Bigheap_sort();
cout << "基于大根堆的排序:";
for_each(big_heap1.getheap().begin() + 1, big_heap1.getheap().end(), print);
cout << endl;
//--------
smallheap smallheap1(a);
cout << "原容器:";
for_each(smallheap1.getheap().begin(), smallheap1.getheap().end(), print);
cout << endl;
smallheap1.standardize();
cout << "标准化:";
for_each(smallheap1.getheap().begin(), smallheap1.getheap().end(), print);//测试代码
cout << endl;
smallheap1.smallheap_build(smallheap1.getheap().end()-1);//传入的是逻辑上完全二叉树的最后一个结点的序号
cout << "容器重构为小根堆:";
for_each(smallheap1.getheap().begin() + 1, smallheap1.getheap().end(), print);
cout << endl;
//在小根堆结构中插入与删除(原来是堆,插完后还是堆)
smallheap1.smallheap_insert(39);
cout << "插入后:";
for_each(smallheap1.getheap().begin() + 1, smallheap1.getheap().end(), print);
cout << endl;
smallheap1.smallheap_del(5);
cout << "删除后:";
for_each(smallheap1.getheap().begin() + 1, smallheap1.getheap().end(), print);
cout << endl;
//基于小根堆的堆排序(不再是小根堆数据结构)
smallheap1.smallheap_sort();
cout << "基于小根堆的排序:";
for_each(smallheap1.getheap().begin() + 1, smallheap1.getheap().end(), print);
cout << endl;
system("pause");
return 0;
}