排序算法之快速排序

 今天开始总结排序算法,面试最常考到的应该就是快速排序,也叫做分划交换排序。

       快速排序最明显的特征就是在待排序序列中选择一个分划元素,也叫做主元(pivot),通过一趟排序就会将排序的数据分割成两个部分,主元的左边都比主元小,主元的右边比主元大,再将分成的两边子序列作相同的处理,当所有的子序列为空或者只有一个元素时被认为有序,完成排序。

      网上的快速排序算法一般有两种,一种是两头交换法,另一种是挖坑填坑法。

      我们先来看两头交换法,以{6,5,9,4,2,7,3,}为例,我们一般把左边第一个元素6作为主元,使用两个下标变量i和j分别指向位置一的元素6和和最后位置3,先移动j。i自左往右移动,将主元与下标为i的元素比较,如果主元大于i所指示的元素,则i右移一位 ,直至遇到一个元素不小于主元的停止右移,此时指针i指向9。j自右往左移动,同样遇到一个元素不大于主元时,停止左移此时指针指向3。然后交换i和j所指示的元素,此时序列交换完成为{6,5,3,4,2,7,9}。下一步继续按照同样的方式移动指针i和j,知道i>=j时结束,最后将主元6和位于i的元素交换,结束第一次分划操作。序列为{2,5,3,4,6,7,9}。继续对主元6两边的子序列作相同的处理。

   我们看一下代码。

public class quickSort {
   public static void quicksort(int arrays[],int left,int right) {
       int x=arrays[left];//主元设为第一个元素
       int i=left;
       int j=right;
       if(left>=right) {
           return; 
       }
       while(i!=j) {
//移动指针j寻找不大于主元的元素
while(i<j&&arrays[j]>=x) { j--; } //移动指针i寻找不大于主元的元素 while(i<j&&arrays[i]<=x) { i++; }
//交换i和j所指示元素
if(i<j) { int temp=arrays[i]; arrays[i]=arrays[j]; arrays[j]=temp; } }
//最后将主元和位于i的元素交换,完成一次划分。 arrays[left]
=arrays[i]; arrays[i]=x; quicksort(arrays,left,i-1); quicksort(arrays,i+1,right); } public static void main(String args[]) { int nums[]= {6,5,9,4,2,7,3}; quicksort(nums,0,6); for(int i=0;i<nums.length-1;i++) { System.out.print(nums[i]+" "); } } }

 第二种挖坑填坑法也不难理解,还是以{6,5,9,4,2,7,3}为例,我们现在以第一个元素为坑也是主元,同样两个指针i和j分别指向6和3,先左移j,找到一个元素不大于主元,此时j指向3,在此位置挖一个坑,把上一个坑用此时j找到的元素填了,此时序列为{3,5,9,4,2,7,3}.然后右移i,直至找到一个元素不小于主元,此时i指向9,在这里挖一个坑,同样用i指向的元素把上一个坑满填上,此时序列为{3,5,9,4,2,7,9}继续重复移动j和i直至i>=j,最后将主元6和位于i的元素交换,结束第一次分划操作。此时序列为{3,5,2,4,6,7,9}。继续对主元6两边的子序列作相同的处理。

我们看一下代码:

public class quickSort {
   public static void quicksort(int arrays[],int left,int right) {
       int x=arrays[left];将第一个元素作为主元,同时也是第一个坑
       int i=left;
       int j=right;
       if(left>=right) {
           return; 
       }   
       while(i!=j) {
// 左移j,找到一个不大于主元的元素
while(i<j&&arrays[j]>=x) { j--; }
//用j指向的元素把坑填了,同时在这里挖一个坑。
if(i<j) { arrays[i]=arrays[j]; }
//右移i,找到一个元素不小于主元
while(i<j&&arrays[i]<=x) { i++; }
//用i指向的元素把坑填了,同时在这里挖一个坑。
if(i<j) { arrays[j]=arrays[i]; } }
//最后一个坑用主元填了。 arrays[i]
=x; quicksort(arrays,left,i-1); quicksort(arrays,i+1,right); } public static void main(String args[]) { int nums[]= {6,5,9,4,2,7,3}; quicksort(nums,0,6); for(int i=0;i<nums.length-1;i++) { System.out.print(nums[i]+" "); } } }

 我们现在看一下快速排序的时间复杂度。如果每次分划操作,左右两个子序列长度基本相等,则效率最高,其最好的时间复杂度为O(nlogn)。反之如果每次分划操作产生的子序列其中一个为空,则快排效率最低,其最坏情况为O(n2),这种情况发生在原始正向有序和反向有序。平均时间复杂度为O(nlogn)。

原文地址:https://www.cnblogs.com/fankailei/p/9769519.html