经典算法:快速排序

活动地址:CSDN21天学习挑战赛

学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您:
想系统/深入学习某技术知识点…
一个人摸索学习很难坚持,想组团高效学习…
想写博客但无从下手,急需写作干货注入能量…
热爱写作,愿意让自己成为更好的人…


欢迎参与CSDN学习挑战赛,成为更好的自己,请参考活动中各位优质专栏博主的免费高质量专栏资源(这部分优质资源是活动限时免费开放喔~),按照自身的学习领域和学习进度学习并记录自己的学习过程。您可以从以下3个方面任选其一着手(不强制),或者按照自己的理解发布专栏学习作品,参考如下:

**

什么是算法

一、数据、数据元素、数据项和数据对象

1.数据:是客观事物的符号表示,是所有能输入到计算机中并被计算机程序处理的符号的总称
2.数据元素:是数据的基本单位,在计算机中通常作为一个整体进行考虑和处理
3.数据项:是组成数据元素的、有独立含义的、不可分割的最小单位
4.数据对象:是性质相同的数据元素的集合,是数据的一个子集

二、数据结构

1.数据结构定义:是相互之间存在一种或多种特定关系的数据元素的集合。数据结构包括逻辑结构和存储结构
2.逻辑结构:数据的逻辑结构是从逻辑关系上描述数据,它与数据的存储无关,是独立于计算机的。因此数据的逻辑结构可以看做是从具体问题抽象出来的数学模型
3.存储结构:数据对象在计算机中的存储表示称为数据的存储结构,也称为物理结构。把数据对象存储到计算机时,通常要求既要存储各数据元素,又要存储数据元素之间的逻辑关系,数据元素在计算机内用一个结点来表示。数据元素在计算机中有两种基本的存储结构,分别是顺序存储结构和链式存储结构

三、算法定义和特性

  1. 定义:是为了解决某类问题而规定的一个有限长的操作序列
  2. 特性:
    (1)有穷性:一个算法必须总是在执行有穷步后结束,且每一步都必须在有穷时间内完成
    (2)确定性:对于每种情况下所应执行的操作,在算法中都有确切的规定,不会产生二义性,使算法的执行者或阅读者都能明确其含义及如何执行
    (3)可行性:算法中的所有操作都的可以通过已经实现的基本操作运算执行有限次来实现
    (4)输入:一个算法有零个或多个输入,当用函数描述算法时,输入往往是通过形参表示的,在它们被调用时从主调函数获得输入值
    (5)输出:一个算法有一个或多个输出,它们是算法进行信息加工后得到的结果,无输出的算法没有任何意义,当用函数描述算法时,输出多用返回值和引用类型的形参表示

四、评价算法优劣的基本标准

1.正确性。在合理的数据输入下能够在有限的运行时间内得到正确的结果
2.可读性。一个好的算法首先应便于人们理解和相互交流,其次才是机器可执行性,可读性强的算法有助于人们对算法的理解,而难懂的算法易于隐藏错误,且难以调试和修改
3.健壮性。当输入的数据非法时,好的算法能适当地做出正确的反应或进行相应处理,而不会产生一些莫名其妙的输出结果
4.高效性。高效性包括时间和空间两个方面。时间高效是指算法设计合理执行效率高,可以用时间复杂度来度量;空间高效性是指算法占用存储容量合理,可以用空间复杂度来度量。时间复杂度和空间复杂度是衡量算法的两个主要指标

快速排序

一、插入排序

插入排序的基本思想是:每一趟将一个待排序的记录,按其关键字的大小插入到已经排好序的一组记录的适当位置上,直到所有待排序记录全部插入为止。
可以选择不同的方法在已排好序的记录中寻找插入位置。根据查找方法的不同,有多种插入排序方法,这里仅介绍三种方法:直接插入排序、折半插入排序和希尔排序。

二、快速排序
1.交换排序

交换排序的基本思想是:两两比较排序记录的关键字,一旦发现两个记录不满足次序要求时则进行交换,直到整个序列全部满足要求为止。本节首先介绍基于简单交换思想实现的冒泡排序。

2.快速排序

快速排序是由冒泡排序改进而得的,在冒泡排序过程中,只对相邻的两个记录进行比较,因此每次交换两个相邻记录时只能消除一个逆序。如果能通过两个(不相邻)记录的一次交换,消除多个逆序,则会大大加快排序的速度。快速排序方法中的一次交换可能消除多个逆序。

3.算法步骤

