堆排序(大小根堆实现)

蓝咒 提交于 2020-02-05 21:24:18

堆排序

堆排序的基本思想:

  1. 对于一组待排序数据,首先按堆的定义建立初始堆(大根堆或小根堆);
  2. 取出堆顶元素(最大或最小),将剩余的元素继续调整成新堆,就得到次大或次小元素;
  3. 反复执行 1、2 ,直到全部元素排序成顺序或逆序,堆排序结束

堆的定义

对于 n 个元素的序列 {K1, K2, …, Kn},当且仅当满足下列关系时称为堆,其中 2i 和 2i +1应不大于 n
堆
其中,1 <= i <= n/2
当任意 K[i] 都小于 K[2i] 和 K[2i + 1] 时,为小根堆
当任意 K[i] 都大于 K[2i] 和 K[2i + 1] 时,为大根堆

堆排序

  堆排序是一种树形选择排序,可以将待排序数组看成是一个完全二叉树,则由堆的定义表明,该完全二叉树中,所有非叶子节点的值都不大于(或不小于)其左、右孩子节点的值。
  因此,在一个堆中,堆顶元素(二叉树根节点)必定为该序列中的最大(或最小)元素。
  所以堆排序就是,先构造堆,取堆顶元素,再构造新堆,重复这一过程,直到排序完成
假设待排序数组为:N = {55, 60, 40, 10, 80, 65, 15, 5, 75}; 结构如下:
排序数组

构造大根堆

构造大根堆,要使得该二叉树中所有非叶子节点的值都大于其左右节点,及使节点 1、2、3、4 的值都大于左右孩子节点。
初始化大根堆过程示意图:
构造大根堆

/*
	N 为待排序数组, target 为需要调整的非叶子节点
	n 为节点个数
*/
void AdjustMaxHeap(int N[], int target, int n) {
	int i = target;
	int j = 2 * i + 1;
	int temp = N[i];
	while(j <= n) {
		if(j < n && N[j] < N[j + 1]) {	// 找出左右孩子的最大值
			j++;
		}
		if(temp < N[j]) {	// 不满足大根堆则交换元素值
			N[i] = N[j];
			i = j;
			j = 2 * j + 1;
		}
		else {
			break;
		}
	}
	N[i] = temp;
}
构造小根堆

构造小根堆,要使得该二叉树中所有非叶子节点的值都小于其左右节点,及使节点 1、2、3、4 的值都小于左右孩子节点。

void AdjustMinHeap(int N[], int target, int n) {
	int i = target;
	int j = 2 * i + 1;
	int temp = N[i];
	while(j <= n) {
		if(j < n && N[j] > N[j + 1]) {	// 找出左右孩子的最小值
			j++;
		}
		if(temp > N[j]) {	// 不满足小根堆则交换元素值
			N[i] = N[j];
			i = j;
			j = 2 * j + 1;
		}
		else {
			break;
		}
	}
	N[i] = temp;
}
实现堆排序

取堆顶元素,调整新堆过程示意图:
调整新堆

void HeapSort(int N[], int n) {
	int i;
	// 构造大根堆,元素从 0 开始
	for(i = n/2 - 1; i >=0; i--) {
		AdjustMaxHeap(N, i, n - 1);
	}
	int temp;
	// 取堆顶元素,重新构造新堆
	for(i = n - 1; i > 0; i--) {
		temp = N[0];
		N[0] = N[i];
		N[i] = temp;
		AdjustMaxHeap(N, 0, i - 1);
	}
}
测试代码
void test() {
    int N[] = {55, 60, 40, 10, 80, 65, 15, 5, 75};
    HeapSort(N, 9);
    int i;
    for(i = 0; i < len; i++) {
        printf("%d ", N[i]);
    }
    printf("\n");
}

测试结果:

E:\C_demo>heapsort.exe
5 10 15 40 55 60 65 75 80

算法复杂度

  • 空间复杂度:堆排序只需一个记录大小的辅助空间,为 O(1)
  • 时间复杂度:堆排序的算法时间由建立初始化堆和不断调整堆这两部分时间构成,为O(nlogn)
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!