十大排序算法之快速排序

简介

快速排序使用了分治的思想,通过一趟排序将待排序列分割成两部分,其中一部分记录的关键字均比另一部分记录的关键字小。之后分别对这两部分记录继续进行排序,以达到整个序列有序的目的。

步骤

  1. 选择基准:在待排序列中,按照某种方式挑出一个元素,作为 “基准”(pivot);

  2. 分割操作:以该基准在序列中的实际位置,把序列分成两个子序列。如果为升序,则此时,在基准左边的元素都比该基准小,在基准右边的元素都比基准大;而基准则在排序后正确的位置上。

  3. 递归地对两个序列进行快速排序,直到序列为空或者只有一个元素;

实例

  1. Java 代码
import java.util.Random;
public class Main
{
	public static void main(String[] args) {
        Random r = new Random();
        int[] data = new int[100];
        for (int i = 0; i < data.length; i++) {
            data[i] = r.nextInt(10);
        }
        Long startTime = System.currentTimeMillis();
        print(data);
        Long endTime = System.currentTimeMillis();
        //方式一:固定基准元
        // sortCommon(data, 0, data.length-1); 
        
        //方法二:随机基准元
        // sortRandom(data, 0, data.length-1); 
        
        //方法三:采用三数取中
        //sortMiddleOfThree(data, 0, data.length-1);  
        
        //优化一
        // sortThreeInsert(data, 0, data.length-1);   //当待排序序列的长度分割到一定大小后,使用插入排序
        
        //优化二
        sortThreeInsertGather(data, 0, data.length - 1);  //在一次分割结束后,可以把与Key相等的元素聚在一起,继续下次分割时,不用再对与key相等元素分割
        print(data);
        System.out.println("排序用时:" + (endTime - startTime));
    }

    public static void sortCommon(int[] data, int low, int high) {
        if (high > low) {
            //进行一次排序,将基准元放置在正确顺序的位置上,并确定当前基准元位置
            int key = getStandard(data, low, high);
            //分别将基准元左侧和基准元右侧当做一个序列从新进行排序,知道序列的长度为1
            sortCommon(data, low, key - 1);
            sortCommon(data, key + 1, high);
        }
    }

    public static int getStandard(int[] data, int low, int high) {
        //将基准元提取出来
        int tmp = data[low];
        while (low < high) {
            //从右往左查询,查找第一个小于基准元的元素,并将其放置在data[low]位置
            while (low < high && data[high] >= tmp) {
                high--;
            }
            data[low] = data[high];
            //从左往右查询,查找第一个大于基准元的元素,并将其放置在data[high]位置
            while (low < high && data[low] <= tmp) {
                low++;
            }
            data[high] = data[low];
        }
        //基准元归为
        data[low] = tmp;
        return low;
    }

    public static void sortRandom(int[] data, int low, int high) {
        if (high > low) {
            //进行一次排序,将基准元放置在正确顺序的位置上,并确定当前基准元位置
            getStandardRandom(data, low, high);
            int key = getStandard(data, low, high);
            //分别将基准元左侧和基准元右侧当做一个序列从新进行排序,知道序列的长度为1
            sortRandom(data, low, key - 1);
            sortRandom(data, key + 1, high);
        }
    }

    private static void getStandardRandom(int[] data, int low, int high) {
        Random r = new Random();
        int ran = low + r.nextInt(high - low);
        //将基准元提取出来
        swap(data, low, ran);
    }

    public static void sortMiddleOfThree(int[] data, int low, int high) {
        if (high > low) {
            //三数去中,并将中间数换到low位置上
            middleOfThree(data, low, high);
            //进行一次排序,将基准元放置在正确顺序的位置上,并确定当前基准元位置
            int key = getStandard(data, low, high);
            //分别将基准元左侧和基准元右侧当做一个序列从新进行排序,知道序列的长度为1
            sortMiddleOfThree(data, low, key - 1);
            sortMiddleOfThree(data, key + 1, high);
        }
    }

    private static void middleOfThree(int[] data, int low, int high) {
        int middle = (high - low) / 2 + low;
        if (data[middle] > data[high]) {
            swap(data, middle, high);
        }
        if (data[low] > data[high]) {
            swap(data, low, high);
        }
        if (data[middle] > data[low]) {
            swap(data, middle, low);
        }
    }

    public static void sortThreeInsert(int[] data, int low, int high) {
        if (high - low + 1 < 10) {
            insertSort(data);
            return;
        } else {
            //三数去中,并将中间数换到low位置上
            middleOfThree(data, low, high);
            //进行一次排序,将基准元放置在正确顺序的位置上,并确定当前基准元位置
            int key = getStandard(data, low, high);
            //分别将基准元左侧和基准元右侧当做一个序列从新进行排序,知道序列的长度为1
            sortThreeInsert(data, low, key - 1);
            sortThreeInsert(data, key + 1, high);
        }
    }

    public static void sortThreeInsertGather(int[] data, int low, int high) {
        if (high - low + 1 < 10) {
            insertSort(data);
            return;
        } else {
            //三数去中,并将中间数换到low位置上
            middleOfThree(data, low, high);
            //进行一次排序,确定基准元位置,并将和基准元相等的元素,一直数组的两侧
            //first 和last 用来计算基准元
            int first = low;
            int last = high;
            //left和right 用来记录和基准元相等的元素
            int left = low;
            int right = high;
            //leftLength和rightLength用来记录左右两侧各有多少和基准元相等的元素
            int leftLength = 0;
            int rightLength = 0;
            int tmp = data[first];
            while (first < last) {
                while (first < last && data[last] >= tmp) {
                    if (data[last] == tmp) {
                        swap(data, last, right);
                        right--;
                        rightLength++;
                    }
                    last--;
                }
                data[first] = data[last];
                while (first < last && data[first] <= tmp) {
                    if (data[first] == tmp) {
                        swap(data, first, left);
                        left++;
                        leftLength++;
                    }
                    first++;
                }
                data[last] = data[first];
            }
            data[first] = tmp;

            //一次排序完成,将两侧与基准元相等的元素移到基准元旁边
            int i = first - 1;
            int j = low;
            while (j < left && data[i] != tmp) {
                swap(data, i, j);
                i--;
                j++;
            }
            i = last + 1;
            j = high;
            while (j > right && data[i] != tmp) {
                swap(data, i, j);
                i++;
                j--;
            }
            sortThreeInsert(data, low, first - 1 - leftLength);
            sortThreeInsert(data, first + 1 + rightLength, high);
        }
    }


    public static void insertSort(int[] a) {
        //从下标为1开始比较,知道数组的末尾
        for (int i = 1; i < a.length; i++) {
            int j;
            //将要比较的元素,拿出待比较过后再插入数组
            int tmp = a[i];
            //一次与前一元素比较,如果前一元素比要插入的元素大,则互换位置
            for (j = i - 1; j >= 0 && a[j] > tmp; j--) {
                a[j + 1] = a[j];
            }
            //将比较的元素插入
            a[j + 1] = tmp;
        }
    }

    public static void print(int[] a) {
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i] + " ");
        }
        System.out.println();
    }

    private static void swap(int[] data, int i, int j) {
        if (i == j) {
            return;
        }
        data[i] = data[i] + data[j];
        data[j] = data[i] - data[j];
        data[i] = data[i] - data[j];
    }
}

  1. 输出结果
    在这里插入图片描述
    在这里插入图片描述
发布了225 篇原创文章 · 获赞 64 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/duoduo_11011/article/details/103459145