实现堆的插入,删除,取堆首元素,堆整理
1.堆的基本概念:
最大(最小)堆是一棵每一个节点的键值都不小于(大于)其孩子
(如果存在)的键值的树。大顶堆是一棵完全二叉树,
同时也是一棵最大树。小顶堆是一棵完全完全二叉树,同时也是一棵最小树。
2.堆的一些基本性质:
堆的插入和删除操作,运行时间为 O(logn),n 为树上结点的个数。
堆可以看成是一棵完全二叉树,除最后一层其余每层结点都是满的。
3.堆的插入和删除操作实现:
插入: 一开始的时候,我们将待插入的数据元素接至堆的末尾,
然后再不断向上提升直至没有大小颠倒为止。
删除: 将堆顶元素和堆的最后一个元素进行交换,
然后对堆顶元素做一个自上而下的堆调整,也就是下滤操作。
下滤操作和上溢操作类似,也是不断交换父亲节点以及其孩子节点,然后更新当前遍历到的节点的编号以及其孩子节点的编号,直到堆中没有大小颠倒为止。
代码实现如下:以大堆为例
头文件heap.h
#pragma once
#include<stdio.h>
#include<string.h>
#define MAX_SIZE 1024
typedef char Heaptype;
//比较函数
typedef int(*Compare)(Heaptype a, Heaptype b);
//堆的结构体
typedef struct Heap
{
Heaptype data[MAX_SIZE];
size_t size;
Compare cmp;
}Heap;
int Greater(Heaptype a, Heaptype b);
void HeapInit(Heap* heap, Compare cmp);
void HeapRemove(Heap* heap, Compare);
void HeapInsert(Heap* heap, Heaptype value);
void HeapPrintf(Heap* heap, const char* msg);
int Heaproot(Heap* heap, Heaptype* value);
void HeapErase(Heap* heap);
void HeapCreate(Heap* heap, Heaptype arr[], size_t size);
void HeapSort(Heaptype arr[], size_t size);
函数实现heap.c
#include"heap.h"
//小堆 任意节点的值小于它的左右孩子的值,堆顶元素值最小,
//根节点到每个节点的路径上组数元素组成的序列是递增的
int Greater(Heaptype a, Heaptype b)
{
return a > b ? 1 : 0;
}
int Less(Heaptype a, Heaptype b)
{
return a < b ? 1 : 0;
}
//初始化
void HeapInit(Heap* heap, Compare cmp)
{
if (heap == NULL)
{
//非法
return;
}
heap->size = 0;
heap->cmp = cmp;
return;
}
//删除堆
void HeapRemove(Heap* heap, Compare cmp)
{
if (heap == NULL)
{
return;
}
heap->size = 0;
heap->cmp = NULL;
return;
}
void Swap(Heaptype* a, Heaptype* b)
{
Heaptype tmp = *a;
*a = *b;
*b = tmp;
return;
}
//上浮函数 (大堆)
void AdjustUp(Heap* heap, size_t index)
{
//定义当前值为孩子节点
size_t child = index;
size_t parent = (child - 1) / 2;
while (child > 0 && heap->data[parent]<heap->data[child])
{
//父亲节点的值小于孩子节点的值,交换父子节点的值
//if (!heap->cmp(heap->data[parent], heap->data[child]))
{
Swap(&heap->data[parent], &heap->data[child]);
}
child = parent; //继续向上遍历
parent = (child - 1) / 2;
}
}
//下沉函数 -暂定为大堆
void AdjustDown(Heap*heap, size_t index)
{
size_t parent = index; //当前遍历到的节点下标0
size_t child = parent * 2 + 1; //左孩子
while (parent > 0)
{
//右孩子小于堆中元素数目 下 左孩子节点值大于右孩子节点值
if (child + 1 < heap->size && heap->cmp(heap->data[child + 1], heap->data[child]))
{
child = child + 1; //右孩子
}
if (heap->cmp(heap->data[child], heap->data[parent])) //如果孩子节点值大于父亲节点值,交换父亲和孩子节点的值
{
Swap(&heap->data[child], &heap->data[parent]);
}
else
{
break;
}
//继续向下遍历
parent = child;
child = parent * 2 + 1;
}
}
//插入(尾插) -上浮函数
void HeapInsert(Heap* heap, Heaptype value)
{
if (heap == NULL)
{
//非法
return;
}
if (heap->size >= MAX_SIZE)
{
//堆满
return;
}
heap->data[heap->size++] = value;
AdjustUp(heap, heap->size - 1);
}
//创建堆
void HeapCreate(Heap* heap, Heaptype arr[], size_t size)
{
if (heap == NULL)
{
return;
}
size_t i = 0;
for (; i < size; ++i)
{
HeapInsert(heap, arr[i]);
}
return;
}
//取堆首元素
int Heaproot(Heap* heap, Heaptype* value)
{
if (heap == NULL)
{
return NULL;
}
if (heap->size == 0)
{
return NULL ;
}
*value = heap->data[0];
return 1;
}
//删除堆首元素 (首尾交换,自上而下调整)
void HeapErase(Heap* heap)
{
if (heap == NULL)
{
return;
}
if (heap->size == 0)
{
return;
}
Swap(&heap->data[0], &heap->data[heap->size - 1]);
//删除最后一个元素
--heap->size;
AdjustDown(heap, 0);//调整0号下标的元素
return;
}
void HeapSort(Heaptype arr[], size_t size)
{
Heap heap;
HeapInit(&heap, Greater);
HeapCreate(&heap, arr, size);
while (heap.size > 0)
{
HeapErase(&heap);
}
memcpy(arr, heap.data, sizeof(Heaptype)*size);
return;
}