一、最大堆的插入

图9-3a 给出了一个具有5个元素的最大堆。由于堆是完全二叉树,当加入一个元素形成6元素堆时,其结构必如9-3b 所示。如果插入元素的值为1,则插入后该元素成为2的左孩子,相反,若新元素的值为5,则该元素不能成为2的左孩子(否则将改变最大树的特性),应把2下移为左孩子(如图9 - 3 c所示),同时还得决定在最大堆中5是否占据2原来的位置。由于父元素20大于等于新插入的元素5,因此可以在原2所在位置插入新的元素。假设新元素的值为21而不是5,这时,同图9-3c 一样,把2下移为左孩子,由于21比父元素值大,所以2 1不能插入原来2所在位置,因此把20移到它的右孩子所在位置, 21插入堆的根节点(如图9-3d所示)。

二、最大堆的删除

从最大堆中删除一个元素时,该元素从堆的根部移出。例如,对图9-3d的最大堆进行删除操作即是移去元素21,因此最大堆只剩下五个元素。此时,图9-3d中的二叉树需要重新构造,以便仍然为完全二叉树。为此可以移动位置6中的元素,即2。这样就得到了正确的结构(如图9-4a所示),但此时根节点为空且元素2不在堆中,如果2直接插入根节点,得到的二叉树不是最大树,根节点的元素应为2、根的左孩子、根的右孩子三者中的最大值。这个值是20,它被移到根节点,因此在位置3形成一个空位,由于这个位置没有孩子节点,2可以插入,最后形成的最大堆如图9-3a 所示。现在假设要删除20,在删除之后,堆的二叉树结构如图9-4b 所示,为得到这个结构,10从位置5移出,如果将10放在根节点,结果并不是最大堆。把根节点的两个孩子(15和2)中较大的一个移到根节点。假设将10插入位置2,结果仍不是最大堆。因此将14上移,10插入到位置4,最后结果如图9-4c 所示。

 

三、最大堆的初始化

使用数组初始化一个最大堆,先将数组的元素复制到最大堆中,然后对其进行重新排序,并初始化为最大堆

假设开始数组a 中有n 个元素,另有n= 10,a [ 1 : 1 0 ]中元素的关键值为[ 20,12,35,15,10,80,30,17,2,1 ],这个数组可以用来表示如图9-5a 所示的完全二叉树,这棵完全二叉树不是最大树。为了将图9-5a 的完全二叉树转化为最大堆,从第一个具有孩子的节点开始(即节点10),这个元素在数组中的位置为i = [n /2 ],如果以这个元素为根的子树已是最大堆,则此时不需调整,否则必须调整子树使之成为堆。随后,继续检查以i-1, i-2等节点为根的子树,直到检查到整个二叉树的根节点(其位置为1)。下面对图9-5 a中的二叉树完成这一系列工作。最初, i = 5,由于10 > 1,所以以位置i为根的子树已是最大堆。下一步,检查根节点在位置4的子树,由于15 < 17,因此它不是最大堆,为将其变为最大堆,可将15与17进行交换,得到的树如图9-5b 所示。然后检查以位置3为根的子树,为使其变为最大堆,将80与35进行交换。之后,检查根位于位置2的子树,通过重建过程使该子树成为最大堆。将该子树重构为最大堆时需确定孩子中较大的一个,因为12 < 17,所以17成为重构子树的根,下一步将12与位置4的两个孩子中较大的一个进行比较,由于12 < 15,15被移到位置4,空位8没有孩子,将12插入位置8,形成的二叉树如图9-5 c。最后,检查位置1,这时以位置2或位置3为根的子树已是最大堆了,然而20 < (m a x [ 17 , 80 ] ),因此80成为最大堆的根,当80移入根,位置3空出。由于20 <(m a x [ 35 , 30 ] ),位置3被35占据,最后20占据位置6。图9-5d 显示了最终形成的最大堆。

 

