基础知识:
逻辑结构: 完全二叉树
物理(存储)结构: 顺序表
大根堆
-
每一个结点元素的值都不小于左右子树结点的值
-
根结点的元素最大
小根堆
-
每一个结点元素的值都不大于左右子树结点的值
-
根结点的元素最小
完全二叉树结点位置计算
-
对于完全二叉树,最后一个分支结点是第n/2个结点 下标为n/2-1
-
对于完全二叉树,第i个结点如果有左右孩子,则左孩子是第2i个 右孩子是第2i+1个
-
对于完全二叉树,下标为i结点如果有左右孩子,则左孩子下标为2i+1,右孩子下标为2i+2
-
对于完全二叉树,第i个结点的父结点为 第 i/2 个
-
对于完全二叉树,下标为i结点的父结点下标为 (i-1)/2
大根堆功能实现
#include "maxheap.h"
/*
typedef int ElemType;
struct Maxheap{
size_t cap; //容量
size_t size; //元素个数
ElemType elems[];
};
typedef struct MaxHeap * MHeap;
*/
MHeap create_maxheap(size_t cap){
MHeap heap = (MHeap)malloc(sizeof(struct MaxHeap) + cap * sizeof(ElemType));
if(heap != NULL){
heap->cap = cap;
heap->size = 0;
}
return heap;
}
//只调整了pos下标 使其作为一棵子树满足大根堆
static void adjust_maxheap(ElemType elems[],size_t pos,size_t n){
ElemType key = elems[pos];
size_t child = 2*pos + 1;
while(child < n){//左孩子存在的
if(child+1 < n && elems[child] < elems[child+1]){//右孩子存在 且 右孩子比左孩子大
++child;
}
//child记录了左右孩子中较大孩子的下标位置
if(key < elems[child]){//孩子结点元素比 父结点元素 大
elems[pos] = elems[child]; //把孩子元素放到父结点中
pos = child;
child = 2*pos + 1;
}else{
break;
}
}
elems[pos] = key;
}
void rebuild_maxheap(ElemType elems[],size_t n){
int i = n/2-1;
for(;i>=0;--i){
adjust_maxheap(elems,i,n);
}
}
//用n个元素创建一个大根堆
MHeap create_by_elems_maxheap(ElemType elems[],size_t n){
MHeap heap = (MHeap)malloc(sizeof(struct MaxHeap) + n * sizeof(ElemType));
if(heap != NULL){
heap->cap = n;
heap->size = n;
int i;
for(i=0;i<n;++i){
heap->elems[i] = elems[i];
}
rebuild_maxheap(heap->elems,heap->size);//把这组数据调整为大根堆
}
return heap;
}
void foreach_maxheap(MHeap heap,void (*foreach)(ElemType)){
assert(heap!=NULL);
int i;
for(i=0;i<heap->size;++i){
foreach(heap->elems[i]);
}
}
/*
MHeap h = create_xx(arr,10);
push_maxheap(h,1024);
*/
//压入一个元素之后 需要保持大根堆的特征
int push_maxheap(MHeap heap,ElemType elem){
assert(heap!=NULL);
if(heap->cap == heap->size){
return FAILURE;
}
int i = heap->size;
while(i>0){
int parent = (i-1)/2; //父结点的下标位置
if(heap->elems[parent] < elem){
heap->elems[i] = heap->elems[parent];
i = parent;
}else{
break;
}
}
heap->elems[i] = elem;
++heap->size;
return SUCCESS;
}
int pop_front_maxheap(MHeap heap,ElemType *pElem){
assert(heap!=NULL);
if(empty_maxheap(heap)){
return FAILURE;
}
if(pElem!=NULL){
*pElem = heap->elems[0];
}
//用最后一个元素替换第一个元素
--heap->size;
heap->elems[0] = heap->elems[heap->size];
adjust_maxheap(heap->elems,0,heap->size);
return SUCCESS;
}
int remove_maxheap(MHeap heap,size_t pos,ElemType *pElem){
assert(heap!=NULL);
//pos [1,heap->size]
if(heap->size==0 || pos==0 || pos>heap->size){
return FAILURE;
}
if(pElem!=NULL){
*pElem = heap->elems[pos-1];
}
--heap->size;
ElemType elem = heap->elems[heap->size]; //最后一个元素
heap->elems[pos-1] = elem;
adjust_maxheap(heap->elems,pos-1,heap->size); //向下调整
int index = pos-1;
//elem = heap->elems[index];
if(elem == heap->elems[index]){//没有把elem往下沉 试着向上浮
while(index>0){
int parent = (index-1)/2;
if(heap->elems[parent] < elem){
heap->elems[index] = heap->elems[parent];
index = parent;
}else{
break;
}
}
heap->elems[index] = elem;
}
return SUCCESS;
}
int pop_back_maxheap(MHeap heap,ElemType *pElem){
assert(heap!=NULL);
if(empty_maxheap(heap)){
return FAILURE;
}
--heap->size;
if(pElem!=NULL){
*pElem = heap->elems[heap->size];
}
return SUCCESS;
}
void clear_maxheap(MHeap heap){
assert(heap!=NULL);
heap->size = 0;
}
size_t size_maxheap(MHeap heap){
assert(heap!=NULL);
return heap->size;
}
bool empty_maxheap(MHeap heap){
assert(heap!=NULL);
return heap->size == 0;
}
void destroy_maxheap(MHeap heap){
assert(heap!=NULL);
free(heap);
}
//有一组数据 要进行排序 堆排序 时间复杂度 O(nlogn)
//排行榜 TOP10 TOP100 1亿
void heap_sort(ElemType elems[],size_t n){
rebuild_maxheap(elems,n);
int i;
for(i=n-1;i>0;--i){//n
int tmp = elems[i];
elems[i] = elems[0];
elems[0] = tmp;
adjust_maxheap(elems,0,i); //函数里循环执行次数最多情况 logn
}
}
堆的用途:排序 TOP10