关于快速排序的一些理解

#include<iostream>
#include<ctime>
using namespace std;
/*
*快速排序
​ *1、所选问题描述:给定一个无序数组序列,将其按降序排列
            例如输入【10, 43, 52, 6, 8, 2, 23, 1, 67, 89, 90, 27】,输出【90 89 67 52 43 27 23 10 8 6 2 1*2、算法思想
            把n个元素划分为三段:左端Left,中间段middle和右端right。中段仅有一个元素。左端的元素都不大于中间段的元素,
            右端的元素都不小于中间段的元素。因此可以对lefe和right对立排序,所以,快速排序是一种分治思想,把大问题分
            为了若干个小问题。middle的元素称为支点或分割元素。
        举例
            考察元素【48371562】。假设选择元素6作为支点。因此6属于middle;43152属于left,87属于right。
            left排序结果为12345;right排序为78。把右端的元素放在支点之后,左端left元素放在支点之前,即可得到有序序列。
*3实现步骤
            1、指定一个支点
                注意,是“指定”,并没有明确的约束条件,也就是说这个支点是任意一个元素,一般我们选择两种支点:当前序列首元,或者随机选取
                两种方式各有优劣,前者胜在简单,但可能影响算法效率
                快排中,支点的最终位置越靠近中间位置效率越高,读起来可能有点怪怪的,注意支点是一个值(具体元素),而不是字面意思的位置,
                当支点在最终序列中的位置靠前或者靠后时算法效率都不高(类似于“最坏情况”)。
                因此,后者在一定程度上减少了最坏情况的发生次数,但随机选取需要耗费额外的时间
                所以在具体应用中一般采用第一种方式来指定“支点”,也就是直接把当前序列的首元作为“支点”。

            2、进行一趟快排
                快排中,一趟操作的最终目的是把“支点”放到它应该去的地方,同时,支点左边的元素都小于支点,右边的元素都大于支点,举个例子,
                已知序列{7, -1, 5, 23, 100, 101},那么第一趟快排的结果是{_, _, 7, _, _, _},可以看到,首元(支点)已经去了它该去的地方

            3、对子序列进行快排。
                第二步我们已经成功用支点将序列分成了3个部分,left,middle right,这三个部分总体是有序的,但是每个元素内部确实无序的,
                因此我们需要让这3个部分的内部也有序,对left和right继续使用快速排序就好(递归思想)。

*效率分析
            1、快速排序算法的平均时间复杂度为O(nlogn)2、具体到实际的快速排序操作,它的时间复杂度与基准元素的选取有关。如果每趟排序都将大部分元素划分到基准元素的一侧,那么快速排序将退化为冒泡排序,
            时间复杂度为O(n^2);一种更为特殊的情形就是序列初始化状态按关键字排序,而每趟排序选取的基准元素为当前子序列中的第一个元素,这种情况下快速排序
            相当于冒泡排序,时间复杂度为O(n^2)3、快速排序算法相比于其他排序算法来说比较耗费空间资源,因为快速排序需要栈空间来实现递归。如果每趟排序都将序列均匀划分成长度相近的两个子序列,
            则栈的最大深度为[log2n]+1。但是如果每趟排序的基准元素都偏向于子序列的一端,最坏情况下栈的深度为n。平均起来,快速排序的空间复杂度为O(logn)*/

int partition(int *array, int low, int high) {

	//二分
	int mid = low + (high - low) / 2;//创建变量存储中间数
	int temp;//创建交换数值时临时存的变量
	//快排优化  : 三数取中   即将 low mid high 中的三个数中的中间数放在low位置上 作为基准数
	//如果mid处元素大于high元素 则交换之
	if (array[mid] > array[high]) {
		temp = array[mid];
		array[mid] = array[high];
		array[high] = temp;
	}
	//如果mid处元素大于low元素 则交换之
	if (array[mid] > array[low]) {
		temp = array[mid];
		array[mid] = array[low];
		array[low] = temp;
	}
	//如果mlow处元素大于high元素 则交换之
	if (array[low] > array[high]) {
		temp = array[low];
		array[low] = array[high];
		array[high] = temp;
	}
	//得到基准值
	int key = array[low];
	//快排核心
	while (low < high) {
		//从尾端往前扫描找到一个比当前基准值大的元素
		while (array[high] <= key && high > low) high--;
		//将得到的high位置元素写入low位置
		array[low] = array[high];
		//从前端往后扫描找到一个比当前基准值小的元素
		while (array[low] >= key && low < high) low++;//比key大的放右边
		//将得到的low位置元素写入high位置
		array[high] = array[low];
	}
	//将key写入最终位置
	array[high] = key;
	return high;
}

void sort(int *array, int low, int high) {
	//递归出口
	if (low >= high) return;//当要划分为两部分前先判断能不能划分,当没办法划分时(low>=high) ,就不用划分了,该数的位置对了。
	//得到分割下标
	int index = partition(array, low, high);//完成一次单元排序
	//递归调用
	sort(array, low, index-1);//对左边单元进行排序
	sort(array, index + 1, high);//对右边单元进行排序
}


// 生成元素为随机数的数组
void Random(int a[],int n)
{
    int i=0;
    srand( (unsigned)time( NULL ) );
    while(i<n)
    {
        a[i++]=rand();
    }
}

int main()
{
	int a[30] = {0};
    Random(a,30);
    for(int i = 0; i < sizeof(a) / sizeof(a[0]); i++)//循环输出排序好的数组内容
    	cout<<a[i]<<" ";
    cout<<endl;
	//传入数组进行排序
    sort(a, 0,sizeof(a) / sizeof(a[0]) - 1);
    //打印数组进行验证
    for(int i = 0; i < sizeof(a) / sizeof(a[0]); i++)//循环输出排序好的数组内容
    	cout<<a[i]<<" ";
    cout<<endl;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浩波的笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值