您的位置:首页 > 其它

堆的实现、堆排序及其应用

2013-10-23 02:10 302 查看
堆排序和其他排序算法的比较



上图引自:http://hi.baidu.com/ycdoit/item/6b5f5b9571a843becc80e560,这篇文章也解释了可能的优化途径。

(sort 是STL的排序方法,qsort是库函数,quicksort是没有经过优化的快速排序实现,Heapsort是一般的堆排序实现)

堆的定义

谈堆排序首先要有堆,堆类似于一种特殊的完全二叉树,分为最大堆和最小堆。

最大堆:所有结点的值都不大于其父结点。

最小堆:所有结点的值都不小于其父结点。

关于堆的定义和特性,请参考http://blog.csdn.net/v_JULY_v/article/details/6198644,非常好的一篇关于堆排序的文章。

堆的实现

谈这个话题是写这篇文章的主要原因。

我们常说程序就是数据结构和算法的组合,具体到堆的实现上,算法体现出了非常强大的抽象作用,表现在:

1. 存储最小堆或者最大堆的数据结构就是一个简单的数组。

2. 算法实现的时候,把这个数组看作一种完全二叉树:

(1) 从根结点开始(编号为1),分层遍历这颗二叉树,每个结点的编号是上一个遍历到的结点编号+1,就是说:

1

/ \

2 3

/ \

4 5

(2) 二叉树各个结点按照编号顺序存在数组中。

(3) 对于完全二叉树来说,下面的条件成立:

第i个结点的父结点为第|_i/2_|个结点(|_i/2_|表示对i/2的结果向下取整)。

第i个结点的左孩子结点为第2i个结点。

第i个结点的右孩子结点为第2i+1个结点。

带着上面的逻辑来实现最小堆和最大堆,就是把父结点和左右子结点的大小关系映射为数组中第i个数据和第2i以及第2i+1个数据的大小关系。

这里我们没有定义二叉树的数据结构,而是在处理数组的时候将其看作分层遍历的完全二叉树结点,具体表现在算法的实现上面。

很多人在想到堆的时候就想到二叉树的数据结构,进而认为堆的实现就基于这种数据结构,堆排序也是对二叉树的排序,这是不准确的,其实我们的操作,包括创建一个最小堆或最大堆,以及进行堆排序都是在上面映射关系的基础上,用处理数组元素的方式进行的。

当然,可以用二叉树的数据结构,但是考虑到这种数据结构相比数组而言,每个结点的大小增加了,而堆排序的算法却没有优化,还是平均N*log2(N)(N为结点数量),必要性在哪里?

所以,有时候一种不同的对待事物的方式可以极大提高我们的编程效率,这就是算法的威力所在。

寻找M个数中的前K个最小的数并保持有序

这个算法题在这篇文章中得到了精彩详尽的讨论,强烈推荐感兴趣的同学学习一下。

这里我们使用最大堆来解决:

1. 用M个数里面的前K个数创建一个K个元素的最大堆。

2. 将第M-k个数到第M个数依次和上面最大堆的第一个元素(存储这个最大堆的第1个数据,也即是抽象的完全二叉树的根结点数据)比较,如果大于等于堆顶元素,继续下一个数进行比较(堆顶元素在最大堆中最大),如果小于堆顶元素,就把堆顶元素值设置为这个数,然后重新对这个堆进行重新最大堆化,使之符合最大堆的要求。

3. 结束之后最大堆里面放的就是最小的K个数了,这时对最大堆进行堆排序,就解决这个问题了。

时间复杂度为 :

O(K) + (M - K)*log2(K)

| |

创建K个元素最大堆的时间复杂度 对剩余M-K个数据进行比较并每次对最大堆进行重新最大堆化

在K远小于M的时候,时间复杂度相当于M*log2(K)。

完整代码实现:

P.S.如果需要在M非常大的情况下测试,可以考虑将M个数据保存在文件中,然后依次读取进行处理。

#include <iostream>
using namespace std;

/******************
根据输入的int数组创建一个最大堆
input:      输入的int数组
maxHeap:     最大堆数组
maxHeapCount 最大堆中元素的个数
******************/
void createMaxHeap(const int * input, int * maxHeap, const int maxHeapCount);

/******************
对输入int数组进行操作,使之符合最大堆的条件:
所有结点的值不大于其父结点

maxHeap:     最大堆数组
pos:         最大堆中的元素标志位,由1开始
maxHeapCount 最大堆中元素的个数
******************/
void heapifyMaxHeap(int * maxHeap, const int pos, const int maxHeapCount);

/******************
对最大堆排序,使之由小到大有序

maxHeap:     最大堆数组
maxHeapCount 最大堆中元素的个数
******************/
void maxHeapSort(int * maxHeap, const int maxHeapCount);

/******************
根据指定的长度初始化输入的int数组
bigData:    输入的int数组
arrayLength: 数组长度
******************/
void initBigDataArray(int * bigData, const int arrayLength);

void main()
{
const int M = 1000;
const int K = 5;
int bigDataM[M];
int maxHeap[K];

initBigDataArray(bigDataM, M);
createMaxHeap(bigDataM, maxHeap, K);

for(int step = K; step < M; ++step)
{
if(bigDataM[step] < maxHeap[0])
{
maxHeap[0] = bigDataM[step];
heapifyMaxHeap(maxHeap, 1, K);
}
}

maxHeapSort(maxHeap, K);

cout<<"bigData array is: ";
for(int step = 0; step < M; ++step)
{
cout<<bigDataM[step]<<" ";
}
cout<<endl;

cout<<"Output maxHeap from less to larger: ";
for(int step = 0; step < K; ++step)
{
cout<<maxHeap[step]<<" ";
}
cout<<endl;

cout<<"Output maxHeap from larger to less: ";
for(int step = 0; step < K; ++step)
{
cout<<maxHeap[K - 1 - step]<<" ";
}
cout<<endl;

return;
}

void heapifyMaxHeap(int * maxHeap, const int pos, const int maxHeapCount)
{
int left = 2 * pos;
int right = 2 * pos + 1;
int largestElemPos = 0;
if(left <= maxHeapCount && maxHeap[left - 1] > maxHeap[pos - 1])
largestElemPos = left;
else
largestElemPos = pos;

if(right <= maxHeapCount && maxHeap[right - 1] > maxHeap[largestElemPos - 1])
largestElemPos = right;

if(largestElemPos != pos)
{
swap(maxHeap[pos - 1], maxHeap[largestElemPos - 1]);
heapifyMaxHeap(maxHeap, largestElemPos, maxHeapCount);
}

}

void createMaxHeap(const int * input, int * maxHeap, const int maxHeapCount)
{
for(int step = 0; step < maxHeapCount; ++step)
{
maxHeap[step] = input[step];
}

for(int startHeapifyPos = maxHeapCount/2; startHeapifyPos >= 1; --startHeapifyPos)
{
heapifyMaxHeap(maxHeap, startHeapifyPos, maxHeapCount);
}
}

void initBigDataArray(int * bigData, const int arrayLength)
{
for(int i = 0; i< arrayLength; ++i)
{
bigData[i] = rand();
}
}

void maxHeapSort(int * maxHeap, const int maxHeapCount)
{
int maxHeapSize = maxHeapCount;
for(int step = maxHeapSize; step >=2; --step)
{
swap(maxHeap[step - 1], maxHeap[0]);
maxHeapSize -=1;
heapifyMaxHeap(maxHeap, 1 , maxHeapSize);
}
}


如有任何错误或者不足,欢迎不吝指出。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: