创建堆,堆排序的详细实现过程,C++完整代码
2015-08-15 13:59
507 查看
堆的基本概念不在此介绍,各位看官自行百度。由于堆的特性导致堆可以用数组进行模拟,所以堆排序其实是在数组(即堆)上进行排序的过程,在所有堆的操作中,都离不开一个操作:调整堆,该过程使堆保持堆的性质(大堆或小堆的性质)。在介绍堆排序之前必要要介绍如何创建堆,由于堆是使用数组保存的,所有我的理解是,建堆的过程就是堆化数组,即使给定的数组具有堆的性质。堆化的过程其实就是调整堆的过程,我们把调整堆的过程定义成一个单独的函数void AdjustHeap(int heap[], int root_index, int
heap_length),参数分别是代表堆的数组,要调整的堆的根节点在数组中的下标,注意是下标,建议读者自己画个图模拟调整堆的过程。第三个参数是堆的长度,在这里就让他等于数组的长度,其实可以不相等。
调整堆的过程如下:
1.根据根节点下标,确定左右子节点的下标。
2.找出根节点和左右子节点中最小值的下标,注意该过程要判断边界,即左右子节点的下标是否超出堆的长度。
3.如果最小值的下标等于根节点的下标,函数返回。
4.否则,交换把根节点与最小值交换,由于交换可能破坏了最小值所在子树的对性质,所以递归调用AdjustHeap函数。
那么现在还有一个问题,就是堆化的时候,从哪个节点开始调整堆呢?这个也是建堆的关键,我们可以这样想,子节点已经是堆了,无需在调整了,所以我们没必要从最后一个节点开始调整,一般是从(heap_length/2)开始调节,一直到下标1为止(堆的下标一般从1开始,0位置不用),从(heap_length/2)开始调节的原因是完全二叉树的性质决定的。这样遍历一遍,对每个节点调用堆调整函数就完成建堆了。
堆排序的思想比较简单,取出堆的第一个元素,调整堆,循环下去,知道取完为止。实现的过程就是先把堆顶元素和堆的最后一个元素互换,堆长度减1,再调整堆,知道堆的长度为1。这样就使堆排序的空间复杂度为O(1)了,注意的是大顶堆排完序之后数组中元素的顺序是从小到大,小顶堆是从大到小。
完整代码如下:
heap_length),参数分别是代表堆的数组,要调整的堆的根节点在数组中的下标,注意是下标,建议读者自己画个图模拟调整堆的过程。第三个参数是堆的长度,在这里就让他等于数组的长度,其实可以不相等。
调整堆的过程如下:
1.根据根节点下标,确定左右子节点的下标。
2.找出根节点和左右子节点中最小值的下标,注意该过程要判断边界,即左右子节点的下标是否超出堆的长度。
3.如果最小值的下标等于根节点的下标,函数返回。
4.否则,交换把根节点与最小值交换,由于交换可能破坏了最小值所在子树的对性质,所以递归调用AdjustHeap函数。
那么现在还有一个问题,就是堆化的时候,从哪个节点开始调整堆呢?这个也是建堆的关键,我们可以这样想,子节点已经是堆了,无需在调整了,所以我们没必要从最后一个节点开始调整,一般是从(heap_length/2)开始调节,一直到下标1为止(堆的下标一般从1开始,0位置不用),从(heap_length/2)开始调节的原因是完全二叉树的性质决定的。这样遍历一遍,对每个节点调用堆调整函数就完成建堆了。
堆排序的思想比较简单,取出堆的第一个元素,调整堆,循环下去,知道取完为止。实现的过程就是先把堆顶元素和堆的最后一个元素互换,堆长度减1,再调整堆,知道堆的长度为1。这样就使堆排序的空间复杂度为O(1)了,注意的是大顶堆排完序之后数组中元素的顺序是从小到大,小顶堆是从大到小。
完整代码如下:
#include <iostream> #define Max 11 int heap[Max]; void AdjustHeap(int heap[], int root_index, int heap_length) //调整堆,这里是最小堆 { int left_child_index = root_index * 2; int right_child_index = left_child_index + 1; int min_index = root_index; if (left_child_index < heap_length && right_child_index < heap_length) { if (heap[left_child_index] < heap[root_index]) { if (heap[left_child_index] < heap[right_child_index]) min_index = left_child_index; else min_index = right_child_index; } else { if (heap[right_child_index] < heap[root_index]) min_index = right_child_index; else min_index = root_index; } } if (left_child_index < heap_length && right_child_index >= heap_length) //这种情况是左子节点是最后一个元素的情况 { if (heap[left_child_index] < heap[root_index]) min_index = left_child_index; else min_index = root_index; } if (min_index != root_index) { int t = heap[root_index]; heap[root_index] = heap[min_index]; heap[min_index] = t; AdjustHeap(heap,min_index,heap_length); } return; } void CreateHeap(int heap[], int heap_length) //建堆 { for (int i = (heap_length / 2); i >= 1; --i) AdjustHeap(heap, i, heap_length); } int main() { heap[0] = -1; for (int i = 1; i != Max; ++i)//输入数组 std::cin >> heap[i]; CreateHeap(heap, Max); //建堆,即堆化 for (int i = 0; i != Max; ++i) std::cout << heap[i] << " "; std::cout << std::endl; //堆建好的堆进行排序 int t = Max; while (t != 1) { int tmp = heap[t - 1]; heap[t - 1] = heap[1]; heap[1] = tmp; AdjustHeap(heap, 1, t-1); --t; } for (int i = Max - 1; i != 0; --i) std::cout << heap[i] << " "; std::cout << std::endl; }