content_views"
c lass="markdown_views prism-atom-one-dark">
cap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-bloc k" style="-webkit-tap-highlight-c olor: rgba(0, 0, 0, 0);"> 高效且应用广泛的排序 —— 快速c lass="tags" href="/PaiXuSuanFa.html" title=排序c lass="tags" href="/SuanFa.html" title=算法>算法>排序c lass="tags" href="/SuanFa.html" title=算法>算法
快速排序是一种常用的c lass="tags" href="/PaiXuSuanFa.html" title=排序c lass="tags" href="/SuanFa.html" title=算法>算法>排序c lass="tags" href="/SuanFa.html" title=算法>算法c ;主要采用分治 的思想。以下是对快速c lass="tags" href="/PaiXuSuanFa.html" title=排序c lass="tags" href="/SuanFa.html" title=算法>算法>排序c lass="tags" href="/SuanFa.html" title=算法>算法的详细介绍及代码示例:
快速排序的基本思路是c ;每次将一个位置上的数据归位c ;使得该数左边的所有数据都比该数小c ;右边所有的数据都比该数大 c ;然后递归将已归位的数据左右两边再次进行快排c ;从而实现所有数据的归位。
c lass="tags" href="/SuanFa.html" title=算法>算法步骤如下:
从数列中挑出一个元素c ;称为“基准”。 重新排序数列c ;所有比基准值小的元素摆放在基准前面c ;所有比基准值大的元素摆在基准后面(相同的数可以到任何一边)。在这个分区结束之后c ;该基准就处于数列的中间位置。这个称为分区操作。 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。
c="https://i-blog.c sdnimg.c n/direc t/07a10405d08c 4868b61da0859c 0a8390.gif#pic _c enter" alt="在这里插入图片描述" />
例如c ;对于数组c ;选择最左边的元素 29 作为中间点元素c ;然后将数组分成三部分:(0, 14, 15, 20, 25),(29),(44, 37)。中间节点 29 已经排好序了c ;不需要处理。接下来再对左右分别进行快速排序。
下面是 Java 代码示例:
<c ode c lass="prism language-c lass="tags" href="/JAVA.html" title=java>java">class="token keyword">public class="token keyword">c lass class="token c lass-name">Quic kSort class="token punc tuation">{ class="token c omment">// 测试 class="token keyword">public class="token keyword">static class="token keyword">void class="token func tion">main class="token punc tuation">( class="token c lass-name">String class="token punc tuation">[ class="token punc tuation">] argsclass="token punc tuation">) class="token punc tuation">{ class="token keyword">int class="token punc tuation">[ class="token punc tuation">] arr class="token operator">= class="token punc tuation">{ class="token number">5 class="token punc tuation">, class="token number">2 class="token punc tuation">, class="token number">9 class="token punc tuation">, class="token number">6 class="token punc tuation">, class="token number">3 class="token punc tuation">, class="token number">1 class="token punc tuation">, class="token number">7 class="token punc tuation">, class="token number">8 class="token punc tuation">, class="token number">4 class="token punc tuation">} class="token punc tuation">; class="token keyword">int left class="token operator">= class="token number">0 class="token punc tuation">; class="token keyword">int right class="token operator">= arrclass="token punc tuation">. length class="token operator">- class="token number">1 class="token punc tuation">; class="token func tion">quic kSort class="token punc tuation">( arrclass="token punc tuation">, leftclass="token punc tuation">, rightclass="token punc tuation">) class="token punc tuation">; class="token c lass-name">System class="token punc tuation">. outclass="token punc tuation">. class="token func tion">println class="token punc tuation">( class="token string">"排序结果:" class="token punc tuation">) class="token punc tuation">; class="token keyword">for class="token punc tuation">( class="token keyword">int num class="token operator">: arrclass="token punc tuation">) class="token punc tuation">{ class="token c lass-name">System class="token punc tuation">. outclass="token punc tuation">. class="token func tion">print class="token punc tuation">( num class="token operator">+ class="token string">" " class="token punc tuation">) class="token punc tuation">; class="token punc tuation">} class="token punc tuation">} class="token c omment">// 快速c lass="tags" href="/PaiXuSuanFa.html" title=排序c lass="tags" href="/SuanFa.html" title=算法>算法>排序c lass="tags" href="/SuanFa.html" title=算法>算法 class="token keyword">public class="token keyword">static class="token keyword">void class="token func tion">quic kSort class="token punc tuation">( class="token keyword">int class="token punc tuation">[ class="token punc tuation">] arrclass="token punc tuation">, class="token keyword">int leftclass="token punc tuation">, class="token keyword">int rightclass="token punc tuation">) class="token punc tuation">{ class="token keyword">if class="token punc tuation">( left class="token operator">< rightclass="token punc tuation">) class="token punc tuation">{ class="token keyword">int partitionIndex class="token operator">= class="token func tion">partition class="token punc tuation">( arrclass="token punc tuation">, leftclass="token punc tuation">, rightclass="token punc tuation">) class="token punc tuation">; class="token c omment">// 将数组划分为两部分c ;并返回划分点的索引 class="token func tion">quic kSort class="token punc tuation">( arrclass="token punc tuation">, leftclass="token punc tuation">, partitionIndex class="token operator">- class="token number">1 class="token punc tuation">) class="token punc tuation">; class="token c omment">// 递归排序左子数组 class="token func tion">quic kSort class="token punc tuation">( arrclass="token punc tuation">, partitionIndex class="token operator">+ class="token number">1 class="token punc tuation">, rightclass="token punc tuation">) class="token punc tuation">; class="token c omment">// 递归排序右子数组 class="token punc tuation">} class="token punc tuation">} class="token c omment">// 划分函数 class="token keyword">public class="token keyword">static class="token keyword">int class="token func tion">partition class="token punc tuation">( class="token keyword">int class="token punc tuation">[ class="token punc tuation">] arrclass="token punc tuation">, class="token keyword">int leftclass="token punc tuation">, class="token keyword">int rightclass="token punc tuation">) class="token punc tuation">{ class="token keyword">int pivot class="token operator">= arrclass="token punc tuation">[ rightclass="token punc tuation">] class="token punc tuation">; class="token c omment">// 选择最后一个元素作为基准值 class="token keyword">int i class="token operator">= left class="token operator">- class="token number">1 class="token punc tuation">; class="token c omment">// i 为较小元素的索引 class="token keyword">for class="token punc tuation">( class="token keyword">int j class="token operator">= leftclass="token punc tuation">; j class="token operator">< rightclass="token punc tuation">; jclass="token operator">++ class="token punc tuation">) class="token punc tuation">{ class="token keyword">if class="token punc tuation">( arrclass="token punc tuation">[ jclass="token punc tuation">] class="token operator"><= pivotclass="token punc tuation">) class="token punc tuation">{ iclass="token operator">++ class="token punc tuation">; class="token func tion">swap class="token punc tuation">( arrclass="token punc tuation">, iclass="token punc tuation">, jclass="token punc tuation">) class="token punc tuation">; class="token c omment">// 交换较小元素与当前元素 class="token punc tuation">} class="token c omment">// 如果数组元素大于等于 middleValuec ;则继续向后遍历c ;middleIndex 值不变 class="token punc tuation">} class="token func tion">swap class="token punc tuation">( arrclass="token punc tuation">, i class="token operator">+ class="token number">1 class="token punc tuation">, rightclass="token punc tuation">) class="token punc tuation">; class="token c omment">// 将基准值放置到正确的位置上 class="token keyword">return i class="token operator">+ class="token number">1 class="token punc tuation">; class="token c omment">// 返回划分点的索引 class="token punc tuation">} class="token c omment">// 交换数组中两个元素的位置 class="token keyword">public class="token keyword">static class="token keyword">void class="token func tion">swap class="token punc tuation">( class="token keyword">int class="token punc tuation">[ class="token punc tuation">] arrclass="token punc tuation">, class="token keyword">int iclass="token punc tuation">, class="token keyword">int jclass="token punc tuation">) class="token punc tuation">{ class="token keyword">int temp class="token operator">= arrclass="token punc tuation">[ iclass="token punc tuation">] class="token punc tuation">; arrclass="token punc tuation">[ iclass="token punc tuation">] class="token operator">= arrclass="token punc tuation">[ jclass="token punc tuation">] class="token punc tuation">; arrclass="token punc tuation">[ jclass="token punc tuation">] class="token operator">= tempclass="token punc tuation">; class="token punc tuation">}
class="token punc tuation">}
c ode>
快速排序在平均情况下时间复杂度为 O(n log n) c ;但在最坏情况下时间复杂度会变为 O(n²) 。可以通过随机选择基准元素或使用三数取中法等方法来避免最坏情况。空间复杂度为 O(log n) c ;因为在递归调用中需要使用栈来存储中间结果。快速排序虽然在最坏情况下时间复杂度可能较高c ;但在实际应用中通常表现良好c ;尤其对于大规模数据集的排序。如果实现得当c ;它是一种高效的c lass="tags" href="/PaiXuSuanFa.html" title=排序c lass="tags" href="/SuanFa.html" title=算法>算法>排序c lass="tags" href="/SuanFa.html" title=算法>算法。
快速c lass="tags" href="/PaiXuSuanFa.html" title=排序c lass="tags" href="/SuanFa.html" title=算法>算法>排序c lass="tags" href="/SuanFa.html" title=算法>算法基本思路
c="https://i-blog.c sdnimg.c n/direc t/1b7a8563c c 3941ec b2106f462445e84c .png" alt="在这里插入图片描述" />
快速排序是一种高效的c lass="tags" href="/PaiXuSuanFa.html" title=排序c lass="tags" href="/SuanFa.html" title=算法>算法>排序c lass="tags" href="/SuanFa.html" title=算法>算法c ;其基本思路是分治法。首先从数列中取出一个数作为基准数c ;然后进行分区过程c ;将比这个数大的数全放到它的右边c ;小于或等于它的数全放到它的左边 。接着再对左右区间重复这个步骤c ;直到各区间只有一个数。概括来说就是“挖坑填数+分治法”。
快速排序就像整理一堆杂乱的卡片。假设我们有一叠无序的数字卡片c ;我们随机选取一张卡片作为基准数c ;比如选择第一张卡片。然后我们从这叠卡片的右边开始c ;找到比基准数小的卡片c ;从左边开始找到比基准数大的卡片c ;找到后交换这两张卡片的位置。这样不断进行c ;直到左右指针相遇。此时c ;我们把基准数放到正确的位置上c ;这个位置左边的数字都小于等于基准数c ;右边的数字都大于基准数。然后我们再对左右两边的子序列重复这个过程c ;直到所有的子序列都只有一个数字c ;此时整个序列就有序了。
例如c ;有一组数字。我们选择4作为基准数c ;首先从右边开始c ;9大于4c ;继续向左c ;3小于4c ;此时停下。然后从左边开始c ;1小于4c ;继续向右c ;6大于4c ;停下。交换3和6的位置c ;得到。接着继续这个过程c ;指针不断移动c ;直到左右指针相遇。最后把4放到正确的位置上c ;此时序列变为。然后再对左边的子序列和右边的子序列分别进行快速排序c ;直到所有子序列都有序。
快速c lass="tags" href="/PaiXuSuanFa.html" title=排序c lass="tags" href="/SuanFa.html" title=算法>算法>排序c lass="tags" href="/SuanFa.html" title=算法>算法步骤
从序列中任选一个数作为基准数c ;一般就使用第一个数。 进行分区操作c ;将大于基准数的数放在右边c ;小于基准数的数放在左边c ;注意一定要先右后左。具体操作是设置两个指针i和jc ;分别指向数组的第一个元素和最后一个元素。从j开始向左挪动c ;直到找到一个小于基准数的数停下来;然后切换到i再向右挪动c ;直到找到一个数大于基准数的数停下来。最后将i和j指向的元素进行交换位置。重复这个过程直到i和j重合c ;此时把重合点的元素与基准元素交换位置。 对左右区间分别执行上述步骤c ;直到每个区间只有一个数为止。
例如对于数组c ;选择5作为基准数。首先j从6开始向左移动c ;找到3小于5停下。i从0开始向右移动c ;找到8大于5停下。交换3和8的位置c ;得到。接着j继续向左移动c ;找到1小于5停下。i继续向右移动c ;找到2小于5不停下c ;继续移动找到8大于5停下。交换1和8的位置c ;得到。此时i和j重合在1的位置c ;把1和5交换位置c ;得到。然后对左边的子序列和右边的子序列分别进行快速排序c ;直到所有子序列都有序。
快速排序代码示例解析
以下是一段快速排序的 Python 代码示例:
<c ode c lass="prism language-c lass="tags" href="/PYTHON.html" title=python>python">class="token keyword">def class="token func tion">quic kSort class="token punc tuation">( listsclass="token punc tuation">, leftclass="token punc tuation">, rightclass="token punc tuation">) class="token punc tuation">: class="token c omment"># 快速排序 class="token keyword">if left class="token operator">>= rightclass="token punc tuation">: class="token keyword">return listskey class="token operator">= listsclass="token punc tuation">[ leftclass="token punc tuation">] low class="token operator">= lefthigh class="token operator">= rightclass="token keyword">while left class="token operator">< rightclass="token punc tuation">: class="token keyword">while left class="token operator">< right class="token keyword">and listsclass="token punc tuation">[ rightclass="token punc tuation">] class="token operator">>= keyclass="token punc tuation">: right class="token operator">-= class="token number">1 listsclass="token punc tuation">[ leftclass="token punc tuation">] class="token operator">= listsclass="token punc tuation">[ rightclass="token punc tuation">] class="token keyword">while left class="token operator">< right class="token keyword">and listsclass="token punc tuation">[ leftclass="token punc tuation">] class="token operator"><= keyclass="token punc tuation">: left class="token operator">+= class="token number">1 listsclass="token punc tuation">[ rightclass="token punc tuation">] class="token operator">= listsclass="token punc tuation">[ leftclass="token punc tuation">] listsclass="token punc tuation">[ rightclass="token punc tuation">] class="token operator">= keyclass="token keyword">print class="token punc tuation">( class="token string">"lists:" class="token punc tuation">, listsclass="token punc tuation">) quic kSortclass="token punc tuation">( listsclass="token punc tuation">, lowclass="token punc tuation">, left class="token operator">- class="token number">1 class="token punc tuation">) quic kSortclass="token punc tuation">( listsclass="token punc tuation">, left class="token operator">+ class="token number">1 class="token punc tuation">, highclass="token punc tuation">) class="token keyword">return lists
c ode>
这段代码首先判断左右指针的位置c ;如果左指针大于等于右指针c ;说明该子序列已经有序c ;直接返回。然后选择左指针指向的元素作为基准数<c ode>keyc ode>。接着使用两个循环c ;从右向左找到小于基准数的元素c ;从左向右找到大于基准数的元素c ;然后交换这两个元素的位置。当左右指针相遇时c ;将基准数放到正确的位置上。最后递归地对左右子序列进行快速排序。
以列表为例c ;调用<c ode>quic kSortc ode>函数进行排序。首先选择3作为基准数c ;从右向左找到2小于3停下c ;从左向右找到6大于3停下c ;交换2和6的位置c ;得到。接着继续这个过程c ;直到左右指针相遇c ;把3放到正确的位置上。然后对左边的子序列和右边的子序列分别进行快速排序c ;直到整个列表有序。
快速排序时间复杂度分析
快速排序的时间复杂度与划分是否平衡密切相关。最优情况下c ;时间复杂度为 O(nlogn)。这是因为每次划分都能将序列均匀地分成两部分c ;此时快速排序的性能与归并排序一样。
例如c ;对于一个包含 n 个数的序列c ;递归的第一层c ;将 n 个数划分为 2 个子区间c ;每个子区间的数字个数约为 n/2;递归的第二层c ;将 n 个数划分为 4 个子区间c ;每个子区间的数字个数约为 n/4;以此类推c ;递归的第 logn 层c ;将 n 个数划分为 n 个子区间c ;每个子区间的数字个数为 1。在每一层的划分过程中c ;时间复杂度约为 O(n)c ;而总共需要划分 logn 层c ;所以最优情况下的时间复杂度为 O(nlogn)。
然而c ;在最坏情况下c ;时间复杂度为 O(n^2)。当每次选择的基准元素是最大或最小元素时c ;快速排序的时间复杂度是 O(n^2)。例如c ;序列已经是有序的c ;每次选择第一个元素作为基准数c ;那么每次划分只能分出一个元素c ;导致递归的深度达到 nc ;而每一层的时间复杂度为 O(n)c ;所以最坏情况下的时间复杂度为 O(n^2)。
平均情况下c ;快速排序的时间复杂度也是 O(nlogn)。在实际应用中c ;快速排序通常表现良好c ;尤其对于大规模数据集的排序。
快速排序避免最坏情况方法
为了避免快速排序的最坏情况c ;可以采用以下几种方法:
随机选取划分点:每次随机从待排序序列中选取一个元素作为划分点c ;从而降低最坏情况的概率。这样可以避免每次都选择到最大或最小元素作为基准数c ;使得划分更加平衡。 三数取中法:选取待排序序列的第一个、中间一个、最后一个元素中的中间值作为划分点c ;从而降低最坏情况的概率。例如对于序列c ;可以选择1、6、3中的中间值3作为基准数c ;这样可以在一定程度上避免选择到最大或最小元素。 在递归深度较浅时采用其他c lass="tags" href="/PaiXuSuanFa.html" title=排序c lass="tags" href="/SuanFa.html" title=算法>算法>排序c lass="tags" href="/SuanFa.html" title=算法>算法c ;比如插入排序或归并排序等c ;从而避免快速排序退化成 O(n^2) 的情况。当问题规模小于某一 k 值时c ;采用插入排序c ;提高c lass="tags" href="/SuanFa.html" title=算法>算法效率。
总结
快速c lass="tags" href="/PaiXuSuanFa.html" title=排序c lass="tags" href="/SuanFa.html" title=算法>算法>排序c lass="tags" href="/SuanFa.html" title=算法>算法是一种高效的c lass="tags" href="/PaiXuSuanFa.html" title=排序c lass="tags" href="/SuanFa.html" title=算法>算法>排序c lass="tags" href="/SuanFa.html" title=算法>算法c ;其基本思路是分治法c ;通过不断地划分和递归c ;将序列分成越来越小的子序列进行排序c ;直到所有子序列都有序。在实际应用中c ;可以根据不同的情况选择合适的方法来避免最坏情况的发生c ;以提高c lass="tags" href="/SuanFa.html" title=算法>算法的性能。