介绍
堆排序是一种常见的排序算法。 堆排序的思路是先将待排序数组建成一个堆(可以是最大堆或最小堆),然后取出堆顶元素(也就是堆中最大或最小的元素),将其放在最终的输出数组中,再将剩余的待排序数组重新建成堆,重复该操作直到所有元素都被输出,最终就得到了一个有序的数组。本文主要介绍使用最小堆进行降序的堆排序。
算法思路
使用最小堆进行降序的堆排序,与使用最大堆进行升序的堆排序类似。 下面给出算法的实现过程:
1. 建立最小堆
对于待排序数组a,我们首先需要建立一个最小堆。使用最小堆可以保证每次取出堆顶元素的时候,得到的都是堆中最小的元素。建立最小堆的过程可以使用下沉操作。
下沉操作的算法思路是:首先将要下沉的元素设为当前节点,然后将当前节点的左右子节点中较小的那个和当前节点比较,如果当前节点比较小,那么下沉操作结束;否则将当前节点和较小的子节点交换位置,接着以新的位置继续进行下沉操作,直到当前节点比两个子节点都小,或者已经到达叶子节点为止。
具体实现代码如下:
void shift_down(int arr[], int start, int end){
int root = start;
while (root * 2 + 1 <= end) {
int child = root * 2 + 1;
if (child + 1 <= end && arr[child] > arr[child + 1])
child++;
if (arr[root] > arr[child]) {
swap(arr[root], arr[child]);
root = child;
}
else
return;
}
}
上述代码中,变量start表示当前节点的下标,end表示堆的结束下标,也就是堆中最后一个元素的下标。函数的执行过程是,首先将当前节点设为根节点,然后进入while循环。在while循环中,首先计算出当前节点的左子节点的下标,即child=root*2+1,同时检查right节点的下标是否超过了堆的长度并且right节点是否比left节点小,如果是,取right节点进行比较。如果当前节点比两个子节点都小,那么该节点已经到达了最终位置,可以结束函数;否则将当前节点和较小的子节点进行交换,接着以新的位置继续进行下沉操作,直到当前节点比两个子节点都小,或者已经到达叶子节点为止。
建立最小堆的过程可以使用shift_down函数进行。
2. 取出堆顶元素
建立好最小堆之后,我们可以开始取出堆顶元素,也就是最小的元素。在本算法中,由于我们需要将数组按照降序排序,因此需要取出最小的元素。取出堆顶元素的算法代码如下:
int extract_min(int arr[], int& len) {
int min_val = arr[0];
arr[0] = arr[len - 1];
len--;
shift_down(arr, 0, len - 1);
return min_val;
}
上述代码中,变量len表示当前堆的长度。函数的执行过程是,首先将数组中的第一个元素(也就是堆顶元素)保存到变量min_val中,接着将数组中最后一个元素放到数组第一个位置,同时将数组长度减1,然后从第一个位置(也就是新的堆顶位置)开始进行下沉操作。下沉操作的结束位置是数组的新长度len减1(因为数组中除了堆顶元素之外的其他元素都已经是有序的了)。取出堆顶元素以后,我们就可以将其插入到有序数组的末尾,即arr[len-i-1]的位置,其中变量i表示已经排好序的元素个数。插入操作的代码如下:
void insert_into_array(int arr[], int min_val, int pos) {
arr[pos] = min_val;
}
3. 重复上述步骤
上述步骤完成后,我们需要重复执行步骤1和步骤2,直到所有元素都被排好序为止。具体来说,我们需要在一个循环内多次执行extract_min函数,并将取出来的元素插入到有序数组的末尾,直到堆中没有元素为止。循环的代码如下:
void heap_sort_descend(int arr[], int len) {
for (int i = 0; i < len; i++) {
int min_val = extract_min(arr, len);
insert_into_array(arr, min_val, len - i - 1);
}
}
测试
下面是一个测试例子,可以测试算法的正确性:
int main() {
int arr[] = { 3, 7, 1, 2, 8, 5, 9, 4, 6, 0 };
int len = sizeof(arr) / sizeof(int);
heap_sort_descend(arr, len);
for (int i = 0; i < len; i++)
cout << arr[i] << " ";
cout << endl;
return 0;
}
测试结果如下:
9 8 7 6 5 4 3 2 1 0
测试结果表明,本算法可以正确地将数组进行了降序排序。
总结
本文介绍了使用最小堆进行降序的堆排序算法。算法思路可以分为以下步骤:建立最小堆,取出堆顶元素,重复上述步骤。最终得到的结果是一个有序的数组。在实际应用中,如果需要将数组按照降序排序,使用本算法可以很方便地实现。