八大排序(二)

<>堆排序

堆排序

基本思路:

  1. 建立一个堆
  2. 将堆顶元素与最后一个元素交换
  3. 交换后堆元素减一,重新调整堆

大堆:

八大排序(二)_第1张图片 

它在数组中的物理结构存储是 

八大排序(二)_第2张图片

关键的地方来了:

将堆顶元素70与最后一个元素10交换,交换后最后一个位置就不变了,因为它就是这个数组中的最大值,再将剩下的数组元素重新变成大堆。

八大排序(二)_第3张图片

 这一次循环过后,我们就把数组中最大值放到最后一个位置,下一次循环把倒数第二大值,放在倒数第二个位置,以此类推直到将数组变成有序的。

建小堆也是一样:

向下调整算法-前提:当前树的左右子树必须都是一个小堆
向下调整算法的核心思想:选出左右孩子中小的哪一个,跟父亲交换,小的往上浮,大的往下沉,建大堆则相反

八大排序(二)_第4张图片

堆向下调整算法(建小堆)实现 

//堆向下调整算法
//建小堆
void AdjustDown(int* a, int n, int root)
{
	int parent = root;
	int child = parent * 2 + 1;
	//孩子超过数组下标结束
	while (child < n)
	{
		//child始终左右孩子中小的那个
		if (a[child + 1] < a[child] && child + 1 parent则已满足小堆,直接break
		else
		{
			break;
		}
	}
}

堆的向上调整算法

使用场景:向堆中插入数据,需要使用向上调整算法调整,因为向堆中插入数据是将数据插入到下标为size的位置,此时就不满足小堆(大堆),因此,需要堆其进行调整,向上调整算法和向下调整算法思路类似,此处以小堆为例,向上调整法只需从插入的节点位置开始和父节点比较,若a[chaild]=a[parent]则说明越界满足小堆,直接break

如下图所示插入一个数据使用向上调整法调整

八大排序(二)_第5张图片

 向上调整算法(建小堆)实现

//堆的向上调整算法
//建小堆
void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			int tem = a[parent];
			a[parent] = a[child];
			a[child] = tem;
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

堆排序(降序)

下面我们将上面建好的小堆进行降序排序

堆排序(降序)的核心思想:因为建小堆可以选出最小的数即根节点,我们将每次建好的小堆的最后一个叶子节点和根节点进行交换,交换后不把最后一个数看作堆里的数据,此时根的左右子树依旧是大堆,然后我们再用向下调整算法选出次小的如此循环直到堆里剩一个数结束

• 升序建大堆
• 降序建小堆

堆排序(降序)实现 

//降序
void HeapSort(int* a, int n)
{
	//建小堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	}
	int end = n - 1;
	//把最小的换到最后一个位置,不把最后一个数看作堆里的
	//每次选出剩下数中最小的
	//从后往前放
	while (end > 0)
	{
		int tem = a[end];
		a[end] = a[0];
		a[0] = tem;
		//选出次小的数
		AdjustDown(a, end, 0);
		--end;
	}
}

 建堆的时间复杂度

八大排序(二)_第6张图片

 由以上推论过程可得建堆的时间复杂度为O(N);
向下调整算法的时间复杂度为O(log2N);
所以堆排序的时间复杂度为O(N*log2N);

你可能感兴趣的:(八大排序,java,开发语言)