数据结构与算法(JAVA篇)之高级排序_快速排序(二)

/**
 *
 * @author SunnyMoon
 */
////////////////////////////////////////////////////////////////////////////////
/*******************************************************************************
 * 概念介绍:
 * *****************************************************************************
 *
 * 影响效率的最大障碍:
 * 对枢纽数据的选择是影响排序的效率。上一篇文章选择枢纽数据为数组的最后一个元素,
 * 这么选择只是为方便,然而却造成了特殊情况时效率极度下降,降到O(n2)。这种特情况就是当数据为逆序的时候。
 * 如果改变特殊情况给快速排序带来的致命影响呢,这将在这一专题中简要介绍。
 *
 * 三数据项取中划分:
 * 目前已经有很多选择更好的枢纽的方法,选择任意一个数据项作为枢纽是一种简单的方法,便是
 * 正如前文看到的那样,在特殊情况下性能很低。从理论上讲实际使数组中值数据是最理想的枢纽
 * 选择,是效率最高的方式,但实际上这个过程比排序本身需要更长的时间,因此这是不可行的。
 * 一种折衷的方法,选择数组里的第一个,最后一个以及中间位置的数据中选择一个中间值,并设
 * 置此数据项为枢纽,这种选择枢纽的方式为三数据项选中。
 * 查找三个数据项的中值数据项比查找所有数据项中值快很多,在大多数通常情况下这种方法是又
 * 快又有效的方法。但是有很特殊的数据排列命名三数据项先中的方法也很低效。
 *
////////////////////////////////////////////////////////////////////////////////
/**
 * 定义一个数组类,封装了对自身数据的排序。
 */
class ArrayIns {

    private long[] theArray;
    private int nElems;

    public ArrayIns(int max) {
        theArray = new long[max];
        nElems = 0;
    }

    public void insert(long value) {
        theArray[nElems] = value;
        nElems++;
    }

    public void display() {
        System.out.print("A=");
        for (int j = 0; j < nElems; j++) {
            System.out.print(theArray[j] + " ");
        }
        System.out.println("");
    }
/**
 * 快速排序主方法
 */
    public void quickSort() {
        recQuickSort(0, nElems - 1);
    }

/**
 * 递归调用快速的排序核心方法
 * @param left
 * @param right
 */
    public void recQuickSort(int left, int right) {
        int size = right-left + 1;
        if (size <= 3) {
            manualSort(left, right);
        } else {
            long median = medianOf3(left, right);//三数取中值
            int partition=partitionIt(left,right,median);//三数据取中值作为枢纽进行划分
            recQuickSort(left, partition - 1);//递归排序数组左子元素
            recQuickSort(partition + 1,right);//递归排序数据左子元素
        }
    }

/**
 * 三数据选中
 * @param left
 * @param right
 * @return
 */
    public long medianOf3(int left, int right) {
        int center = (left + right) / 2;

        if (theArray[left] > theArray[center]) {
            swap(left, center);
        }
        if (theArray[left] > theArray[right]) {
            swap(left, right);
        }
        if (theArray[center] > theArray[right]) {
            swap(center, right);
        }
        swap(center, right - 1);
        return theArray[right - 1];
    }
    
/**
 * 交换数据
 * @param dex1
 * @param dex2
 */
    public void swap(int dex1, int dex2) {
        long temp = theArray[dex1];
        theArray[dex1] = theArray[dex2];
        theArray[dex2] = temp;
    }
    
/**
 * 根据三数据选中进行划分
 * @param left
 * @param right
 * @param pivot
 * @return
 */
    public int partitionIt(int left, int right, long pivot) {
        int leftPtr = left;//定位到最左元素
        int rightPtr = right-1;//定位到枢纽

        while (true) {
            while (theArray[++leftPtr] < pivot);//寻找大于枢纽元素
            while (theArray[--rightPtr] > pivot);//寻找小于枢纽元素
            if (leftPtr >= rightPtr) {//确定划分结束退出循环
                break;
            } else {
                swap(leftPtr, rightPtr);//交换需划分的元素
            }
        }
        swap(leftPtr, right-1);//恢复枢纽到正确位置
        return leftPtr;//返回枢纽
    }
/**
 * 手动排序
 * @param left
 * @param right
 */
    public void manualSort(int left, int right) {
        int size = right-left + 1;
        if (size <= 1) {//当元素为1时直接返回
            return;
        }
        if (size == 2) {
            if (theArray[left] > theArray[right]) {//当元素为2时排序
                swap(left, right);
            }
            return;
        } else {//当元素为3时排序
            if (theArray[left] > theArray[right - 1]) {
                swap(left, right - 1);
            }
            if (theArray[left] > theArray[right]) {
                swap(left, right);
            }
            if (theArray[right - 1] > theArray[right]) {
                swap(right - 1, right);
            }
        }
    }
}

/**
 * 主类
 */
public class QuickSort2 {


    public static void main(String[] args) {
        int maxSize = 15;
        ArrayIns arr = new ArrayIns(maxSize);
        for (int j = 0; j < maxSize; j++) {//随机生机数据插入数组中
            long n = (int) (java.lang.Math.random() * 99);
            arr.insert(n);
        }
        System.out.println("显示排序前数据");
        arr.display();
        arr.quickSort();
        System.out.println("显示排序后数据");
        arr.display();
    }
}

/**
 *运行结果:
 *显示排序前数据
 *A=38 62 44 89 50 91 36 60 47 22 83 7 33 31 38
 *显示排序后数据
 *A=7 22 31 33 36 38 38 44 47 50 60 62 83 89 91 
 */

/**
 * 总结:
 * 快速排序是常用排序中效率最高的一种排序方式。
 * 但在应用中的一此特殊情况影响他的效率,这不是算法本身的问题,而是如果实现的问题。
 * 三数据项选中方法很好的解决了这样的问题。
 */
 

你可能感兴趣的:(java,数据结构,算法,J#)