【基础算法】排序-复杂排序之三(堆排序)

归并排序的平均时间复杂度为O(NlogN),但是要占用空间,因此效率上并没有提升多少。

快速排序的平均时间复杂度为O(NlogN),但是最坏的情况,时间复杂度还是会到O(N^2)。

因此能不能有一种排序,时间复杂度为O(NlogN),最坏的情况时间复杂度也是O(NlogN)呢?

利用优先级队列中二叉堆的性质,我们考虑把一串无序的序列构建成堆,然后依次把最顶上的元素放到数组的最末尾,这样数组就可以从小到大排好序了。

因此我们采取两步法来实现堆排序

第一步:建堆

建堆的目的是为了把那些父节点比子节点小的元素沉降到它的相应位置。因此我们应该从父节点的最后一位开始依次向上遍历,直到顶点为止。

定理:父节点的最后一位 i 一定是元素总数N的一半,即i=N/2。利用的就是子节点=父节点*2或子节点=父节点*2+1。

建堆的过程是让N/2个元素依次沉降到相应位置,所以时间复杂度是(N/2)*logN

		int N = array.length-1;
		// heap construction
		for (int i = N / 2; i >= 1; i--)
			sink(array, i, N);

第二步:堆排序

把最顶点和最后一位元素交换,然后将换到顶点的新元素沉降到合适位置。

时间复杂度是NlogN

		while (N > 1) {
			exchange(array, 1, N--);
			sink(array, 1, N);
		}

这样堆排序就结束了。

以下是sink函数的实现

	public static void sink(int[] array, int k, int N) {
		// N is the number of disorder elements
		while (2 * k <= N) {
			int j = 2 * k;
			if (j < N && more(array[j + 1], array[j]))
				j++;
			if (more(array[k], array[j]))
				break;
			exchange(array, j, k);
			k = j;
		}
	}

	public static boolean more(int v, int w) {
		return v > w;
	}

	public static void exchange(int[] array, int i, int j) {
		int temp = array[i];
		array[i] = array[j];
		array[j] = temp;
	}


通过堆排序,我们发现它几乎完成了时间复杂度为O(NlogN),最坏的情况时间复杂度也是O(NlogN)的效果,但是有一个问题在于这个排序依旧是一个不稳定的排序,能不能发明一个稳定的排序且有同样的效果,我们只能等待大师们的灵感了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值