堆的操作及实现
1、如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为
小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。**
2、堆的性质:
堆中某个节点的值总是不大于或不小于其父节点的值;
堆总是一棵完全二叉树。
3、 堆向下调整算法
现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整
成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。
4、下面我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆。
int a[] = {1,3,8,5,7,6};
5、 堆的插入
先插入一个80到数组的尾上,再进行向上调整算法,直到满足堆。
6、堆的删除
删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。
7、堆排序
8、接下来看一下代码实现
Heap.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
typedef int HPDataType;
typedef struct Heap
{
HPDataType* _a;
int _size;
int _capacity;
}Heap;
void HeapInit(Heap* hp);
void HeapDestory(Heap* hp);
void HeapCreat(Heap* hp, HPDataType* arr, int n);
void HeapPush(Heap* hp, HPDataType x);
void HeapPop(Heap* hp);
HPDataType HeapTop(Heap* hp);
int HeapSize(Heap* hp);
int HeapEmpty(Heap* hp);
void HeapSort(HPDataType* a, int n);
void HeapPrint(Heap* hp);
void HeapTest();
Heap.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "Heap.h"
void HeapInit(Heap* hp)
{
assert(hp);
//hp->_a = NULL;
hp->_capacity = hp->_size = 0;
}
void swap(int* x, int* y)
{
int tmp = 0;
tmp = *x;
*x = *y;
*y = tmp;
}
void AdjustDown(int* a, int n, int root)
{
int parent = root;
int child = parent * 2 + 1;
while (child < n)//调到叶子节点就结束
{
if(child+1 < n && a[child+1] > a[child])
{
++child;
}
if (a[parent] < a[child])
{
swap(&a[parent], &a[child]);//走到这里开始以根节点,及父节点向下调整
//调整部分的是为了交换元素后,以调整节点为根的二叉树仍然保持大顶堆
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void HeapCreat(Heap* hp ,HPDataType* arr, int n)
{
int i = 0;
assert(hp);
hp->_a = (HPDataType*)malloc(sizeof(HPDataType)*n);
memcpy(hp->_a,arr,sizeof(HPDataType)*n);
hp->_capacity = hp->_size = n;
for (i = (n-2)/2; i >= 0; i--)
{
AdjustDown(hp->_a, hp->_size, i);
}
}
void HeapDestory(Heap* hp)
{
assert(hp);
free(hp->_a);
hp->_a = NULL;
hp->_capacity = hp->_size = 0;
}
void HeapPrint(Heap* hp)
{
int i = 0;
assert(hp);
for (i = 0; i < hp->_size; i++)
{
printf("%d ", hp->_a[i]);
}
printf("\n");
}
void AdjustUp(int* a, int size, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (a[parent] < a[child])
{
swap(&a[parent], &a[child]);
child = parent;
parent = (child-1)/2;
}
else
{
break;
}
}
}
void HeapPush(Heap* hp, HPDataType x)//O(log(N))
{
assert(hp);
//判断是否需要开辟空间
if (hp->_capacity == hp->_size)
{
if(hp->_capacity == 0)
{
hp->_capacity = 3;
hp->_a = (HPDataType*)realloc(hp->_a, sizeof(HPDataType)*hp->_capacity);
}
else
{
hp->_a = (HPDataType*)realloc(hp->_a, sizeof(HPDataType)*hp->_capacity * 2);
hp->_capacity *= 2;
}
}
//加入元素,并调整重新形成大顶堆
hp->_a[hp->_size] = x;
hp->_size++;
//hp->_a[hp->_size++] = x;
AdjustUp(hp->_a, hp->_size, hp->_size-1);
}
void HeapPop(Heap* hp)//O(log(N))
{
assert(hp);
swap(&hp->_a[0], &hp->_a[hp->_size-1]);
hp->_size--;
AdjustDown(hp->_a, hp->_size, 0);
}
HPDataType HeapTop(Heap* hp)
{
assert(hp);
return hp->_a[0];
}
int HeapSize(Heap* hp)
{
assert(hp);
return hp->_size == 0 ? 0 : -1;
}
int HeapEmpty(Heap* hp)
{
assert(hp);
if (hp->_size == 0)
{
return 0;
}
else
{
return -1;
}
}
void HeapSort(HPDataType* a, int n)//时间复杂度N*log(N)
{
int i = 0;
int end = 0;
//建堆
for(i=(n-2)/2; i>=0; i--)
{
AdjustDown(a, n, i);
}
end = n-1;
while(end > 0)
{
swap(&a[0], &a[end]);
AdjustDown(a, end, 0);
--end;
}
}
void HeapTest()
{
int i = 0;
int arr[] = {27,15, 19, 18, 28, 34, 65, 49, 25, 37};
int sz = sizeof(arr)/sizeof(arr[0]);
Heap phead;
HeapInit(&phead);
HeapCreat(&phead, arr, sz);
HeapPrint(&phead);
/*HeapPush(&phead, 70);
HeapPush(&phead, 45);
HeapPush(&phead, 55);
HeapPop(&phead);*/
HeapSort(arr, sz);
for(i=0; i<sz; i++)
{
printf("%d ", arr[i]);
}
}