①选择待排序表中的第一个记录作为枢轴,将枢轴记录暂存在r[0]的位置上。附设两个指针low和high,初始时分别指向表的上界和下界(第一趟时,low=1;high=L.length;)。
②从表的右侧位置依次向左搜索,找到第一个关键字小于枢轴关键字pivotkey的记录,将其移至low处。具体操作是:low<high时,若high所指记录的关键字大于等于pivotkey,则向左移动指针high(执行操作–high);否则将high所指记录与枢轴记录交换。
③然后从表的最左侧位置,依次向右搜索找到第一个关键字大于pivotkey的记录和枢轴记录交换。具体操作是:当low<high时,若low所指记录的关键字小于等于pivotkey,则向右移动指针low(执行操作++low);否则将low所指记录与枢轴记录交换。
④重复步骤②和③,直至low与high相等为止。此时low和high的位置即为枢轴在此趟排序中的最终位置,原表被分为两个子表。
在上述过程中,记录的交换都是与枢轴之间发生,每次交换都要移动三次记录,可以先将枢轴记录暂存在r[0]的位置上,排序过程中只移动要与枢轴交换的记录,即只做r[low]和r[high]的单向移动,直至一趟排序结束后再将枢轴记录移至正确位置上。

4.例:

int Partition(SqList &L,int low,int high)				//对顺序表L中的子表r[low..high]进行一趟排序,返回枢轴位置
{
	L.r[0]=L.r[low];									//用子表的第一个记录做枢轴记录
	pivotkey=L.r[low].key;								//枢轴记录关键字保存在pivotkey中
	while(low<high)										//从表的两端交替地向中间扫描
	{
		while(low<high&&L.r[high].key>=pivotkey) --high;
		L.r[low]=L.r[high];								//将比枢轴记录小的记录移到低端
		while(low<high&&L.r[low].key>=pivotkey) ++low;
		L.r[high]=L.r[low];								//将比枢轴记录大的记录移到高端
	}													//while
	L.r[low]=L.r[0];									//枢轴记录到位
	return low;											//返回枢轴位置
}

void QSort(SqList &L,int low,int high)					//调用前置初值:low=1;high=L.length;
{														//对顺序表L中的子序列L.r[low..high]做快速排序
	if(low<high)										//长度大于1
	{
		pivotloc=Partition(L,low,high);					//将L.r[low..high]一分为二,pivotloc是枢轴位置
		QSort(L,low,pivotloc-1);						//对左子表递归排序
		QSort(L,pivotloc+1,high);						//对右子表递归排序
	}
}

void QuickSort(SqList &L)								//对顺序表L做快速排序
{
	QSort(L,1,L.length);
}

5.算法分析
①时间复杂度

最好情况:每一趟排序后都能将记录序列均匀地分割成两个长度大致相等的子表,类似折半查找。在n个元素的序列中,对枢轴定位所需时间为O(n)。若设T(n)是对n个元素的序列进行排序所需的时间,而且每次对枢轴正确定位后,正好把序列划分为长度相等的两个子表,此时,设Cn是一个常数,表示n个元素进行一趟快速排序的时间,则总的排序时间为
T(n)=Cn+2T(n/2)
≤n+2T(n/2)
≤n+2(n/2+2T(n/4))=2n+4T(n/4)
≤2n+4(n/4+2T(n/8))=3n+8T(n/8)

≤in+2ᵏT(n/2ᵏ)
∵k=log₂n
∴T(n)≤nlog₂n+not(1)≈O(nlog₂n)
最坏情况:在待排序序列已经排好序的情况下,必须经过n-1趟才能将所有记录定位,而且第i趟需要经过n-i次比较。这样,总的关键字比较次数KCN为
KCN=n(n-1)/2≈n²/2
这种情况下,快速排序的速度已经退化到简单排序的水平。枢轴记录的合理选择可避免这种最坏情况的出现,如利用“三者取中”的规则:比较当前表中第一个记录、最后一个记录和中间一个记录的关键字,取关键字居中的记录为枢轴记录,事先调换到第一个记录的位置。
理论上可以证明,平均情况下,快速排序的时间复杂度为O(nlog₂n)。

②空间复杂度

快速排序是递归的,执行时需要有一个栈来存放相应数据。最大递归调用次数与递归树的深度一致,所以最好情况下的空间复杂度为O(log₂n),最坏情况下为O(n)。

6.算法特点

①记录非顺次的移动导致排序方法是不稳定的。
②排序过程中需要定位表的下界和上界,所以适合用于顺序结构,很难用于链式结构。
③当n较大时,在平均情况下快速排序是所有内部排序方法中速度最快的一种,所以其适合初始记录无序、n较大时的情况。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值