数据结构C_堆
概念:
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:
Ki <= K2*i+1 且 Ki<= K2*i+2 (Ki >= K2*i+1 且 Ki >= K2*i+2) i =0,1,2…,则称为小堆(或大堆)。
小堆(大堆)中:任一结点的关键码均小于(大于)等于它的左右孩子的关键码,位于堆顶结点的关键码最小(最大),从根节点到每个结点的路径上数组元素组成的序列都是递增(递减)的。
堆存储在下标为0开始的数组中,因此在堆中给定下标为i的结点时:
如果i=0,结点i是根节点,没有双亲节点;否则结点i的双亲结点为结点(i-1)/2
如果2 * i + 1 <= n - 1,则结点i的左孩子为结点2 * i + 1,否则结点i无左孩子
如果2 * i + 2 <= n - 1,则结点i的右孩子为结点2 * i + 2,否则结点i无右孩子
堆的创建:
将二叉树调整为最小堆的原理:
从最后一个非叶子结点开始调整,一直到根节点为止,将每个结点及其子
树调整到满足小堆的性质即可
堆的插入&删除
堆的插入:在已经建成的最小堆的后面插入新元素,插入之后,当树中结点不满足堆的性质时,就需要对堆进行重新调整
堆的删除:删除时每次删除堆顶元素
实现堆的一系列操作:
头文件:Heap.h
#pragma once
#include <assert.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
typedef int HPDataType;
typedef struct Heap
{
HPDataType* _a;
int _size;
int _capacity;
}Heap;
//堆的初始化
void HeapInit(Heap* hp, HPDataType* a, int n);
//堆的销毁
void HeapDestory(Heap* hp);
//堆的插入
void HeapPush(Heap* hp, HPDataType x);
//堆的删除
void HeapPop(Heap* hp);
//访问堆顶
HPDataType HeapTop(Heap* hp);
//堆的大小
int HeapSize(Heap* hp);
//判断堆是否为空
int HeapEmpty(Heap* hp);
//堆的排序
int HeapSort(HPDataType* a, int n);//不要直接调Heap
//向下调整
void AdjustDown(HPDataType* a, int n, int root);
//向上调整
void AdjustUp(Heap* hp, int child);
//交换
void Swap(HPDataType* a, HPDataType* b);
//打印
void HeapPrint(Heap* hp);
void TestHeap();
源文件:Heap.c
#include"Heap.h"
//交换
void Swap(HPDataType* a, HPDataType* b)
{
HPDataType tmp = 0;
tmp = *a;
*a = *b;
*b = tmp;
}
//堆的初始化
void HeapInit(Heap* hp, HPDataType* a, int n)
{
assert(hp&&a);
hp->_a = (HPDataType*)malloc(sizeof(HPDataType)*n);
hp->_size = n;
hp->_capacity = n;
int i;
for (i = 0; i < n; i++)
{
hp->_a[i] = a[i];
}
for (i = (n - 2) / 2; i >= 0; --i)
{
AdjustDown(hp->_a, hp->_size, i);
}
}
//向下调整
void AdjustDown(HPDataType* a, int n, int root)
{
int parent = root;
int child = root * 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 AdjustUp(HPDataType* a, int n, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (a[child] < a[parent])
{
Swap(&(a[child]), &a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
break;
}
}
//堆的销毁
void HeapDestory(Heap* hp)
{
assert(hp);
free(hp);
hp->_a = NULL;
hp->_capacity = hp->_size = 0;
}
//堆的插入
void HeapPush(Heap* hp, HPDataType x)
{
if (hp->_size == hp->_capacity)
{
hp->_capacity *= 2;
hp->_a = (HPDataType*)realloc(hp->_a, sizeof(HPDataType)*hp->_capacity);
assert(hp->_a);
}
hp->_a[hp->_size] = x;
hp->_size++;
int child;
child = (int)hp->_size - 1;
AdjustUp(hp->_a, hp->_size, hp->_size - 1);
}
//堆的删除
void HeapPop(Heap* 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;
}
//判断堆是否为空
int HeapEmpty(Heap* hp)
{
if (hp->_size == 0)
{
printf("堆为空\n");
}
else
printf("堆不为空\n");
}
//堆的排序
int HeapSort(HPDataType* a, int n) //不要直接调Heap
{
//建大堆
int i, end;
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 HeapPrint(Heap* hp)
{
int i = 0;
for (i = 0; i < (int)hp->_size; i++)
{
printf("%d ", hp->_a[i]);
}
printf("\n");
}
测试:test.c
#include "Heap.h"
void TestHeap()
{
Heap hp;
HPDataType a[] = { 53, 17, 78, 9, 45, 65, 87, 23, 31 };
int n = sizeof(a) / sizeof(a[0]);
HeapInit(&hp, a, n);
printf("初始化:");
HeapPrint(&hp);
HeapPush(&hp, 100);
printf("插 入:");
HeapPrint(&hp);
printf("堆大小:%d\n", HeapSize(&hp));
printf("取堆顶:%d\n", HeapTop(&hp));
printf("删 除:");
HeapPop(&hp);
HeapPrint(&hp);
printf("判 空:");
HeapEmpty(&hp);
printf("堆大小:%d\n", HeapSize(&hp));
printf("取堆顶:%d", HeapTop(&hp));
printf("\n");
}
int main()
{
TestHeap();
system("pause");
return 0;
}