数据结构 堆

来源:互联网 发布:交通枢纽大数据 编辑:程序博客网 时间:2024/05/18 13:11

堆的概念:

优先队列: 特殊的队列,取出元素的顺序是依照元素的优先权(关键字)大小,而不是元素进入队列的顺序

堆:实现用完全二叉树进行实现


堆的特性: 堆必须是一棵完全二叉树

大顶堆:一棵二叉树中所有的节点都是其子树节点中的最大值

小顶堆:一棵二叉树中所有的节点都是其子树节点中的最小值


堆的插入:


如图所示 这是一个大顶堆

在6处插入一个新的元素

如果插入的是20,符合大顶堆的规则,此时不用发生变换

如果插入的是35 35要大于31,不符合大顶堆的规则,此时将35与31交换

如果插入的是58 58要大于31且大于44,不符合规则,此时发生两次交换,最终58成为堆顶


注:在编写程序前,需要明确一个知识点,如果一个节点的编号是i 则它的父节点的编号为i/2

证明如下:

(1)假设子节点为第K层的第2M个结点。

则其父节点为第K-1层的第M个结点。

根据二叉树的特性,满二叉树的第K层共有2^K-1个节点,则父节点为全二叉树的第t=2^(K-2)-1+M个节点。子节点为全二叉树的第i=2^(K-1)-1+2M。即父结点编号为t=(i-1)/2=i/2。


(2)假设子节点为第K层的第2M+1个结点。

则其父节点为第K-1层的第M+1个结点。

则父结点为全二叉树的第t=2^(K-2)-1+M+1=2^(K-2)+M个结点。子节点为全二叉树的第i=2^(K-1)-1+2M+1=2^(K-1)+2M个结点。即父结点编号为t=i/2

从而得证。


插入程序:

void MaxHeap::Insert(Elementype item) {int i;  //初始插入位置if (IsFull()) {cout << "the heap has been full!" << endl;return;}i = ++size;  //先比较 后插入for (; heapData[i / 2] < item; i /= 2) {  //如果父节点比子节点小 则交换位置 同时将节点位置调整为父节点heapData[i] = heapData[i/2];}heapData[i] = item;  //节点入位置return;}


最大堆的删除:


(1)先从堆中取出顶部,比如这个堆的顶是58,则取出58用于返回

(2)将堆中的最后一个元素移动到堆顶

(3)31和左右两子进行比较 如果比孩子小 则进行交换(这里比44要小),则和44进行交换

(4)31到了[2]这个位置,此时31比35要小 将31和35进行交换

(5)最终31移动到了[4]这个位置

Elementype MaxHeap::deleteMaxHeap() {int Parent, Child;Elementype MaxItem, temp;   //MaxItem 用来暂存顶部的元素 temp用来移动Parent = 1;Child = 0;if (IsEmpty()) {cout << "The heap has been empty!!" << endl;return NULL;}MaxItem = heapData[1];  //堆顶temp = heapData[size--];  //用来暂存数据for (; Parent * 2 <= size; Parent = Child) {   //将Parent设置为1 从顶部开始 进行比较Child = Parent * 2;  //先调整成左节点//先判断左右子哪个更大if ((Child < size) && (heapData[Child] < heapData[Child + 1]))Child++; if (temp >= heapData[Child])break;   //找到合适的位置 退出循环else     heapData[Parent] = heapData[Child];  //Parent用子节点代替}heapData[Parent] = temp;return MaxItem;   //返回底部最大值}


最大堆的构建:


(1)先从最后一个带子节点的元素开始(最后一个顶元素,这里是87)

(2)将87调整成大顶堆(调整方法与删除一样)

(3)然后遍历 依次将30->83->83->43->66->调成大顶堆


void MaxHeap::adjustMent(int i) {int Parent, Child;   //调整父节点 子节点Parent = i; if (IsEmpty()) {cout << "The heap has been empty!" << endl;return;}Elementype HeapTop = heapData[i];  //取出根节点用于比较for (; HeapTop * 2 <= size; Parent = Child) {Child = Parent * 2;if ((Child < size) && (heapData[Child] < heapData[Child + 1]))Child++;if (HeapTop >= heapData[Child])break;elseheapData[HeapTop] < heapData[Child];}heapData[Parent] = HeapTop;}void MaxHeap::adjustMentHeap() {int i = size/2; //从最后一个节点的根节点开始for (; i > 0; i--) {adjustMent(i);}}



整个程序架构如下

#include <iostream>#include <algorithm>#include <stdlib.h>#define MAXSIZE 100001#define MAXDATA 999999using namespace std;class HeapNode;typedef int Elementype;class MaxHeap {public:Elementype *heapData;int size;  //当前数组元素个数int capacity; //数组容量public:MaxHeap(int MaxSize) {heapData = new Elementype[MaxSize];  //申请内存空间size = 0;capacity = MaxSize;heapData[0] = MAXDATA;  //哨兵节点}/*操作结合*/bool IsFull();    //判断是否为满void Insert(Elementype item);  //插入一个元素bool IsEmpty();   //判断是否为空Elementype deleteMaxHeap();   //弹出一个最大元素void adjustMent(int i); //调整void adjustMentHeap();  //调整整个堆};bool MaxHeap::IsFull() {  //判断为满if (size == capacity)return true;return false;}bool MaxHeap::IsEmpty() {  //判断为空if (size == 0)return true;return false;}void MaxHeap::Insert(Elementype item) {int i;  //初始插入位置if (IsFull()) {cout << "the heap has been full!" << endl;return;}i = ++size;  //先比较 后插入for (; heapData[i / 2] < item; i /= 2) {  //如果父节点比子节点小 则交换位置 同时将节点位置调整为父节点heapData[i] = heapData[i/2];}heapData[i] = item;  //节点入位置return;}Elementype MaxHeap::deleteMaxHeap() {int Parent, Child;Elementype MaxItem, temp;   //MaxItem 用来暂存顶部的元素 temp用来移动Parent = 1;Child = 0;if (IsEmpty()) {cout << "The heap has been empty!!" << endl;return NULL;}MaxItem = heapData[1];  //堆顶temp = heapData[size--];  //用来暂存数据for (; Parent * 2 <= size; Parent = Child) {   //将Parent设置为1 从顶部开始 进行比较Child = Parent * 2;  //先调整成左节点//先判断左右子哪个更大if ((Child < size) && (heapData[Child] < heapData[Child + 1]))Child++; if (temp >= heapData[Child])break;   //找到合适的位置 退出循环else     heapData[Parent] = heapData[Child];  //Parent用子节点代替}heapData[Parent] = temp;return MaxItem;   //返回底部最大值}void MaxHeap::adjustMent(int i) {int Parent, Child;   //调整父节点 子节点Parent = i; if (IsEmpty()) {cout << "The heap has been empty!" << endl;return;}Elementype HeapTop = heapData[i];  //取出根节点用于比较for (; HeapTop * 2 <= size; Parent = Child) {Child = Parent * 2;if ((Child < size) && (heapData[Child] < heapData[Child + 1]))Child++;if (HeapTop >= heapData[Child])break;elseheapData[HeapTop] < heapData[Child];}heapData[Parent] = HeapTop;}void MaxHeap::adjustMentHeap() {int i = size/2; //从最后一个节点的根节点开始for (; i > 0; i--) {adjustMent(i);}}int main() {MaxHeap aaa(100);aaa.Insert(10);aaa.Insert(20);aaa.Insert(30);aaa.Insert(40); aaa.Insert(50);system("PAUSE");return 0;}