堆的建堆,插入、删除、操作
堆本身就是一个完全二叉树,在这里采用数组进行存储。因为可以通过下标快速找到它的孩子。堆的最大作用就是:返回一组的数据的最值。
建堆:
在建堆的过程中,需要几个基本操作:首先先建立一个数组用来存储堆数据,其次就要开始对这组数据进行建堆的过程,需要将数据进行比较、搬移。这里面需要进行向上调整将数据搬到合适的位置上。注意边界问题:在向上调整的过程中需要判断是否已经到堆顶。这里缺少一个对调整的节点的叙述,调整的结点就是最后一个非叶子结点。
插入数据:
再次就是对堆进行插入操作时将数据插入到堆的最后一个位置上,然后进行向上调整(特别像现在流行的玄幻小说主人公一路逆天的过程)。
删除数据:
最后对堆做删除操作时,采用覆盖的方法将最后一个元素把堆顶元素覆盖然后进行向下调整。为什么要这样做呢?这是因为如果直接删除堆顶会破坏堆结构,这样要重新建堆。(如果是海量数据)相当麻烦。
总结为: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.堆本身就是一个完全二叉树。而且局部有序,堆顶为最值,这一特性是研究它的价值所在。
珍&源码