您的位置:首页 > 其它

【每日算法】堆排序

2017-07-23 19:31 169 查看
1、堆:堆数据结构是一种数组对象。
对于表示堆的数组arr[0…n-1],我们以arr[0]为根,给定某个节点下标i,令其父节点和左右后代节点的下标为:
parent(i) = (i-1)/2;
left(i) = 2*i+1;
right(i) = 2*i+2;



堆分为最大堆和最小堆,上面就是最大堆,特点就是:除根节点以外的每个节点i,都有arr[ parent(i) ] >= arr[i]。最小堆的特点则是:除根节点以外的每个节点i,都有arr[ parent(i) ] <= arr[i]。
堆排序一般使用最大堆,最大堆中的最大元素位于根节点。
因为具有n个元素的堆是基于一颗完全二叉树的,所以其高度为O(log n)。
2、如何保持堆中的性质:

首先,我们假定以节点i的左右儿子为根的两棵二叉树都是最大堆,而以节点i为根的二叉树可能不是最大堆,则调整的过程如下:
从元素arr[i], arr[left(i)], arr[right(i)]中找出最大的元素,将下标存在largest中;
如果arr[i]是最大的,说明以节点i为根的二叉树是最大堆,无须调整,程序结束;否则,交换arr[i]和arr[largest],于是arr[i], arr[left(i)], arr[right(i)]三者满足了最大堆的性质,但是交换后,下标为largest的节点存放arr[i]的值,以该节点为根的子树又可能违反最大堆的性质,因此需要对该子树递归调用本调整过程
代码:
//arr[0...size-1]
void maxHeapify(int arr[], int i, int size)
{
int l = left(i);
int r = right(i);
int largest = i;
if (l < size && arr[l] > arr[largest])
largest = l;
if (r < size && arr[r] > arr[largest])
largest = r;
if (largest != i)
{
exchange(arr[i], arr[largest]);
maxHeapify(arr, largest, size);
}
}


3、建堆:

上面保持堆的性质是一个铺垫,它也是堆算法中的核心部分,后面我们将利用它完成建堆和堆排序。
我们先看看如何使用maxHeapify()来将一个数组arr[0…size-1]变成一个最大堆。
对于每一片树叶,我们都可以看作是一个只含一个元素的堆。于是对于叶子节点的父亲节点(左右子树都是最大堆),我们可以调用maxHeapify()来进行调整。调整之后,我们得到更大的堆,对于这些堆的父节点,我们又可以调用maxHeapify()来进行调整。
为保证maxHeapify()的调用前提,我们只需从最下面的非叶子节点开始调整,一直到根节点,整个堆建立完毕。
那么,最下面的非叶子节点的下标是多少?
在这里我只给出结论,有兴趣的读者可以尝试证明一下:
当用数组表示存储了n个元素的堆时,叶子节点的下标为:n/2, n/2+1, … , n-1。 (n/2表示向下取整)
于是我们的调整顺序为n/2-1, … , 0:
代码:
buildMaxHeap(int arr[], int size)
{
for (int i = size/2-1; i >= 0; --i)
maxHeapify(arr, i, size);
}

4、堆排序:

为进行原地排序,我们引入另一个变量:heap_size,它用来表示堆的大小,而用size来表示数组的大小。
于是数组arr[0…size-1]中,arr[0…heap_size-1]为堆,arr[heap_size, size-1]为排好序的元素。
由最大堆的性质可知道,arr[0]存放着堆中最大的元素,于是可以利用该性质如下排序:
初始heap_size = size,调用buildMaxHeap(arr, heap_size)建立最大堆;
令i = size-1,交换arr[0]和arr[i],heap_size–,i–;
交换后,原来根的子女仍是最大堆,而根元素则可能违背了最大堆的性质,所以调用maxHeapify(arr, 0, heap_size)进行调整;
重复以上过程,直到堆的大小变为2,此时再重复一次以上过程,整个数组便从小到大排好序了。

代码:
void heapSort(int arr[], int size)
{
if (NULL == arr || size <= 0)
return ;
int heap_size = size;
buildMaxHeap(arr, heap_size);
for (int i = size-1; i >= 1; --i)
{
exchange(arr[0], arr[i]);
--heap_size;
maxHeapify(arr, 0, heap_size);
}
}

堆排序(heapsort)的时间复杂度为O(n logn),不稳定。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: