Java实现【快速排序】【归并排序】【桶排序/基数排序】

一、快速排序

快速排序算法通过多次比较和交换来实现排序,其排序流程如下:
1.首先设定一个分界值,通过该分界值将数组分成左右两部分。
2.将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
3.然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
4.重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。

public class QuickSort {
    public static void main(String[] args) {

//        int[] arrays = {101, 34, 119, 1};
//        int[] result = insertSort(arrays);
//        System.out.println(Arrays.toString(result));

        //速度测试  8049
        long begin = System.currentTimeMillis();

        int[] array = new int[8];
        for (int i = 0; i < array.length; i++) {
            array[i] = (int) (Math.random() * 8000000);
        }
        int[] results = quickSort(array,0,array.length-1);

        long end = System.currentTimeMillis();
        System.out.println("用时:"+(end - begin));
        System.out.println(Arrays.toString(results));
    }

    public static int[] quickSort(int[]arr,int left,int right){
//        System.out.println(Arrays.toString(arr));
        //左下标
        int lIndex = left;
        //右下标
        int rIndex = right;
        //pivot中轴值
        int pivot = arr[(left + right) / 2];
        //临时变量
        int temp = 0;
        //while循环的目的是让比pivot值小放到左边,比pivot大的放到右边
        while(lIndex < rIndex){
            //pivot的左边一直找,找到>=pivot的值时退出
            while (arr[lIndex] < pivot){
                lIndex += 1;
            }
            while (arr[rIndex] > pivot){
                rIndex -= 1;
            }
//            System.out.println(Arrays.toString(arr));
            //若lIndex>=rIndex说明左边已经全部都是小于pivot的值,右边已全部都是大于pivot的值
            if(lIndex >= rIndex){
                break;
            }
            //进行值的交换
            temp = arr[lIndex];
            arr[lIndex] = arr[rIndex];
            arr[rIndex] = temp;
            //交换完成后若arr[lIndex] == pivot 相同,说明pivot左边已完成排序,右边的指针前移
            if(arr[lIndex] == pivot){
                rIndex -= 1;
            }
            //交换完成后若arr[rIndex] == pivot 相同,说明pivot右边已完成排序,左边的指针后移
            else if(arr[rIndex] == pivot){
                lIndex += 1;
            }
        }
        //如果lIndex == rIndex ,需将左指针后移 ,右指针前移 避免出现栈溢出
        if(lIndex == rIndex){
            lIndex++;
            rIndex--;
        }
        //若右指针比初始的做指针大,说明左边没有进行排序
        if(left < rIndex){
            quickSort(arr,left,rIndex);
        }
        if(right > lIndex){
            quickSort(arr,lIndex,right);
        }
        return arr;
    }
}

二、归并排序

归并操作的工作原理如下:
1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2.设定两个指针,最初位置分别为两个已经排序序列的起始位置
3.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4.重复步骤3直到某一指针超出序列尾
5.将另一序列剩下的所有元素直接复制到合并序列尾

public class MergeSort {

    public static void main(String[] args) {

//        int[] arrays = {101, 34, 119, 1};
//        int[] temp = new int[arrays.length];
//        mergeSort(arrays, 0, arrays.length - 1, temp);
//        System.out.println(Arrays.toString(arrays));

        //速度测试  8049
        long begin = System.currentTimeMillis();

        int[] array = new int[80000];
        for (int i = 0; i < array.length; i++) {
            array[i] = (int) (Math.random() * 8000000);
        }
        int[] temp = new int[array.length];
        mergeSort(array, 0, array.length - 1, temp);

        long end = System.currentTimeMillis();
        System.out.println("用时:" + (end - begin));
//        System.out.println(Arrays.toString(array));
    }

    public static void mergeSort(int[] arrays, int left, int right, int[] temp) {
        if (left < right) {
            int pivot = (left + right) / 2;
            mergeSort(arrays, left, pivot, temp);
            mergeSort(arrays, pivot + 1, right, temp);
            merge(arrays, left, pivot, right, temp);

        }
    }

