我们知道在C语言中也有一个名字叫做堆,那么在数据结构中的堆和c语言中的堆一样吗?
答案是:no
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...则称为小堆(大堆)
几个公式:
parent=(child-1)/2 左孩子:child=2*parent+1 右孩子:child=2*parent+1 +2
一、堆的创建:(物理存储是一个顺序表,逻辑上是完全二叉树)
将二叉树调整为最小堆的原理:
从最后一个非叶子结点开始调整,一直到跟结点为止,将每个结点及其子树调整到满足小堆的性质即可
最后一个非叶子结点就是最后一个叶子结点的双亲:[(size-1)-1/2,0] 最后一个下标为size-1
我们采用向下调整的方法进行堆的创建:
是一个持续向下走的过程
1.当前到调整的是叶子结点
2. 当前要调整的已经满足堆的性质
我们用代码实现以下大堆的创建:
先初始化堆
//初始化
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 temp;
temp = *a;
*a = *b;
*b = temp;
}
//向下调整(大堆)
void AdjustDown(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]));
//AdjustDown(pH, MaxChild);
parent = MaxChild;
}
}
//建堆
void heapmake(Heap *pH)
{
int i;
for (i = (pH->size - 2) / 2; i > 0; i--)
{
AdjustDown(pH, i); //向上调整
}
}
二、堆的删除
方法:
1.将堆中最后一个元素替代堆顶元素
2.将栈中元素减少一个,相当于将堆中最后一个元素删除
3.此时堆结构可能被破坏,在向下调整使其满足堆的性质
代码如下~
//删除
void heapPop(Heap *pH, int array[], int size)
{
assert(pH);
assert(pH->size > 0);
pH->array[0] = pH->array[pH->size - 1];
pH->size--;
AdjustDown(pH, 0);
}
三、堆的插入
方法:
在创建好的堆后面,插入之后,可能不满足堆的性质,采用向上调整的方法就行调整
代码看这里~
//向上调整
void Adjustup(Heap *pH, int child)
{
while (1)
{
int 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 heapInsert(Heap *pH, int data)
{
pH->array[pH->size++] = data; //先将数据插到堆尾
Adjustup(pH,pH->size-1); //在做向上调整
}
程序所有源代码:
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#define MAX_SIZE 100
typedef struct Heap{
int array[MAX_SIZE];
int size;
}Heap;
//交换数据
void swap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
//向下调整(大堆)
void AdjustDown(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]));
AdjustDown(pH, MaxChild);//递归
//parent = MaxChild;
//}
}
//建堆
void heapmake(Heap *pH)
{
int i;
for (i = (pH->size - 2) / 2; i >= 0; i--)
{
AdjustDown(pH, i); //向上调整
}
}
//初始化
void HeapInit(Heap *pH, int array[],int size)
{
assert(pH);
memcpy(pH->array, array, sizeof(int)*size);
pH->size = size;
}
//堆顶元素
int heaptop(Heap *pH, int array[], int size)
{
return pH->array[0];
}
//元素个数
int heapsize(Heap *pH, int array[], int size)
{
return pH->size;
}
//判空
int heapisempty(Heap *pH, int array[], int size)
{
return pH->size == 0 ? 1 : 0;
}
//删除
void heapPop(Heap *pH, int array[], int size)
{
assert(pH);
assert(pH->size > 0);
pH->array[0] = pH->array[pH->size - 1];
pH->size--;
AdjustDown(pH, 0);
}
//向上调整
void Adjustup(Heap *pH, int child)
{
while (1)
{
int 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 heapInsert(Heap *pH, int data)
{
pH->array[pH->size++] = data; //先将数据插到堆尾
Adjustup(pH,pH->size-1); //在做向上调整
}
void test()
{
Heap heap;
int array[] = { 53, 17, 78, 9, 45, 87, 23, 31 };
int size = sizeof(array) / sizeof(int);//求元素个数
HeapInit(&heap,array, size); //初始化
heapmake(&heap);
int i;
for (i = 0; i < heap.size; i++)
{
printf("%d ", heap.array[i]);
}
printf("\n");
int j = heaptop(&heap, array, size);//堆顶
printf("堆顶为:%d\n", j);
int k=heapsize(&heap, array, size);//元素个数
printf("元素个数为:%d\n", k);
int a=heapisempty(&heap, array, size);//是否为空堆
printf("%d\n", a);
heapPop(&heap, array, size); //删除
int h;
for (h = 0; h < heap.size; h++)
{
printf("%d ", heap.array[h]);
}
printf(" 删除\n");
heapInsert(&heap, 90);//插入
int b;
for (b = 0; b < heap.size; b++)
{
printf("%d ", heap.array[b]);
}
printf(" 插入\n");
}
运行结果: