文章目录
- 1 堆
- 2 基本操作
- 2.1 建堆
- 2.1.1存储结构
- 2.1.2 自上而下调整
- 2.1.3 创建堆
- 2.2 删除堆顶元素
- 2.3 增加元素
- 2.3.1 自下往上调整
- 2.3.2 增加一个元素
- 2.4 堆排序
- 3 完整示例
1 堆
- 概念:一颗完全二叉树,树中的每个结点的值不大于(或不小于)其左右孩子的值。
- 大顶堆:父结点的值大于或等于孩子结点的值,每个结点值都以它为根结点的子树的最大值;
- 小顶堆:父结点的值小于或等于孩子结点的值,每个结点值都以它为根结点的子树最小的值。
- 堆一般用优先队列,优先队列默认使用大顶堆,下面的讲解以大顶堆为主,另外当大小顶堆操作不同时,附带小顶堆实现代码。
2 基本操作
2.1 建堆
- 规则:从最后一个位置开始,从右到左,从下到上。用结点x与结点x所有孩子结点比较,如果孩子结点y有大于x的值,就交换x和y为位置,交换后,让x继续与原来y结点的所有孩子比较,直到现在位置结点x的所有孩子结点值都比它小,或者没有孩子结点为止。
2.1.1存储结构
- 数组存储完全二叉树,第一个结点序号从1开始,数组i号位的左孩子结点就是(2 * i)号位,右孩子则是(2 * i + 1)号位;
const int MAXN = 110;
int heap[MAXN];
int n;
2.1.2 自上而下调整
void downAdjust(int low, int high){
int i = low, j = i * 2;
while(j <= high){
if(j + 1 <= high && heap[j + 1] > heap[j]){
j = j + 1;
}
if(heap[j] > heap[i]){
swap(heap[j], heap[i]);
i = j;
j = i * 2;
}else{
break;
}
}
}
void downAdjust(int low, int high){
int i = low, j = i * 2;
while(j <= high){
if(j + 1 <= high && heap[j + 1] < heap[j]){
j = j + 1;
}
if(heap[j] < heap[i]){
swap(heap[j], heap[i]);
i = j;
j = i * 2;
}else{
break;
}
}
}
2.1.3 创建堆
void createHeap(){
for (int i = n / 2; i >= 1; --i)
{
downAdjust(i, n);
}
}
2.2 删除堆顶元素
void deleteTop(){
heap[1] = heap[n--];
downAdjust(1,n);
}
2.3 增加元素
2.3.1 自下往上调整
void upAdjust(int low, int high){
int i = high, j = i / 2;
while(j >= low){
if(heap[j] < heap[i]){
swap(heap[j], heap[i]);
i = j;
j = i / 2;
}else{
break;
}
}
}
void upAdjust(int low, int high){
int i = high, j = i / 2;
while(j >= low){
if(heap[j] > heap[i]){
swap(heap[j], heap[i]);
i = j;
j = i / 2;
}else{
break;
}
}
}
2.3.2 增加一个元素
void Insert(int x){
heap[++n] = x;
upAdjust(1,n);
}
2.4 堆排序
void heapSort(){
createHeap();
for (int i = n; i > 1; --i)
{
swap(heap[i], heap[1]);
downAdjust(1, i - 1);
}
}
3 完整示例
3.1 大顶堆
#include
#include
using std::swap;
const int MAXN = 110;
int heap[MAXN]= {0, 85, 55, 82, 57, 68, 92, 99, 98, 66, 56};
int n = 10;
void downAdjust(int low, int high){
int i = low, j = i * 2;
while(j <= high){
if(j + 1 <= high && heap[j + 1] > heap[j]){
j = j + 1;
}
if(heap[j] > heap[i]){
swap(heap[j], heap[i]);
i = j;
j = i * 2;
}else{
break;
}
}
}
void createHeap(){
for (int i = n / 2; i >= 1; --i)
{
downAdjust(i, n);
}
}
void deleteTop(){
heap[1] = heap[n--];
downAdjust(1,n);
}
void upAdjust(int low, int high){
int i = high, j = i / 2;
while(j >= low){
if(heap[j] < heap[i]){
swap(heap[j], heap[i]);
i = j;
j = i / 2;
}else{
break;
}
}
}
void Insert(int x){
heap[++n] = x;
upAdjust(1,n);
}
void heapSort(){
createHeap();
for (int i = n; i > 1; --i)
{
swap(heap[i], heap[1]);
downAdjust(1, i - 1);
}
}
int main(int argc, char const *argv[])
{
createHeap();
Insert(100);
for (int i = 1; i <= n; ++i)
{
printf("%d ", heap[i]);
}
return 0;
}
3.2 小顶堆(实现哈夫曼树)
#include
#include
using std::swap;
const int MAXN = 20010;
long long heap[MAXN];
int n;
void downAdjust(int low, int high){
int i = low, j = i * 2;
while(j <= high){
if(j + 1 <= high && heap[j + 1] < heap[j]){
j = j + 1;
}
if(heap[j] < heap[i]){
swap(heap[j], heap[i]);
i = j;
j = i * 2;
}else{
break;
}
}
}
void createHeap(){
for (int i = n / 2; i >= 1; --i)
{
downAdjust(i, n);
}
}
void deleteTop(){
heap[1] = heap[n--];
downAdjust(1, n);
}
void upAdjust(int low, int high){
int i = high, j = i / 2;
while(j >= low){
if(heap[j] > heap[i]){
swap(heap[j], heap[i]);
i = j;
j = i / 2;
}else{
break;
}
}
}
void Insert(int x){
heap[++n] = x;
upAdjust(1, n);
}
int main(int argc, char const *argv[])
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf("%lld", &heap[i]);
}
createHeap();
long long ans = 0;
long long x, y;
while(n > 1){
x = heap[1];
deleteTop();
y = heap[1];
deleteTop();
Insert(x + y);
ans += x + y;
}
printf("%lld\n", ans);
return 0;
}