    public static void merge(int[] arrays, int left, int pivot, int right, int[] temp) {
        //初始化左边有序序列的初始索引
        int leftIndex = left;
        //初始化右边有序序列的初始索引
        int rightIndex = pivot + 1;
        //指向temp数组的当前索引
        int tempIndex = 0;

        //一.先把左右两边(有序)的数组按照规则填充到temp数组中
        //直到左右两边的有序序列,有一边处理完成为止
        while (leftIndex <= pivot && rightIndex <= right) {
            if (arrays[leftIndex] <= arrays[rightIndex]) {
                temp[tempIndex] = arrays[leftIndex];
                leftIndex++;
                tempIndex++;
            } else {
                temp[tempIndex] = arrays[rightIndex];
                rightIndex++;
                tempIndex++;
            }
        }

        while (leftIndex <= pivot) {
            temp[tempIndex] = arrays[leftIndex];
            tempIndex++;
            leftIndex++;
        }
        while (rightIndex <= right) {
            temp[tempIndex] = arrays[rightIndex];
            tempIndex++;
            rightIndex++;
        }

        tempIndex = 0;
        int tempLeft = left;
        while (tempLeft <= right) {
            arrays[tempLeft] = temp[tempIndex];
            tempIndex++;
            tempLeft++;
        }
    }
}

三、桶排序/基数排序

基本思想:先排好个位,再排十位,百位,千位…

1.创建10个的桶,下标从0到9。
2.遍历原数据,获取元素的个位,将其放入匹配下标的桶中。
3.全部放入之后再取出替换原数据,再将排序过一次的原数据遍历,获取元素的十位,将其放入匹配下标的桶中,依次百位,千位…
4.最后一次放到桶中,再按照桶的下标从0-9将其中的数据取出,就获得到了有序数列。

public class RadixSort {
    public static void main(String[] args) {
/*
        int[] arrays = {101, 34, 119, 1};
        int[] result = radixSort(arrays);
        System.out.println(Arrays.toString(result));
*/


        //速度测试  91
        long begin = System.currentTimeMillis();

        int[] array = new int[8000000];
        for (int i = 0; i < array.length; i++) {
            array[i] = (int) (Math.random() * 8000000);
        }
        int[] results = radixSort(array);

        long end = System.currentTimeMillis();
        System.out.println("用时:"+(end - begin));
//        System.out.println(Arrays.toString(results));
    }


    public static int[] radixSort(int[] arrays) {
        //数组中最大数
        int max = arrays[0];
        for (int i = 1; i < arrays.length; i++) {
            if (arrays[i] > max) {
                max = arrays[i];
            }
        }
        //最大数是几位数
        int maxLength = (max + "").length();

        // 定义10个桶,每个桶是一个数组
        /*说明
            1. 二维数组包含10个一维数组
		    2. 为了防止在放入数的时候,数据溢出,则每个一维数组(桶),大小定为arrays.length
		    3. 明确,基数排序是使用空间换时间的经典算法
         */
        int[][] bucket = new int[10][arrays.length];

        //定义一个数组记录每个桶实际存放的数据个数
        int[] bucketCounts = new int[10];
        //取出数据用
        int index = 0;
        //使用循环进行排序
        for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
            //针对每个元素对应的位数进行处理,第一次处理个位数,第二次处理十位,以此类推
            for (int j = 0; j < arrays.length; j++) {
                //取出每个元素对应位数的值
                int digitOfElement = arrays[j] / n % 10;
                //将其放入对应的桶中
                bucket[digitOfElement][bucketCounts[digitOfElement]] = arrays[j];
                //将指针向前移动一下
                bucketCounts[digitOfElement]++;
            }
            //按照这个桶的顺序(一维数组的下标依次取出数据,放入到原来的数组中)
            index = 0;
            //遍历每一个桶中的数据
            for (int k = 0; k < bucketCounts.length; k++) {
                //只有桶中有数据时才放入原数组
                if(bucketCounts[k]!=0){
                    //循环第k个桶
                    for (int l = 0;l < bucketCounts[k];l++){
                        //取出元素放入arrays
                        arrays[index++] = bucket[k][l];
                    }
                }
                //第i+1轮处理后将桶的指针回到初始位置
                bucketCounts[k] = 0;
            }
        }

        return arrays;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章