算法之排序算法浅谈

来源:互联网 发布:log4j源码讲解 编辑:程序博客网 时间:2024/04/30 08:39

    在8大排序算法之间的时间复杂度,辅助空间以及稳定性情况如下表1:

    

表1

   一:快速排序。

   快速排序的核心在鱼partition函数部分,如何选择pivot分割点,以及如何围绕分割点进行分割;

   法一:如下代码

/***   快速排序法*/public class QuickSort {//运用分治思想,按照每次的中间值分开两部分后,每部分继续递归去分为两部分排序public void Quick_Sort(int A[],int start,int end){int position = QCCore01(A, start, end);if(position>start){Quick_Sort(A,start,position-1);}if(position<end){Quick_Sort(A,position+1,end);}}//快排核心部分,选取一个分界值,然后把数组分为两部分,运用前后两指针对向移动方法private int QCCore01(int A[],int start,int end){int key = A[start];//这里取的是第一个元素作为分界值while(start<end){            //右指针先左移,直到遇到“小”值            while(A[end]>=key&&start<end){            end--;            }            //把“小”值交换到左边,把分界值转换过来            if(start<end){            int temp = A[end];            A[end] = key;            A[start] = temp;            }            //左指针右移,直到遇到“大”值            while(A[start]<=key&&start<end){            start++;            }            //把“大”值交换到右边,把分界值转换过来            if(start<end){            int temp = A[start];            A[start] = key;                A[end] = temp;             }             }return start;//返回中间值的标号}} 
   该方法比较常用,即选择每次排序段数组第一个元素作为pivot元素,然后两遍依次向中间夹逼,每次都是与pivot元素交换;


   法二:代码如下

   

/***   快速排序法*/public class QuickSort {//运用分治思想,按照每次的中间值分开两部分后,每部分继续递归去分为两部分排序public void Quick_Sort(int A[],int start,int end){int position = QCCore02(A, start, end);if(position>start){Quick_Sort(A,start,position-1);}if(position<end){Quick_Sort(A,position+1,end);}}    //快排核心部分,运用双指针同时从前向后,产生大小差值,并根据差值数替换。    private int QCCore02(int A[],int start, int end){        int small = start;//记录“小”值的数目,big遇到“大”值不增加,遇到“小”值才增加        int big = start+1;//代表当前指针去遍历元素        int key = A[start];//取第一个数作为分界值                //双指针去遍历        while(big<=end){            if(A[big]<key){                small++;                if(big!=small){                    int temp = A[big];                    A[big] = A[small];                    A[small] = temp;                }            }            big++;        }        //最后需要交换分界值到指定位置        int temp = A[small];        A[small] = A[start];        A[start] = temp;                return small;//返回分界值的位置    }} 
   该方法pivot元素仍然是选择数组段第一个元素作为分割点,但是交换方法上改为比较巧妙的双指针同向运动,一个small指针表示当前最后一个小段元素,big指针表示当前最后一个大段元素,即保证两个指针间的元素都为大段元素,最后只需要把pivot元素放在small指针后面即可(该方法的交换不是鱼pivot元素直接交换);

   

   法三:代码如下

   

/** * 快速排序 * */public class QuickSort {/** * 主调用方法 * */public void quickSort(int[] array,int n){if(n>2){this.recurSort(array, 0, n-1);}}/** * 递归进行不断划分,首先进行三个元素间的分割点选择,接着进行划分,并递归 * */private void recurSort(int[] array,int start,int end){if(start<end){int pivot = (end-start)/2+start;this.threeSort(array, start, pivot, end);int curPivot = this.partition(array, pivot, start+1, end-1);this.recurSort(array, curPivot+1, end);this.recurSort(array, start, curPivot-1);}}/** * 对数组中三个位置进行排序,针对于快排中的选分割点,选择左中右三个元素中的中间元素作为分割点,防止最坏情况发生; * 如果不采用该选择策略,该方法可以不用; * */private void threeSort(int[] array,int l,int m,int r){if(array[l]>array[m]){this.swap(array, l, m);if(array[r]<=array[l]){this.swap(array, r, l);this.swap(array, m, r);}else if(array[r]<=array[m])this.swap(array, m, r);}else{if(array[r]<=array[l]){this.swap(array, r, l);this.swap(array, m, r);}else if(array[r]<=array[m])this.swap(array, m, r);}}/** * 交换两数组中两个元素位置 * @param i 位置1 * @param j 位置2 * */private void swap(int[] array,int i,int j){int temp = array[i];array[i] = array[j];array[j] = temp;}/** * 一次快排的划分 * @param array 待排序数组 * @param pivot 划分点的序号 * @param start 数组中划分段的起始点序号 * @param end 数组中划分段的结束点序号 * */private int partition(int[] array,int pivot,int start, int end){int pivotIndex = pivot;if(start<end){/*记录结束点的序号*/int toail = end;/*记录划分点的值*/int value = array[pivot];/*把划分点与划分段最后一个数交换,即把划分点的值放到最后*/this.swap(array, pivot, end);end--;/*主循环*/while(start<end){if(array[start]<value)start++;else if(array[end]>=value)end--;else{this.swap(array, start, end);}}/*循环出来后,做扫尾工作,准备还原分割点*//*当start的值大于分割点,则必须交换*/if(array[start]>=value){this.swap(array, start, toail);pivotIndex = start;}/*如果start的值小于分割点的值,则交换start右边一个元素与分割点;如果右边没有元素,则保持不动*/else if(array[start]<value && start+1<toail){this.swap(array, start+1, toail);pivotIndex = start+1;}else{pivotIndex = toail;}}return pivotIndex;}}
   该方法是通过把pivot元素一开始就放置到数组末端,然后双指针向中间夹逼,同时找到一大一小才互相交换元素,而不是与pivot元素交换;在选择pivot的方法上,当然允许继续选择数组段的第一个元素作为pivot元素,但是这里提供了一个threeSort()函数,该函数是将数组段的最左,中间,最右三个元素排序后返回中间元素的序号,将该元素作为pivot即可防止快排最坏情况的发送。

0 0
原创粉丝点击