(3)详解桶排序及排序大总结(C语言数据结构及算法)

一、堆的重要操作

(1)向大根堆形态的完全二叉树中添加一个数到树的末尾,通过向上调整该数的位置,使得二叉树保持大根堆的形态。

//交换数组两元素位置
void swap(int* arr, int i, int j)
{
	int tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}

//某个数在index位置,往上继续移动
void heapInsert(int* arr, int index)
{
	//当该数比它的父亲大时,可以向上移动
	while (arr[index] > arr[(index - 1) / 2])
	{
		swap(arr, index, (index - 1) / 2);
		index = (index - 1) / 2;
	}
}

(2)从大根堆形态的完全二叉树中移除一个数,并将大根堆末尾的数移动到空出的位置补充,通过向下调整补充数的位置,使得二叉树保持大根堆的形态。

//某个数在index位置,能否向下移动(将堆顶数移走,重新构建堆)
void heapify(int* arr, int index, int heapSize)
{
	int left = index * 2 + 1;//左孩子的下标
	while (left < heapSize)//当左孩子存在的时候
	{
		//两个孩子中,谁的值大,把下标给largest
		int largest = left + 1 < heapSize && arr[left + 1] > arr[left] ? left + 1 : left;
		//父亲和较大的孩子之间,谁的值大,把下标给largest
		largest = arr[largest] > arr[index] ? largest : index;
		if (largest == index)
			break;
		//否则交换堆顶index的值和孩子largest的值
		swap(arr, largest, index);
		index = largest;
		left = index * 2 + 1;
	}
}

(3)时间复杂度

上面两段代码的时间复杂度都是O(logN)


二、堆排序

(1)思路

1.把无序数组构成大根堆(heapInsert函数),此时最大值被放在堆顶位置。

2.将堆顶数与堆底数(完全二叉树中最后面的数)交换位置,最大数被放在队尾并移出堆结构。

3.将得到的新堆重新构成大根堆(heapify函数),第二大的数被放在堆顶位置。

4.将堆顶数与堆底数(完全二叉树中最后面的数)交换位置,第二大的数被移出堆结构。

5.重复上述操作,直到所有数都被移出堆。

(2)代码实现

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>

//交换数组两元素位置
void swap(int* arr, int i, int j)
{
	int tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}

//某个数在index位置,往上继续移动
void heapInsert(int* arr, int index)
{
	//当该数比它的父亲大时,可以向上移动
	while (arr[index] > arr[(index - 1) / 2])
	{
		swap(arr, index, (index - 1) / 2);
		index = (index - 1) / 2;
	}
}

//某个数在index位置,能否向下移动(将堆顶数移走,重新构建堆)
void heapify(int* arr, int index, int heapSize)
{
	int left = index * 2 + 1;//左孩子的下标
	while (left < heapSize)//当左孩子存在的时候
	{
		//两个孩子中,谁的值大,把下标给largest
		int largest = left + 1 < heapSize && arr[left + 1] > arr[left] ? left + 1 : left;
		//父亲和较大的孩子之间,谁的值大,把下标给largest
		largest = arr[largest] > arr[index] ? largest : index;
		if (largest == index)
			break;
		//否则交换堆顶index的值和孩子largest的值
		swap(arr, largest, index);
		index = largest;
		left = index * 2 + 1;
	}
}

//堆排序
void heapSort(int* arr, int len)
{
	if (arr == NULL || len < 2)
		return;
	for (int i = 0; i < len; i++)
	{
		heapInsert(arr, i);//使数组构成大根堆
	}
	int heapSize = len;
	swap(arr, 0, --heapSize);
	while (heapSize > 0)
	{
		heapify(arr, 0, heapSize);
		swap(arr, 0, --heapSize);
	}
}

int main()
{
	int arr[] = { 2,5,3,6,4,1 };
	int len = sizeof(arr) / sizeof(arr[0]);
	heapSort(arr, len);
	for (int k = 0; k < len; k++)
		printf("%d ", arr[k]);
}

(3)时间复杂度和空间复杂度

时间复杂度为O(NlogN),上面两个重要操作的时间复杂度为O(logN),共执行N次。

额外空间复杂度为O(1)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值