快速排序&堆排序

本文详细介绍了两种经典的排序算法——快速排序和堆排序。快速排序通过递归地将数组分成两部分并排序来实现高效排序,而堆排序则利用堆这种特殊的数据结构进行排序。文章还探讨了两种算法的具体实现细节、时间复杂度、稳定性及优化方法。
摘要由CSDN通过智能技术生成

快速排序

测试用例: 5 2 1 6 4 7 9 0 8 3

  • 思路:采用的分治算法,结合递归。

    1.选择一个基准值,把数组中比基准值大的数据放到基准值的右边,把比基准值小的元素放到左边。(这时,基准值被放在了正确的位置)
    2.对基准值左边的数组和右边的数组不但进行步骤1。
    3.递归的结束条件是小区间内没有数据或者数据只有一个。即 left>right 或者 left == right

  • 时间复杂度:
    平均:O(nlogN) 每次把一个基准值放到最终合适的位置,时间复杂度是longN,一共有n个元素
    最坏:O(n^2)

  • 稳定性:不稳定

    优化版本:对于快速排序来说,在数组有序时,时间复杂度最高,可以通过基准值的选取来优化。
    可以采用随机数法,使得基准值为数组中的任意可能位置;
    但是最常用的还是三数取中法,在数组的首,尾和中间处取三个值,选择三个数第二大的数作为基准值。

int GetLocation(int arr[], int left, int right)
{
	//如何将基准值方法合适的地方(也就是将区间划分成 小于基准值,大于基准值,和基准值 三个区间)
	//方法:从前往后找比基准值大的数据,从后往前找比基准值小的元素,交换这两个数据,
	        //如果是左边的数为基准值,先让右边的数向左移动找比基准值小的,
	       //最后有一步要交换基准值和从右往左走的停下来的位置上的数据
	int begin = left;
	int end = right;
	int pivot = arr[left];
	while (begin < end)
	{
		while (begin < end && arr[end] > pivot)
			end--;
		while (begin < end && arr[begin] <= pivot)
			begin++;

		Swap(&arr[begin],&arr[end]);
	}
	//交换的是数组中的内容,而不是随便一个变量和数组中的数据
	Swap(&arr[left], &arr[end]);
	return end;
}

void QuickSort(int arr[], int left, int right)
{
	if (left >= right)
		return;
	int pivotIndex = GetLocation(arr, left, right);
	QuickSort(arr, left, pivotIndex-1);
	QuickSort(arr, pivotIndex + 1, right);
	return;
}

堆排序

例子:5 2 1 6 4 7 9 0 8 3

首先明确什么是堆: 堆是一种逻辑上是树形结构,但是实际上是数组线性结构的一种数据结构。
                   堆的性质:大堆的每个节点要比自己的孩子节点大或相等。
  • 思路: 堆排序首先是要建堆, 升序,需要建大堆,
    但是建立一次大堆只能找到一个最大的数,所以要对n个数据 进行排序就需要建n次堆,
    每建好一次堆,就让和最后一个数据交换,然后在缩小数据规模。

步骤
1.创建大堆
2.交换大堆第一个元素和最后一个元素
3.每次对这个建好的对进行向下调整,也就是对arr[0]元素进行向下调整

  • 时间复杂度:
    平均:O(nlog(n)) 每次向下调整只能确定一个最大的值,然后和数组末尾元素交换,
    因此是n,向下调整的时间复杂度是logn,综合结果就是O(nlog(n))
  • 空间复杂度:
    O(1) 没有额外空间开销
  • 稳定性:不稳定
void AdjustDown(int tree[], int size, int parentIndex)
{
	int leftIndex = parentIndex * 2 + 1;
	int rightIndex = parentIndex * 2 + 2;

	//先判断有没有右孩子
	if (leftIndex >= size)
	{
		return;
	}

	int maxIndex = leftIndex;  //假设左右孩子中,左孩子是较大值
	if (rightIndex < size && tree[rightIndex] > tree[leftIndex])
 //如果想要比较左孩子和右孩子的大小,必须确保右孩子存在,并且要先判断右孩子是否存在
		maxIndex = rightIndex;

	//比较根  与 左右孩子中较大的值的大小
	if (tree[parentIndex] > tree[maxIndex])
		return;
	else
	{
		//交换根和 孩子节点中较大的值
		Swap(tree + parentIndex, tree + maxIndex);

		//为了保证堆的性质不被破坏,所以要对更换后的位置继续调整
		AdjustDown(tree, size, maxIndex);
	}
}

void CreateBigHeap(int arr[], int size)
{
	for (int i = (size - 2)/2; i >= 0; i--)
	{
		AdjustDown(arr,size,i);
	}
}

void HeapSort(int arr[], int size)
{
	//从最后一个非叶子节点开始,逐渐往前面进行向下调整,建立大堆,
	//全部调整只能找到最大值
	CreateBigHeap(arr, size);

	for (int i = 0; i < size; i++)
	{
		Swap(arr+0, arr+size-1-i);
		AdjustDown(arr,size-i-1, 0);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值