小堆:任意结点的关键码均小于它的左右孩子的关键码,位于堆顶的关键码最小,从根结点到每个结点的路径上的数组元素组成 的序列都是递增的。
大堆:任意结点的关键码均大于它的左右孩子的关键码,位于堆顶的关键码最大,从根结点到每个结点的路径上的数组元素组成 的序列都是递减的。
有上面的图可以看出:对存储在下标为0开始的数组中,因此在堆中给定下标i的结点:
1.如果i =0,结点i 是根结点,没有双亲结点; 否则结点i 的双亲结点为结点(i -1)/ 2;
2.如果2 * i + 1 <= n -1, 则结点i 的 左孩子结点为2 * i +1,否则没有左孩子。
3.如果2 * i + 1 <= n -1, 则结点i 的 右孩子结点为2 * i +2,否则没有右孩子。
堆在逻辑上:完全二叉树 物理上:有序线性表
向下调整的条件(堆的创建,删除):1.当前要调整的是叶子结点
2.当前要调整的已经满足对的性质了。
向上调整:用于堆的插入
堆创建的前提:1.左右子树都是堆
2. 对所有的叶子结点建堆
3.最后一个非叶子结点就是最后一个结点的双亲
4.最后一个结点的下标是size -1;
5.最后一个非叶子结点的下标是(size -1 -1)/ 2;
总结小点:找最大的几个值--->建小堆
找最小的几个值--->建大堆
升序---------------->建大堆
降序---------------->建小堆
Heap.h
#pragma once
#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<Windows.h>
typedef struct Heap{
int array[100];
int size;
}Heap;
void HeapInit(Heap *pH, int array[], int size)
{
assert(pH);
memcpy(pH->array, array, sizeof(int)* size);
pH->size = size;
}
//交换函数
void Swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
//向下调整 递归
void AdjustDownRecursion(Heap *pH, int parent)
{
//判断是否是叶子节点
//没有左子树,没有右子树
//完全二叉树,没有左子树,就一定没有右子树
//判断有没有左子树,是判断左子树的下标是否越界
int left = 2 * parent + 1;
int right = 2 * parent + 2;
int maxChild;
if (left >= pH->size){
return;
}
maxChild = left;
if (right < pH -> size&&pH->array[right]>pH->array[left]){
maxChild = right;
}
if (pH->array[parent] > pH->array[maxChild]){
return;
}
Swap(pH->array + parent, &(pH->array[maxChild]));
AdjustDownRecursion(pH, maxChild);
}
//向下调整 非递归
void AdjustDownLoop(Heap *pH, int parent)
{
while (1){ //判断是否是叶子节点
//没有左子树,没有右子树
//完全二叉树,没有左子树,就一定没有右子树
//判断有没有左子树,是判断左子树的下标是否越界
int left = 2 * parent + 1;
int right = 2 * parent + 2;
int maxChild;
if (left >= pH->size){
return;
}
maxChild = left;
if (right < pH->size&&pH->array[right]>pH->array[left]){
maxChild = right;
}
if (pH->array[parent] > pH->array[maxChild]){
return;
}
Swap(pH->array + parent, &(pH->array[maxChild]));
parent = maxChild;
}
}
//建堆
void HeapMake(Heap*pH)
{
int i;
for (i = (pH->size - 2/ 2); i >= 0; i--){
AdjustDownLoop(pH, i);
}
}
int HeapTop(Heap*pH)
{
return pH->array[0];
}
//求堆的大小
//int HeapSize(Heap*pH)
//{
// return pH->size;
//}
//判断堆是否为空
int HeapIsEmpty(Heap*pH)
{
return pH->size == 0 ? 1 : 0;
}
void HeapPop(Heap*pH)
{
assert(pH);
assert(pH->size > 0);
pH->array[0] = pH->array[pH->size - 1];
pH->size--;
AdjustDownLoop(pH, 0);
}
void AdjustUp(Heap*pH, int child)
{
int parent;
while (1){
parent = (child - 1) / 2;
if (child == 0){
//走到整棵树的根了
break;
}
if (pH->array[parent] >= pH->array[child]){
//满足堆的条件了
break;
}
Swap(pH->array + parent, pH->array + child);
child = parent;
}
}
//建大堆
void AdjustDownArray(int array[], int size, int root)
{
int parent = root;
int left, right, max;
while (1){
left = parent * 2 + 1;
right = parent * 2 + 2;
if (left >= size){
return;
}
max = left;
if (right<size&&array[right]>array[left]){
max = right;
}
if (array[parent] > array[max]){
return;
}
Swap(array + parent, array + max);
parent = max;
}
}
//TopK问题
//在array中找到最小的K个数(建大堆)
int *TopK(int array[], int size, int k)
{
int i;
int *rarray = (int *)malloc(sizeof(int)*k);
for (i = 0; i < k; i++){
rarray[i] = array[i];
}
//建堆
for (i = (k - 2) / 2; i >= 0; i--){
AdjustDownArray(rarray, k, i);
}
for (i = k; i < size; i++){
if (array[i] < rarray[0]){
rarray[0] = array[i];
//对rarray进行向下调整
AdjustDownArray(rarray, k, 0);
}
}
return rarray;
}
//堆排序 (从小到大 建大堆)
void HeapSortRight(int array[], int size)
{
int i;
for (i = size / 2 - 1; i >= 0; i--){
AdjustDownArray(array, size, i);
}
for (i = 0; i < size;){
Swap(&(array[0]), &(array[size - 1 - i]));
AdjustDownArray(array, size - 1 - i, 0);
}
}
void Test()
{
Heap heap;
int array[] = { 53, 17, 78, 9, 45, 65, 87, 23, 31 };
int size = sizeof(array) / sizeof(int);
HeapInit(&heap, array, size);
HeapMake(&heap);
for (int i = 0; i < heap.size; i++){
printf("%d ", heap.array[i]);
}
printf("\n ");
printf("Heap\n");
}
main.c
#include"Heap.h"
int main()
{
Test();
system("pause");
return;
}