四、源码

1.MaxHeap.h

#pragma once
#include"MyException.h"
/*最大堆*/
template<class T>
class MaxHeap {
public:
MaxHeap(int maxSize=10);
~MaxHeap();
int Size()const;
T Max()const;
MaxHeap<T>& Insert(const T &x);
MaxHeap<T>& DeleteMax(T &x);
void Initialize(T* a, int size, int arraySize);
void Output(ostream& out)const; private:
int curSize;
int maxSize;
T *heap;
};
template<class T>
MaxHeap<T>::MaxHeap(int maxSize) {
this->maxSize = maxSize;
heap = new T[this->maxSize+1];
curSize = 0;
}
template<class T>
MaxHeap<T>::~MaxHeap() {
delete[] heap;
}
template<class T>
int MaxHeap<T>::Size()const {
return curSize;
}
template<class T>
T MaxHeap<T>::Max()const {
if (curSize == 0)
throw OutOfBounds();
return heap[1]; }
template<class T>
MaxHeap<T>& MaxHeap<T>::Insert(const T &x) {
if (curSize == maxSize) //最大堆满
throw NoMem();
int i = ++curSize; //先增加尺寸,然后i就是要插入位置的坐标
while (i != 1 && x > heap[i / 2]) { //将待插入元素与其父节点进行比较,若大于父节点,则父节点下移,待插入位置移动到父节点
heap[i] = heap[i / 2]; //父节点下移
i = i / 2; //待插入位置移动到父节点
}
heap[i] = x; //最终要插入的位置
return *this;
}
template<class T>
MaxHeap<T>& MaxHeap<T>::DeleteMax(T &x) {
if (curSize == 0)
throw OutOfBounds();
x = heap[1]; //重构堆,并且y保存的是最后一个元素
T y = heap[curSize--]; int i = 1; //堆的当前节点
int ci = 2; //i的孩子
while (ci <= curSize) {
//使得ci为孩子节点中的最大值得坐标
if (ci < curSize && heap[ci] < heap[ci + 1]) {
ci++;
}
if (y >= heap[ci])
break; //将子节点中的最大值移动到父节点
heap[i] = heap[ci];
i = ci; //父节点下移一层
ci = ci * 2; //子节点下移一层
}
heap[i] = y;
return *this;
}
/*初始化一个非空最大堆
a:输入的一个数组,用于初始化最大堆
size:数组中有效元素的个数(使用a[0]-a[size-1]初始化最大堆)
arraySize:数组的大小*/
template<class T>
void MaxHeap<T>::Initialize(T* a, int size, int arraySize) {
delete[] heap;
curSize = size;
maxSize = arraySize;
heap = new T[maxSize + 1];
for (int i = 1; i <= curSize; i++)
heap[i] = a[i - 1]; for (int i = curSize / 2; i > 0; i--) {
T parent = heap[i];
int childrenIndex = 2 * i;
while (childrenIndex <= curSize) {
//将children移到最大的孩子
if (childrenIndex < curSize && heap[childrenIndex] < heap[childrenIndex + 1]) {
childrenIndex++;
}
//父节点大,不用移动位置
if (parent > heap[childrenIndex])
break;
//父节点小,需要移动位置(此时其子树可能不满足最大堆的性质,因此要下移,通过while循环来使下移的节点成为新的父节点,直到其所有子树均满足最大堆的性质)
heap[childrenIndex / 2] = heap[childrenIndex];
childrenIndex = childrenIndex * 2;//下移一层
}
heap[childrenIndex / 2] = parent;
}
}
template<class T>
void MaxHeap<T>::Output(ostream& out)const {
for (int i = 1; i <= curSize; i++) {
out << heap[i] << " ";
}
}
template<class T>
ostream& operator<<(ostream& out,const MaxHeap<T>& maxHeap) {
maxHeap.Output(out);
return out;
}

