初夏小谈:堆的基本操作(完整版)

堆的建堆,插入、删除、操作

堆本身就是一个完全二叉树,在这里采用数组进行存储。因为可以通过下标快速找到它的孩子。堆的最大作用就是:返回一组的数据的最值。

建堆:

在建堆的过程中,需要几个基本操作:首先先建立一个数组用来存储堆数据,其次就要开始对这组数据进行建堆的过程,需要将数据进行比较、搬移。这里面需要进行向上调整将数据搬到合适的位置上。注意边界问题:在向上调整的过程中需要判断是否已经到堆顶。这里缺少一个对调整的节点的叙述,调整的结点就是最后一个非叶子结点。

插入数据:

再次就是对堆进行插入操作时将数据插入到堆的最后一个位置上,然后进行向上调整(特别像现在流行的玄幻小说主人公一路逆天的过程)。

删除数据

最后对堆做删除操作时,采用覆盖的方法将最后一个元素把堆顶元素覆盖然后进行向下调整。为什么要这样做呢?这是因为如果直接删除堆顶会破坏堆结构,这样要重新建堆。(如果是海量数据)相当麻烦。

总结为1.大堆大数往上调,2.大堆小数往下调,3.小堆小数往上调,小堆大数往下调。有点上蹿下跳的意思哈哈。堆就是这样。再向下调整的过程中需要注意是否已经到了叶子节点。

OK代码如下:

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

//顺序表建堆
typedef int HPDataType;

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


//向下调整
void ADjustDown(int array[], int size, int root);

//向上调整
void ADjustUp(int array[], int size, int root);

void CreateHeap(int array[], int size);

//建堆
void HeapCreateHeap(Heap* heap, int array[], int size, int capacity);
//增加
void AddHeapNode(Heap* heap, int data);
//删除
void DelHeapFirst(Heap* heap);
#include"Heap.h"

//建小堆
void CreateHeap(int array[], int size)
{
	int FNLNode = (size - 2) / 2;
	for (; FNLNode >= 0; FNLNode--)
	{
		ADjustDown(array, size, FNLNode);
	}
}


//这里调小堆(向下调整) 小大下
void ADjustDown(int array[], int size, int root)
{
	int left = 2 * root + 1;
	int right = 2 * root + 2;
	int num;
	if (left >= size)
	{
		return;
	}
	if (right < size && array[right] < array[left])
	{
		num = right;
	}
	else
	{
		num = left;
	}

	if (array[root] <= array[num])
	{
		return;
	}

	int temp = array[root];
	array[root] = array[num];
	array[num] = temp;

	ADjustDown(array, size, num);
}

//小堆
//向上调整
void ADjustUp(int array[], int size, int root)
{
	while (root != 0)
	{
		if (array[(root - 1) / 2] <= 0)
		{
			return;
		}
		if (array[(root - 1) / 2] < array[root])
		{
			return;
		}
		int temp = array[(root - 1) / 2];
		array[(root - 1) / 2] = array[root];
		array[root] = temp;
		root = (root - 1) / 2;
	}
	//ADjustUp(array, size, root);
}

//建堆
void HeapCreateHeap(Heap* heap, int array[], int size , int capacity)
{
	heap->capacity = capacity;
	heap->size = size;
	heap->arr = (int*)malloc(sizeof(int)*heap->capacity);
	for (int i = 0; i < size; i++)
	{
		heap->arr[i] = array[i];
	}

	CreateHeap(heap->arr, heap->size);
}

//增加
void AddHeapNode(Heap* heap, int data)
{
	if (heap->size == heap->capacity)
	{
		return;
	}
	heap->arr[heap->size] = data;
	heap->size++;
	ADjustUp(heap->arr, heap->size, heap->size - 1);
}

//删除
void DelHeapFirst(Heap* heap)//O(logn)
{
	assert(heap->size > 0);
	heap->arr[0] = heap->arr[heap->size - 1];
	heap->size--;
	ADjustDown(heap->arr, heap->size, 0);
}

//返回堆顶元素
HPDataType GetHeapFirst(Heap* heap)
{
	assert(heap->size > 0);
	return heap->arr[0];
}

//打印堆
void PrintHeap(Heap* heap)
{
	assert(heap->size > 0);
	for (int i = 0; i < heap->size; i++)
	{
		printf("%d ", heap->arr[i]);
	}
	printf("\n");
}
#include"Heap.h"

void SeqHeapTest()
{
	Heap* heap = (Heap*)malloc(sizeof(Heap));
	int array[] = { 2,6,8,4,9,3,1,10 };
	int size = sizeof(array) / sizeof(array[0]);
	int capcaty = 10;
	//建堆
	HeapCreateHeap(heap, array, size , capcaty);
	PrintHeap(heap);

	//插入
	AddHeapNode(heap, 5);
	PrintHeap(heap);

	//删除
	DelHeapFirst(heap);
	PrintHeap(heap);

	//获取堆顶元素
	int num = GetHeapFirst(heap);
	printf("%d\n", num);
}
int main()
{
	//Test();
	SeqHeapTest();
	system("pause");
	return 0;
}

结果显示:

1 4 2 6 9 3 8 10
1 4 2 5 9 3 8 10 6
2 4 3 5 9 6 8 10
2
请按任意键继续. . .
 

在堆的操作中应特别注意:1.向下调整/向上调整为什么是这样?

                                           2.当然此次堆的建立是小堆。也可以建大堆。那就稍稍调整一下,向下调整的条件和向上调整                                                  的条件,以及建堆的条件即可。

                                           3.堆本身就是一个完全二叉树。而且局部有序,堆顶为最值,这一特性是研究它的价值所在。

                                                                                                                                                                          珍&源码

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值