用数组实现堆

本文介绍了堆数据结构的基本概念,包括小堆和大堆的定义及其性质。堆是一种完全二叉树,其中每个节点的值都大于或小于其子节点。接着详细讲述了堆的实现方法,包括向下调整、堆的创建、插入、删除操作以及如何运用堆进行排序。通过这些步骤,读者可以掌握如何用数组来实现堆。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、简单了解堆

       如果有一个关键码的集合k = {k0,k1,k2,...,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:ki <= k21+1 且 ki <= k2i+2(ki >= k2i+1 且 ki >= k2i+2) i = 0,1,2...,则称为小堆(或大堆)。将根结点最大的堆叫做最大堆或大根堆,根结点最小的堆叫做最小堆或小根堆。

       堆的性质:

            ·堆中某个节点的值总是不大于或不小于其父节点的值;

            ·堆总是一棵完全二叉树。

二、堆的实现

       具体实现:

            1.堆的向下调整:将堆变成小堆或大堆(前提:调整的树左右子树必须是一个堆,才能调整)

            2.对的创建:从倒数第一个非叶子节点的子树开始调整,一直调整到节点的树,就可以调整成堆。

            3.堆的插入:先插入一个值到数组的尾上,再进行向上调整的算法,直到满足堆。

            4.堆的删除:删除堆是删除堆顶的数据,将堆顶的数据和最后一个数据一换,然后删除数组最后一数据,再进行向下调整算法。

            5.堆排序:结合了建堆和向下调整,先建堆然后将堆顶元素和数组最后一个元素交换,再将堆顶元素进行向下调整,直到排好序。

三、代码实现

#pragma once
#include <stdlib.h>
#include <assert.h>

//向下调整
//array[size]表示数组及大小
//root表示要调整的结点的下标
//前提是[root]所在结点左右子树已经满足堆的性质
void AdjustDown(int array[], int size, int root)
{
	//int left = 2 * root + 1;
	//int right = 2 * root + 2;
	int min = 2 * root + 1;
	if (min >= size)
	{
		//越界
		return;
	}
	//确定那个是最小的孩子
	if (min+1 < size && array[min+1] < array[min])
	{
		min = min+1;
	}
	if (array[root] <= array[min])
	{
		return;
	}
	//交换值
	int tmp = array[root];
	array[root] = array[min];
	array[min] = tmp;
	AdjustDown(array, size, min);
}

//建堆
void CreateHeap(int array[], int size)
{
	//从最后一个非叶子结点开始,调整到0结束
	//最后一个非叶子结点就是最后一个结点的双亲结点
	for (int i = (size - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(array, size, i);
	}
}

typedef int HPDataType;

typedef struct Heap
{
	HPDataType* array;
	int size;
	int capacity;
}	Heap;

//初始化
void HeapCreateHeap(Heap* heap, int array[], int size)
{
	heap->capacity = size * 2;
	heap->size = size;
	heap->array = (HPDataType*)malloc(sizeof(HPDataType) * size);
	for (int i = 0; i < size; ++i)
	{
		heap->array[i] = array[i];
	}

	//建堆
	CreateHeap(heap->array, heap->size);
}

//小堆
void AdjustUp(int array[], int size, int child)
{
	while (child != 0)
	{
		int parent = (child - 1) / 2;
		if (array[child] >= array[parent])
		{
			return;
		}
		int tmp = array[parent];
		array[parent] = array[child];
		array[child] = tmp;
		child = parent;
	}
}

//增加
void HeapInsert(Heap* heap, int val)
{
	heap->array[heap->size] = val;
	++heap->size;
	AdjustUp(heap->array, heap->size, heap->size - 1);
}

//删除(只能删除堆顶元素)
void HeapPop(Heap* heap)
{
	assert(heap->size > 0);
	heap->array[0] = heap->array[heap->size - 1];
	--heap->size;
	AdjustDown(heap->array, heap->size, 0);
}

//堆排序
void HeapSort(int *array, int size)
{
	CreateHeap(array, size);
	while (size--){
		int tmp = array[0];
		array[0] = array[size];
		array[size] = tmp;
		AdjustDown(array, size, 0);
	}
}

//返回堆顶元素,返回最值
HPDataType HeapTop(Heap* heap)
{
	assert(heap->size > 0);
	return heap->array[0];
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值