算法-优化快速排序

本文探讨了如何优化快速排序算法,以确保其平均时间复杂度稳定在O(nlogn)。通过引入随机选取基准元素的策略,避免了最坏情况的发生。文章提供了C++代码实现,并详细解释了算法的核心思想、分析了其主要模块,包括数据读入、快速排序及输出。同时,分享了源代码链接供读者参考学习。
摘要由CSDN通过智能技术生成

问题概述


题目:优化快速排序

问题描述:
快速排序是一种不稳定的排序算法,时间复杂度最好情况时是Onlogn,最坏情况下是On2,因而本算法是为了优化快速排序,使其算法时间复杂度基本稳定在Onlogn

输入:
输入n个整数,用快速排序的方法进行排序;
输出:
可能有多组输入数据,对于每组输入数据,
输出多行,每一行输出一个排好序的整数(从小到大);
样例输入:
5
12
18
14
13
16
样例输出:
12
13
14
16
18


1. 问题分析

1.1 算法核心


快速排序的核心思想是分治,不断的对范围内的某一个元素进行排序要求是这个被选中的元素左侧是都比他小的元素,右侧是都比他大的元素,选中的元素排好后,将他左右两侧再分别进行相同操作的排序这样的话,排序到最后最后一个元素就会在他该在的位置这样就排好序了。
总结如下:
(1)调整序列中的元素,任意选中一个元素,使当前序列被选中的
元素在调整后满足左侧所有元素均小于该元素,右侧所有元素均大于
该元素;
(2)对该元素的左侧右侧分别进行如(1)的调整,直到当前调整区
间不超过1.


1.2 算法分析


主要包括三个模块,
第一个是读入数据模块,存储至全局数组numbers,
第二个模块是快速排序模块,利用内核调整函数partition进行区间调整,本次采用的是递归方式的快速排序,便于理解:
第三个模块是输出模块,输出调整后的数组需要注意的是,快速排序有很多种方式,最基础的方式是默认每次都选中数组最左侧的元素进行排序,但我们还可以优化!
具体优化方式如下:

可以采用生成随机数的方式选中本次递归调整的元素是哪一个,但这种方法也存在缺陷,因为随机数底层实现是生成[0, RAND_MAX]范围内的整数,而RAND_MAX这个常量是定义在<stdlib.h>这个头文件中的,因此每台计算机可能有所不同,但这个数不会超过10W,所以针对一些特定的大数题目时,我们可以这样来处理,
假定调整区间范围是[a, b],而 a和 b可能大于RAND_MAX,我们可以优化采用另一种方式,比例系数的方法,先用rand函数生成一个[0, RAND_MAX]范围内的整数,然后用这个随机数除以RAND_MAX,这样就会得到一个[0, 1]范围内的比例系数,这个比例系数相当于是[a, b]范围内的比例位置,只需要用这个比例系数乘以(b - a),再加上a即可代表我们随机生成的随机数,即 (int)(round(1.0 * rand() / RAND_MAX * (b-a)+a)) ;


2. 解决方案


#include <iostream>
#include <algorithm>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;

int numbers[5001];
int temp, i, j, numberCounts;
int partition(int changeNumber[], int left, int right);
void scanNumbers();
void quickSort(int changeNumber[], int left, int right);
void showResult();
void swap(int &number1, int &number2);

int main(void)
{
	srand((unsigned)time(NULL)); // 设置随机数种子
	scanNumbers();
	quickSort(numbers, 0, numberCounts - 1);
	showResult();

	return 0;
}

void swap(int &number1, int &number2)
{
	int t = number1;
	number1 = number2;
	number2 = t;
}

void scanNumbers()
{
	scanf("%d", &numberCounts);
	for(int i = 0; i < numberCounts; i++) scanf("%d", &numbers[i]);
}

void showResult()
{
	for(int i = 1; i <= numberCounts; i++)
	{
		printf("%d", numbers[i - 1]);
		if(i % 8 == 0) printf("\n");
		else printf(" ");
	}
}

int partition(int changeNumber[], int left, int right)
{
	int randNumber;
	randNumber = (round(1.0*rand() / RAND_MAX * (right - left) + left));
	swap(changeNumber[left], changeNumber[randNumber]);

	/*
		下面这一部分是基础快速排序的调整区间部分,若是不采用随机数的方式
		,默认选中最左侧元素进行调整,那么删掉上面部分即可
	 */
	temp = changeNumber[left];
	while(left < right)
	{
		while(left < right && changeNumber[right] > temp) right--;
		changeNumber[left] = changeNumber[right];
		while(left < right &&  changeNumber[left] < temp) left++;
		changeNumber[right] = changeNumber[left];
	}
	changeNumber[left] = temp;

	return left;
}

void quickSort(int changeNumber[], int left, int right)
{
	if(left < right)
	{
		int pos = partition(numbers, left, right);
		quickSort(numbers, left, pos - 1);
		quickSort(numbers, pos + 1, right);
	}
}

3. 资源分享


旗木白哉のGitHub:
https://github.com/YangMengHeng
C++ / C源代码下载地址:
https://github.com/YangMengHeng/myCode/tree/master/VSCode
Java源代码下载地址:
https://github.com/YangMengHeng/myCode/tree/master/Java
旗木白哉のblog源代码下载地址:
https://github.com/YangMengHeng/myCode/tree/master/%E6%97%97%E6%9C%A8%E7%99%BD%E5%93%89%E3%81%AEblog


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值