堆排序—C语言

堆排序(堆排序)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。利用可以数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。

根大堆的英文堆的两种形式之一。根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆,又称最大堆(大顶堆) 。

大根堆要求根节点的关键字既大于或等于左子树的关键字值,又大于或等于右子树的关键字值。

大根堆排序算法的基本操作:

  1. 建堆,建堆是不断调整堆的过程,从LEN / 2处开始调整,一直到第一个节点,此处LEN是堆中元素的个数。建堆的过程是线性的过程,从LEN / 2到0处一直调用调整堆的过程,相当于o(h1)+ o(h2)... + o(hlen / 2)其中h表示节点的深度,len / 2表示节点的个数,这是一个求和的过程,结果是线性的O(N)。
  2. 调整堆:调整堆在构建堆的过程中会用到,而且在堆排序过程中也会用到利用的思想是比较节点我和它的孩子节点左(我),右(I),选出三者最大(或者最小)者,如果最大(小)值不是节点我而是它的一个孩子节点,那边交互节点我和该节点,然后再调用调整堆过程,这是一个递归的过程调整。堆的过程时间复杂度与堆的深度有关系,是LGN的操作,因为是沿着深度方向进行调整的。
  3. 堆排序:。堆排序是利用上面的两个过程来进行的首先是根据元素构建堆然后将堆的根节点取出(一般是与最后一个节点进行交换),将前面LEN-1个节点继续进行堆调整的过程,然后再将根节点取出,这样一直到所有节点都取出堆排序过程的时间复杂度是O(nlgn)因为建堆的时间复杂度是O(N)(调用一次)。;调整堆的时间复杂度是LGN,调用了n-1个次,所以堆排序的时间复杂度是O(nlgn)

给出一串待排序的数字: 4     6     8     5     9

void Adjust(int *arr,int start,int end)
{
	int tmp = arr[start];
	for(int i = 2*start+1;i <= end; i = 2*i+1)
	{
		//是否有右孩子
		if((i < end) && arr[i] < arr[i+1])
		{
			i++;
		}
		//i肯定是当前孩子的最大值的下标
		if(arr[i] > tmp)
		{
			arr[start] = arr[i];
			start = i;
		}
		else
		{
			break;
		}
	}
	arr[start] = tmp;
}
void HeapSort(int *arr,int len)
{
	int i = 0;
	for(i = (len-1-1)/2;i >= 0;i--)
	{
		Adjust(arr,i,len-1);
	}
	//肯定是大根堆
	//先交换,后调整(只需要调整0号下标这棵树)
	for(i = 0;i < len-1;i++)
	{
		int tmp = arr[0];
		arr[0] = arr[len-1-i];
		arr[len-1-i] = tmp;
		Adjust(arr,0,len-1-i-1);
	}

}
void Show(int *arr,int len)
{
	for(int i = 0;i  < len;i++) 
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[] = {1,32,0,76,45,2,7,9,4,5};
	int len = sizeof(arr)/sizeof(arr[0]);
	HeapSort(arr,len);
	Show(arr,len);
	return 0;
}
发布了35 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41078889/article/details/84329641