《算法导论》— Chapter 6 堆排序
2015-07-05 10:56
453 查看
序
本文主要介绍堆排序算法(HeapSort),堆排序像合并排序而不像插入排序,堆排序的运行时间为O(nlgn);像插入排序而不像合并排序,它是一种原地(in place)排序算法。在任何时候,数组中只有常数个元素存储在输入数组以外,这样,堆排序就把插入排序和合并排序的优点结合起来。堆排序还引入了另外一种算法设计技术,利用某种数据结构(在此算法中为“堆”)来管理算法执行中的信息。堆数据结构不只在堆排序算法中有用,还可以构成一个有效的优先队列。堆数据结构是一种数组对象,它可以被视为一颗完全二叉树,树种每个结点与数组中存放该结点值的那个元素对应。树的每一层都是填满的,最后一层除外(最后一层从一个结点的左子树开始填)。
堆数据结构在最大(最小)优先级队列中得到有效的应用,本文以大顶堆为例,详细给出堆排序算法的实现以及最大级优先队列的算法实现。
git代码
GitHub chapter 6 程序代码下载
堆数据结构
堆数据结构是一种数组抽象,它可以被看做一颗完全二叉树,树中每个结点与数组中存放该结点值的那个元素对应。除了堆顶根节点之外,所有树结点都有父节点,同理,除了叶子结点外,所有树结点都至少有一个儿子结点。//求左儿子结点 int Left(int i) { return 2 * i; } //求右儿子结点 int Right(int i) { return 2 * i + 1; } //求父节点 int Parent(int i) { return i / 2; }
在堆排序算法中,有以下几个关键步骤:
MaxHeapify过程,其运行时间为O(logn),是保持最大堆性质的关键;
BuildMaxHeap过程,建立大顶堆,在无序的原始数组中构造出一颗大顶堆;
HeapSort过程,对大顶堆从最后一个叶子结点开始处理排序,得到一组升序排列的序列。
堆排序算法实现
(1) MaxHeap.h#ifndef MAX_HEAP_H #define MAX_HEAP_H /* * 大顶堆 MaxHeap 数据结构 */ #include <iostream> using namespace std; class MaxHeap { public: MaxHeap(int *data, int size); ~MaxHeap(); void maxHeapSort(); void displayList(int size) { for (int i = 0; i < size; i++) cout << m_dataList[i] << "\t"; cout << endl; } private: int *m_dataList; int m_heapSize; void buildMaxHeap(int *data); void maxHeapify(int *data, int i); int Left(int i) { return 2 * i; } int Right(int i) { return 2 * i + 1; } void swap(int &a, int &b) { int temp = a; a = b; b = temp; } }; #endif
(2)MaxHeap.cpp
#include "MaxHeap.h" #include <iostream> using namespace std; MaxHeap::MaxHeap(int *data, int size) :m_dataList(data), m_heapSize(size) {} MaxHeap::~MaxHeap() { delete m_dataList; } void MaxHeap::buildMaxHeap(int *data) { for (int i = m_heapSize / 2; i >= 1; i--) { maxHeapify(data, i); } } void MaxHeap::maxHeapify(int *data, int i) { int largest; int left = Left(i); int right = Right(i); if (left <= m_heapSize && data[left-1] > data[i-1]) largest = left; else largest = i; if (right <= m_heapSize && data[right-1] > data[largest-1]) largest = right; if (largest != i) { swap(data[i - 1], data[largest - 1]); maxHeapify(data, largest); } } void MaxHeap::maxHeapSort() { buildMaxHeap(m_dataList); int length = m_heapSize; for (int i = length; i >= 1; i--) { swap(m_dataList[i - 1], m_dataList[0]); m_heapSize--; maxHeapify(m_dataList, 1); } }
(3)main.cpp
#include "MaxHeap.h" #include <iostream> #include <cstdlib> #include <ctime> using namespace std; const int N = 10; int main() { //声明一个待排序数组 int array ; //设置随机化种子,避免每次产生相同的随机数 srand(time(0)); for (int i = 0; i<N; i++) { array[i] = rand() % 101;//数组赋值使用随机函数产生1-100之间的随机数 } //调用堆排序函数对该数组进行排序 MaxHeap *maxHeap = new MaxHeap(array, N); cout << "排序前:" << endl; maxHeap->displayList(N); maxHeap->maxHeapSort(); cout << endl << "排序后:" << endl; maxHeap->displayList(N); system("pause"); return 0; }
测试结果:
最大优先级队列
优先级队列是一种用来维护一组元素构成的集合元素的数据结构,这一组元素中的每一个都有关键字key,分为最大优先级队列和最小优先级队列两种。本章集中讨论了基于最大堆实现的最大优先级队列。
一个最大优先级队列有以下关键操作:
Insert(x) : 将关键字x插入集合,并保持集合的性质;
MaxiMum():返回集合中最大关键字的元素,对于最大优先级队列,队头元素即是最大关键字元素;
ExtractMax() : 去掉并返回队列集合中最大关键字的元素;
IncreaseKey(x , k) : 将元素位置x处的关键字值增加到k , k 本值不可小于x位置元素的初始值;
算法实现:
(1) MaxPriQueue.h
#ifndef _MAXPRIQUEUE_H_
#define _MAXPRIQUEUE_H_
/*
* 最大堆实现的最大优先级队列数据结构
*/
#include <iostream>
using namespace std;
class MaxPriQueue{
public:
MaxPriQueue(int *data, int size);
~MaxPriQueue();
//将元素x插入该优先级队列
void insert(int x);
//去掉并返回队列中具有最大关键字的元素
int extractMax();
//将元素x的关键字的值增加到k
void increaseKey(int x, int k);
void maxHeapify(int *data, int i);
int MaxiMum()
{
return m_dataList[0];
}
void displayList()
{
for (int i = 0; i < m_queueSize; i++)
cout << m_dataList[i] << "\t";
cout << endl;
}
private:
int *m_dataList;
int m_queueSize; //优先级当前长度
//求左儿子结点 int Left(int i) { return 2 * i; } //求右儿子结点 int Right(int i) { return 2 * i + 1; } //求父节点 int Parent(int i) { return i / 2; }
void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
void buildMaxHeap(int *data);
};
#endif
(2) MaxPriQueue.cpp
#include "MaxPriQueue.h" #include <iostream> using namespace std; //构造函数 MaxPriQueue::MaxPriQueue(int *data, int size) :m_dataList(data), m_queueSize(size) { //构建大顶堆 buildMaxHeap(m_dataList); } MaxPriQueue::~MaxPriQueue() { delete m_dataList; } void MaxPriQueue::buildMaxHeap(int *data) { //从最后一个根元素自底向上调整 for (int i = m_queueSize / 2; i >= 1; i--) maxHeapify(data, i); } int MaxPriQueue::extractMax() { if (m_queueSize < 1) return -1; int max = m_dataList[0]; m_dataList[0] = m_dataList[m_queueSize - 1]; m_queueSize--; maxHeapify(m_dataList, 1); return max; } void MaxPriQueue::increaseKey(int x, int k) { if (k < m_dataList[x-1]) return; m_dataList[x-1] = k; //自底向上调整大顶堆 while (x > 1 && m_dataList[Parent(x)-1] < m_dataList[x-1]) { swap(m_dataList[Parent(x)-1], m_dataList[x-1]); x = Parent(x); } } void MaxPriQueue::insert(int x) { m_queueSize++; m_dataList[m_queueSize - 1] = x-1; increaseKey(m_queueSize, x); } void MaxPriQueue::maxHeapify(int *data, int i) { int largest; int left = Left(i); int right = Right(i); if (left <= m_queueSize && data[left - 1] > data[i - 1]) largest = left; else largest = i; if (right <= m_queueSize && data[right - 1] > data[largest - 1]) largest = right; if (largest != i) { swap(data[i - 1], data[largest - 1]); maxHeapify(data, largest); } }
(3) main.cpp
#include "MaxPriQueue.h" #include <iostream> #include <cstdlib> #include <ctime> using namespace std; const int N = 10; int main() { //声明一个待排序数组 int array ; //设置随机化种子,避免每次产生相同的随机数 srand(time(0)); for (int i = 0; i<N; i++) { array[i] = rand() % 101;//数组赋值使用随机函数产生1-100之间的随机数 } //调用堆排序函数对该数组进行排序 MaxPriQueue *maxPriQueue = new MaxPriQueue(array, N); cout << "大顶堆:" << endl; maxPriQueue->displayList(); cout << "堆顶元素" << maxPriQueue->MaxiMum() << endl; cout << "删除最大元素" << maxPriQueue->extractMax() << endl; cout << "新的大顶堆:" << endl; maxPriQueue->displayList(); cout << "将队头元素增加至100." << endl; maxPriQueue->increaseKey(1, 100); cout << "新的大顶堆:" << endl; maxPriQueue->displayList(); system("pause"); return 0; }
测试结果:
相关文章推荐
- android 中 webview 怎么用 localStorage
- 设计模式
- [LeetCode] Path Sum II
- jsp EL 表达式
- Crashing Robots - poj 2632
- LTE中的功率控制
- 从零开始写驱动——vfd专用驱动芯片HT16514并行驱动程序编写
- 求double类型的n次方
- ArrayList和LinkedList的区别
- android通过drawable资源实现常用的自定义效果
- Python安装第三方库遇到 error: Unable to find vcvarsall.bat
- LeetCode88 Merge Sorted Array
- 如何提高JavaScript代码质量
- 论程序员在当今社会的重要性
- 计算机操作系统笔记——问答题
- Unity3D 模型换肤技术
- HDU 3068 最长回文
- 判断两序列是否为同一二叉搜索树序列
- iOS面试题归总
- Lua脚本语法说明(转)