排序--堆排序

发布于:2025-03-25 ⋅ 阅读:(32) ⋅ 点赞:(0)

一,引言

堆排序作为一种不局限于数组的排序,在实践中有这非同寻常的意义,为此学好堆排序的底层原理和代码实现是非常重要的,下面从向上调整算法,向下调整算法,堆排序,时间复杂度,空间复杂度和稳定性等方面进行分析:
 

二,向下调整算法--假设建小堆

1,函数原型:

void HeapSort(int* p, int bit, int tail);


第一个参数数组地址,第二个参数数组个数,第三个参数父亲节点的位置。

2,代码逻辑:
下面看一下随机的一组数据:

该数组以完成二叉树的形式展示如图:

首先第一步找一个非叶子节点(9)做为一个子树进行排序;

 父亲节点和孩子节点进行比较,首先判断有没有右孩子节点,若存在右孩子节点,进行左右孩子进行比较取小值,取较小值与父亲节点进行比较,若该节点小于父亲节点进行交换。第一轮排序结束。其结果保证该子树单独为堆。

第二趟排序:
选择前一个节点进行第二次排序如图:

因为父亲节点小于两个孩子节点所以不需要进行交换。
 

此时该二叉树如图:


再选择前一个节点4,进行相同排序第一趟如图:

此时孩子节点下方还有节点还需要继续进行比较,交换后的4变成新的父亲节点,与下方的孩子节点进行比较,结果如图:

每次比较的方法个第二步都相同,直到孩子节点为最后一个节点则比较结束。

总结:为此看函数模型的第二个参数根据数据个数可以得出最后一个节点,第三个参数传入父亲节点,通过函数循环依次的调取每一个非叶子节点(9--2--1)根据函数节点个数判断结束条件。

代码实现:

void HeapSort(int* p, int bit, int  tail)
{
	assert(p);
	int parent = tail;
	int child = parent * 2 + 1;

	while (child < bit)
	{
		if (child + 1 < bit)
		{
			if (p[child] > p[child + 1])
			{
				child++;
			}
		}
		if (p[child] < p[parent])
		{
			swap(&p[child], &p[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

三,堆排序

推排序就是首先通过建堆算法对一个数组进行建堆,之后通过第一个数据和最后一个数据进行交换,之后通过向下调整算法,重新构成一次次小的堆,依次往复最终使得该数组变成有序。

代码实现如下:

int main()
{
	int arr[] = { 4,2,9,8,7,13,1};
	int a = (6 - 1) / 2;
	for (int i = a; i >= 0; i--)
	{
		HeapSort(arr, 7, i);
	}
	for (int j = 6; j > 0; j--)
	{
		swap(&arr[0], &arr[j]);
		HeapSort(arr, j, 0);

	}

	return 0;
}

第一个for循环进行建堆算法,这个方法有很多,具体可以参考数据结构---堆中有讲解。第二个for循环进行排序。这里需要注意小堆是降序,大堆是升序。

四,时间复杂度:


这里的时间复杂度注意分析建堆和向下调整的时间复杂度具体·如图:

 

 

而向下调整相当于每个节点最多进行高度次的调整。因此是N*log^N.

综上堆排序的时间复杂度为N*log^N。

五,空间复杂度

因没有开辟新的空间因此为O(1).

六,稳定性

堆排序为不稳定排序,在不断的调整相同数据会变成变换。 


网站公告

今日签到

点亮在社区的每一天
去签到