2.MyException.h

 
#include<iostream>
#include <string> using namespace std; class NoMem {
public:
NoMem() {
this->message = "内存不足";
}
NoMem(string msg) {
this->message = msg;
}
void OutputMessage() {
cout << message << endl;
} private:
string message; };
class OutOfBounds {
public:
OutOfBounds() {
this->message = "输入超过了数组的界";
}
OutOfBounds(string msg) {
this->message = msg;
}
void OutputMessage() {
cout << message << endl;
} private:
string message; };
class BadInput {
public:
BadInput() {
this->message = "输入有误";
}
BadInput(string msg) {
this->message = msg;
}
void OutputMessage() {
cout << message << endl;
} private:
string message; };

3.主函数

#include"MaxHeap.h"
#include"MyException.h"
#include<iostream>
using namespace std;
void main() {
try {
MaxHeap<int> heap;
int a[10] = { 4,5,2,1,7,3,9,0,6,8 };
heap.Initialize(a, 10, 10);
cout << heap << endl;
cout << "max:" << heap.Max() << endl; int x = 0;
heap.DeleteMax(x);
cout << heap << endl; heap.DeleteMax(x);
cout << heap << endl; heap.DeleteMax(x);
cout << heap << endl; heap.DeleteMax(x);
cout << heap << endl; heap.DeleteMax(x);
cout << heap << endl;
cout << "size:" << heap.Size() << endl;
cout << "max:" << heap.Max() << endl; heap.DeleteMax(x);
cout << heap << endl; heap.DeleteMax(x);
cout << heap << endl; heap.DeleteMax(x);
cout << heap << endl; heap.DeleteMax(x);
cout << heap << endl;
cout << "size:" << heap.Size() << endl; heap.DeleteMax(x);
cout << heap << endl;
cout << "size:" << heap.Size() << endl; //heap.DeleteMax(x);
//cout << heap << endl;
//cout << "size:" << heap.Size() << endl; heap.Insert(4).Insert(3);
cout << heap << endl;
cout << "size:" << heap.Size() << endl; heap.Insert(6).Insert(100);
cout << heap << endl;
cout << "size:" << heap.Size() << endl; heap.Insert(40);
cout << heap << endl; }catch(OutOfBounds o){
o.OutputMessage();
} system("pause"); }

五、程序运行结果

数据结构c++语言描述——最大堆(MaxHeap)的更多相关文章

  1. 数据结构(Java语言描述)-第一章:概述

    第一章 概述 1.0 序言 自己为啥要学数据结构嘞,我觉得主要有以下三个原因: 前段时间在看并发编程时,发现aqs,corrunthashmap等底层都用到了数据结构,主要的有队列,还有链表,学习数据 ...

  2. 数据结构--Java语言描述

    本篇文章是为了记录自己在学习数据结构时的笔记,会对常见的数据结构做基本的介绍以及使用Java语言进行实现.包括 动态数组 栈 队列 链表 二分搜索树 优先队列和堆 线段树 Trie树 并查集 AVL树 ...

  3. 数据结构( Pyhon 语言描述 ) — —第10章:树

    树的概览 树是层级式的集合 树中最顶端的节点叫做根 个或多个后继(子节点). 没有子节点的节点叫做叶子节点 拥有子节点的节点叫做内部节点 ,其子节点位于层级1,依次类推.一个空树的层级为 -1 树的术 ...

  4. c++学习书籍推荐《数据结构C++语言描述:应用标准模板库STL(第2版)》下载

    本书是Ford和Topp两位教授于1996看出版的名著Data Structures with C++的第2版,在全球范围内已经有数以万计的学生从中受益.作者将C++语言作为算法描述语言,应用包含规范 ...

  5. 数据结构( Pyhon 语言描述 ) — — 第5章:接口、实现和多态

    接口 接口是软件资源用户可用的一组操作 接口中的内容是函数头和方法头,以及它们的文档 设计良好的软件系统会将接口与其实现分隔开来 多态 多态是在两个或多个类的实现中使用相同的运算符号.函数名或方法.多 ...

  6. 数据结构( Pyhon 语言描述 ) — —第9章:列表

    概念 列表是一个线性的集合,允许用户在任意位置插入.删除.访问和替换元素 使用列表 基于索引的操作 基本操作 数组与列表的区别 数组是一种具体的数据结构,拥有基于单个的物理内存块的一种特定的,不变的实 ...

  7. 数据结构( Pyhon 语言描述 ) — — 第7章:栈

    栈概览 栈是线性集合,遵从后进先出原则( Last - in first - out , LIFO )原则 栈常用的操作包括压入( push ) 和弹出( pop ) 栈的应用 将中缀表达式转换为后缀 ...

  8. 数据结构( Pyhon 语言描述 ) — — 第2章:集合概览

    集合类型 定义 个或多个其他对象的对象.集合拥有访问对象.插入对象.删除对象.确定集合大小以及遍历或访问集合的对象的操作 分类 根据组织方式进行 线性集合 线性集合按照位置排列其项,除了第一项,每一项 ...

  9. 数据结构( Pyhon 语言描述 ) — — 第4章:数据和链表结构

    数据结构是表示一个集合中包含的数据的一个对象 数组数据结构 数组是一个数据结构 支持按照位置对某一项的随机访问,且这种访问的时间是常数 在创建数组时,给定了用于存储数据的位置的一个数目,并且数组的长度 ...

