最小堆的插入、删除和创建的C语言实现

来源:互联网 发布:足球数据直播 编辑:程序博客网 时间:2024/06/05 11:21

堆是一种特殊的“队列”,它取出元素的顺序是依照元素的优先级大小,而不是元素进入队列的先后顺序。堆具有两个特性,1.结构性:它是能用数组表示的完全二叉树。2.堆序性:任一结点的关键字是其子树所有结点的最大值(最大堆)或最小值(最小堆),即任意子树也应该是个堆。

根据最小堆的结构特性,本文使用含有哨兵元素的数组实现了最小堆的创建、插入和删除。

数据类型定义和函数声明

#include<stdio.h>#include<stdlib.h>#define MinData -100//哨兵元素的值typedef struct HeapStruct{int *p;int size;int capacity;} *MinHeap;MinHeap Init_MinHeap(int MaxSize);int IsFull(MinHeap H);int IsEmpty(MinHeap H);void Insert(MinHeap H, int data);int Delete(MinHeap H);void BuildMinHeap(MinHeap H, int N);void PrintValue(MinHeap H);

程序中用到的功能函数

int IsFull(MinHeap H){return (H->size == H->capacity) ? 1 : 0;}int IsEmpty(MinHeap H){return (H->size == 0) ? 1 : 0;}void PrintValue(MinHeap H){int i;printf("最小堆中的元素依次为:");for (i = 1; i <= H->size; i++)printf("%d ", H->p[i]);printf("\n");}

最小堆的初始化

该函数给最小堆分配了内存空间并完成初始化操作,此时最小堆中元素为空。

MinHeap Init_MinHeap(int MaxSize){MinHeap H = (MinHeap)malloc(sizeof(HeapStruct));H->p = (int*)malloc((MaxSize + 1) * sizeof(int));H->p[0] = MinData;H->size = 0;H->capacity = MaxSize;return H;}

在最小堆中插入元素

插入元素的关键是把要插入的元素放在最小堆的合适位置中。所谓合适即不破坏最小堆的结构性和堆序性。

为了将一个元素data插入到堆中,在遵守堆的结构性特点(完全二叉树)基础上,在下一个空闲位置创建一个空穴。如果元素data可以放在该空穴中而并不破坏堆的序,则完成插入。否则,把空穴的父节点上的元素移入该空穴中,这样,空穴就朝着根的方向上移动一层。继续该过程知道元素data能放入空穴中。因为空穴在逐渐往树的上方移动,所以把这种策略成为“上滤”。

void Insert(MinHeap H, int data){int i;if (IsFull(H)){printf("最小堆已满,无法插入元素");return;}for (i = ++H->size; data < H->p[i / 2]; i /= 2)H->p[i] = H->p[i / 2];H->p[i] = data;}

删除最小堆中的最小元素

删除元素的关键是把堆中最后一个元素移动到最小堆中的合适位置。所谓合适即不破坏最小堆的结构性和堆序性。

删除元素以类似于插入的方式处理。找到最小元很容易(第一个元素),困难的部分是删除后的调整。当删除一个最小元时,在根节点处产生一个空穴。由于现在堆里少了一个元素,因为堆中最后一个元素lastvalue必须移动到该堆的某个地方。通常我们将空穴的两个儿子中较小者移入空穴,这样就把空穴向下退了一层。重复该步骤知道lastvalue可以放在空穴中。通常把这种策略成为“下滤”。

int Delete(MinHeap H){int minvalue , lastvalue, child, parent;if (IsEmpty(H)){printf("最小堆已满,无法删除元素");return -999;}minvalue = H->p[1];lastvalue = H->p[H->size--];for (parent = 1; 2 * parent <= H->size; parent = child){child = 2 * parent;/*默认左结点的元素值更小*/if (child != H->size && H->p[child + 1] < H->p[child])/*若右节点的元素值更小,则调整child*/child++;if (lastvalue < H->p[child])break;elseH->p[parent] = H->p[child];}H->p[parent] = lastvalue;return minvalue;}

创建最小堆

在创建最小堆时,可以 : 通过插入操作Insert函数,将N 个元素一个个相继插入到一个初始为空的堆中去 ,但其时间代价最大为O(NlogN)。

也可以在线性复杂度下建立最小堆,基本步骤为:1. 将N个元素按输入顺序存入,先满足完全二叉树的结构特性。2.调整各节点位置,以满足最大堆的堆序性。这样创建最小堆时的时间代价为O(N)。在调整节点位置时,只需对从第N/2个节点到第一个节点依次应用“下滤”策略即可,其实也就是进行了N/2次的近似删除操作。

void BuildMinHeap(MinHeap H, int N){int i, num, parent, child, root, lastvalue;if (N > H->capacity){printf("要创建的元素个数超过堆的最大容量,创建失败");return;}for (i = 1; i <= N; i++){printf("请输入要插入的元素值:");scanf_s("%d", &num);H->p[i] = num;}H->size = N;root = N / 2;/*从第N/2个结点到第1个结点依次进行下滤 近似N/2次删除操作*/while (root){lastvalue = H->p[root];for (parent = root; 2 * parent <= H->size; parent = child){child = 2 * parent;/*默认左结点的元素值更小*/if (child != H->size && H->p[child + 1] < H->p[child])/*右结点元素值更小*/child++;if (lastvalue < H->p[child])break;elseH->p[parent] = H->p[child];}H->p[parent] = lastvalue;--root;}}

主程序

测试序列:150 80 40 30 10 70 110 100 20 90 60 50 120 140 130

正确结果为:10 20 40 30 60 50 110 100 150 90 80 70 120 140 130

void main(){int num;MinHeap H;H = Init_MinHeap(100);BuildMinHeap(H, 15);PrintValue(H);printf("请输入你要插入的数据:");scanf_s("%d", &num);Insert(H, num);PrintValue(H);printf("请输入你要插入的数据:");scanf_s("%d", &num);Insert(H, num);PrintValue(H);num = Delete(H);printf("删除的元素为:%d\n", num);PrintValue(H);}


原创粉丝点击