什么是堆?堆有什么特性?堆是怎样实现的?
1:堆不同于链表队列,因为链表队列是一种线性结构而堆是一种树状结构,堆有最大堆和最小堆两种。
2:只有以下几种情况才符合最大堆的特性
(1)每个父节点最多可以有两个子节点
(2)根节点的值是所有堆节点中值的最大者,且每个父节点的值要比他子节点的值大
(3)除了根节点没有兄弟节点,最后一个节点的左子节点可以没有兄弟节点,其他节点必须有兄弟节点
如图:
下图就不是最大堆:
3:堆树状结构的实现我们可以将堆中节点的值保存在数组中,这样就可以达到最大堆的效果。
(1)定义一个结构体来表示堆
typedef struct _Heap {
int* elems; //保存堆的数组
int size; //当前堆中已存储的元素个数
int capacity; //堆中最大容量
}Heap;
(2)定义了堆的结构体后就要对堆进行初始化
//初始化堆
bool initHeap(Heap& heap, int size, int* array) {
int nowSize = size > MAX_SIZE ? size : MAX_SIZE;
heap.elems = new int[nowSize];
if (!heap.elems)return false; //内存分配失败
heap.size = 0;
heap.capacity = nowSize;
if (size > 0) {
memcpy(heap.elems, array, nowSize * sizeof(int));
heap.size = size;
buildHeap(heap);
/*for (int i = 0;i < size;i++) {
insertHeap(heap, array[i]);
}*/
}
return true;
}
对堆进行初始化,在程序中对堆设置了一个最大的元素个数,所以在初始化时如果要入堆的元素个数小于最大的元素个数我们就设置为开始定义的最大元素个数,int nowSize = size > MAX_SIZE ? size : MAX_SIZE;代码如此,在为其分配一块内存,将外部的数组拷贝到分配的内存中。
(3)因为一开始入堆的元素在堆中没有调整为最大堆所以接下来就要先建立一个最大堆
//建立最大堆
static void buildHeap(Heap& heap) {
int i = 0;
for ((i = heap.size / 2 - 1);i >= 0;i--) {
adjustHeapDown(heap, i);
}
}
建立了最大堆以后就要将最大堆中的元素调整为最大堆的形式
//调整为最大堆
static void adjustHeapDown(Heap& heap,int index) {
int now = heap.elems[index];
int father, son;
for (father = index;(2 * father + 1) < heap.size;father = son) {
son = father * 2 + 1;
if ((son + 1) < heap.size && heap.elems[son + 1] > heap.elems[son]) {
son++;
}
if (now > heap.elems[son]) {
break;
}
else {
heap.elems[father] = heap.elems[son];
heap.elems[son] = now;
}
}
}
核心算法就是怎样将一个普通的堆调整为最大堆
具体思路如下:
(3)最大堆建立成功后,如果在最大堆中尾部插入元素我们要怎么 将一个一般的堆调整为最大堆呢?
代码实现
//在最大堆中插入元素
void insertHeap(Heap& heap, int index) {
if (heap.size >= heap.capacity) {
cout << "堆空间已经消耗完!";
exit(1);
}
int x = heap.size;
heap.elems[heap.size++] = index;
adjustHeapUp(heap, x);
}
//将元素插入最大堆后调整为最大堆
void adjustHeapUp(Heap& heap, int index) {
if (index < 0 || index > heap.size) {
cout << "堆空间已经消耗完!";
exit(1);
}
int father, son;
son = index;
while (son > 0) {
father = son / 2 - 1;
int tmp = heap.elems[son];
if (father >= 0) {
if (heap.elems[father] < heap.elems[son]) {
heap.elems[son] = heap.elems[father];
heap.elems[father] = tmp;
son = father;
}
else {
break;
}
}
else {
break;
}
}
}
(3)最大堆中最大元素的出堆
代码实现
//将堆中的最大元素出堆
bool outHeap(Heap& heap, int& index) {
if (heap.size <= 0)return false;
index = heap.elems[0];
heap.elems[0] = heap.elems[--heap.size];
//下面注释的两行代码和上面的代码等效
//heap.elems[0] = heap.elems[heap.size - 1];
//heap.size--;
adjustHeapDown(heap, 0);
return true;
}
//调整为最大堆
static void adjustHeapDown(Heap& heap,int index) {
int now = heap.elems[index];
int father, son;
for (father = index;(2 * father + 1) < heap.size;father = son) {
son = father * 2 + 1;
if ((son + 1) < heap.size && heap.elems[son + 1] > heap.elems[son]) {
son++;
}
if (now > heap.elems[son]) {
break;
}
else {
heap.elems[father] = heap.elems[son];
heap.elems[son] = now;
}
}
}
最大堆代码的具体实现main文件
#include<iostream>
#include<stdlib.h>
#include"Heap.h"
using namespace std;
int main(void) {
Heap heap;
int arr[] = {32,45,4,6,99 ,100};
initHeap(heap, sizeof(arr) / sizeof(arr[0]), arr);
for (int i = 0;i < heap.size;i++) {
cout << heap.elems[i] << " ";
}
cout << "堆中的元素个数为:" << heap.size << endl;
cout << endl << "在堆中插入元素" << endl;
insertHeap(heap, 120);
for (int i = 0;i < heap.size;i++) {
cout << heap.elems[i] << " ";
}
cout << "堆中的元素个数为:" << heap.size << endl;
cout << endl << "将最大堆中的最大元素出队" << endl;
int x, c = heap.size;
for (int i = 0;i < c;i++) {
outHeap(heap, x);
cout << x << " ";
}
cout << endl;
system("pause");
return true;
}
头文件的实现
#pragma once
#include<iostream>
using namespace std;
#define MAX_SIZE 128
typedef struct _Heap {
int* elems; //保存堆的数组
int size; //当前堆中已存储的元素个数
int capacity; //堆中最大容量
}Heap;
//使用静态函数只能在这个文件中被调用
static void buildHeap(Heap& heap); //建立最大堆
static void adjustHeapUp(Heap& heap, int index); //实现最大堆
static void adjustHeapDown(Heap& heap, int index);
void insertHeap(Heap& heap, int index);
bool outHeap(Heap& heap, int& index);
void destoryHeap(Heap& heap);
bool initHeap(Heap& heap, int size, int* array);
//建立最大堆
static void buildHeap(Heap& heap) {
int i = 0;
for ((i = heap.size / 2 - 1);i >= 0;i--) {
adjustHeapDown(heap, i);
}
}
//调整为最大堆
static void adjustHeapDown(Heap& heap,int index) {
int now = heap.elems[index];
int father, son;
for (father = index;(2 * father + 1) < heap.size;father = son) {
son = father * 2 + 1;
if ((son + 1) < heap.size && heap.elems[son + 1] > heap.elems[son]) {
son++;
}
if (now > heap.elems[son]) {
break;
}
else {
heap.elems[father] = heap.elems[son];
heap.elems[son] = now;
}
}
}
//在最大堆中插入元素
void insertHeap(Heap& heap, int index) {
if (heap.size >= heap.capacity) {
cout << "堆空间已经消耗完!";
exit(1);
}
int x = heap.size;
heap.elems[heap.size++] = index;
adjustHeapUp(heap, x);
}
//初始化堆
bool initHeap(Heap& heap, int size, int* array) {
int nowSize = size > MAX_SIZE ? size : MAX_SIZE;
heap.elems = new int[nowSize];
if (!heap.elems)return false; //内存分配失败
heap.size = 0;
heap.capacity = nowSize;
if (size > 0) {
memcpy(heap.elems, array, nowSize * sizeof(int));
heap.size = size;
buildHeap(heap);
/*for (int i = 0;i < size;i++) {
insertHeap(heap, array[i]);
}*/
}
return true;
}
//将元素插入最大堆后调整为最大堆
void adjustHeapUp(Heap& heap, int index) {
if (index < 0 || index > heap.size) {
cout << "堆空间已经消耗完!";
exit(1);
}
int father, son;
son = index;
while (son > 0) {
father = son / 2 - 1;
int tmp = heap.elems[son];
if (father >= 0) {
if (heap.elems[father] < heap.elems[son]) {
heap.elems[son] = heap.elems[father];
heap.elems[father] = tmp;
son = father;
}
else {
break;
}
}
else {
break;
}
}
}
//将堆中的最大元素出堆
bool outHeap(Heap& heap, int& index) {
if (heap.size <= 0)return false;
index = heap.elems[0];
heap.elems[0] = heap.elems[--heap.size];
//下面注释的两行代码和上面的代码等效
//heap.elems[0] = heap.elems[heap.size - 1];
//heap.size--;
adjustHeapDown(heap, 0);
return true;
}
//销毁堆
void destoryHeap(Heap& heap) {
delete heap.elems;
}