随机推荐

  1. FpSpread添加标注

    先看效果 实现: FarPoint.Web.Spread.StyleInfo Errorcss = new FarPoint.Web.Spread.StyleInfo(); Errorcss.Bord ...

  2. SQL Server2008知识点总结

    1.SQL Server2008基本服务及功能 2.管理SQL Server2008安全:登录.权限.数据库用户.管理角色.服务器角色.管理数据库角色. 3.数据库管理.表管理(临时表和系统表.列值属 ...

  3. Mysql常用命令记录

    -- 导出数据库: mysqldump -u user_name -p database_name > import_file.sql -- 执行脚本 source database.sql

  4. vc2015编译protobuf

    下载地址:https://github.com/google/protobuf 1.编译通过cmake生成sln文件来编译用cmd命令 cd 到3.0.0-beta-4\cmake mkdir bui ...

  5. git教程 入门

    快速上传已有代码到github 如何将最新代码上传到github,这里讲本地已有项目文件的情况(假如本地有一个helloworld的工程目录,目录中有很多项目文件.),步骤如下: 前提:已安装git客 ...

  6. EasyShortcut Easyshortcut easyShortcut 简介

    关于EasyShortcut Easyshortcut easyShortcut 简介: 参考: http://chunsheng.me/EasyShortcut/

  7. css 溢出文本显示省略号

    这个标题其实已经是一个老生常谈的问题了.很多时候,比如网站最基本的文章列表,标题会很长,而显示列表的区域宽度却没有这么宽,这时候最正常的做法就是 让超出宽度的部分文字用省略号(…)来表示.通常做法是网 ...

  8. python学习第二天 --变量及其字符串

    python变量: 在计算机程序中,变量不仅可以是数字,还可以是任意数据类型. 在Python程序中,变量是用一个变量名表示,变量名必须是大小写英文.数字和下划线(_)的组合,且不能用数字开头. 在P ...

  9. 字符串:各种奇葩的内置方法 - 零基础入门学习Python014

    字符串:各种奇葩的内置方法 让编程改变世界 Change the world by program 字符串:各种奇葩的内置方法 或许现在又回过头来谈字符串,有些朋友可能会觉得没必要,也有些朋友会觉得不 ...

  10. PHP(w3s) 笔记

    <!--php注释-->// 这是单行注释# 这也是单行注释/*这是多行注释块它横跨了多行*/