Java排序算法合集,所有代码调试运行无误,附带常用算法运行时间比较

 

如果觉得copy代码太麻烦,这里为你准备好了代码文件Java排序算法源代码

目录

时间复杂度 O(n^2)

冒泡排序

选择排序

插入排序

时间复杂度 O(n log n)

希尔排序

归并排序

快速排序

堆排序

四种常用排序时间复杂度的比较

非比较排序

计数排序

基数排序


 

时间复杂度 O(n^2)

冒泡排序

/**
 * 冒泡排序
 */
public class BubbleSort {
    public static void main(String[] args) {
        int[] arr = { 5, 4, 3, 7, 6, 9, 8, 1, 2, 0 };
        for (int i : bubbleSort(arr)) {
            System.out.print(i);
            System.out.print(" ");
        }
    }

    /**
     * 冒泡排序,将大的数慢慢冒出,每次冒出的数字下标此处称作游标
     *
     * @param intArray 目标数组
     * @return 排序后的数组
     */
    public static int[] bubbleSort(int[] intArray) {
        for (int i = 0; i < intArray.length; i++) { // 冒泡的次数
            for (int j = 1; j < intArray.length - i; j++) {// 游标的位置,游标的最大位置即冒泡的终点
                // 每次比较要进行的操作
                if (intArray[j - 1] > intArray[j])
                    swap(intArray, j, j - 1);
            }
        }
        return intArray;
    }

    /**
     * 交换i,j俩个位置的数
     */
    public static void swap(int[] intArray, int i, int j) {
        int temp = intArray[i];
        intArray[i] = intArray[j];
        intArray[j] = temp;
    }
}

选择排序

/**
 * 选择排序
 */
public class SelectSort {
    public static void main(String[] args) {
        int[] arr = { 5, 4, 3, 7, 6, 9, 8, 1, 2, 0 };
        for (int i : selectSort(arr)) {
            System.out.print(i);
            System.out.print(" ");
        }
    }

    /**
     * 选择排序,在未拍序列中选择最大的一个数字放入未排序列的末尾
     *
     * @param intArray 目标数组
     * @return 排序后的数组
     */
    public static int[] selectSort(int[] intArray) {
        for (int i = intArray.length - 1; i > 0; i--) {// 需要选择放入的位置,第intArray[0]位置不用放
            swap(intArray, i, maxSubScript(intArray, i));
        }
        return intArray;
    }

    /**
     * 交换i,j俩个位置的数
     */
    public static void swap(int[] intArray, int i, int j) {
        int temp = intArray[i];
        intArray[i] = intArray[j];
        intArray[j] = temp;
    }

    /**
     * 返回最大值下标
     *
     * @param intArray 目标数组
     * @param len      寻找的长度arr[0]-arr[len]
     * @return 该范围内最大值下标
     */
    public static int maxSubScript(int[] intArray, int len) {
        if (intArray.length == 0)
            return -1;
        int maxSub = 0;
        for (int i = 1; i <= len; i++)
            maxSub = intArray[maxSub] > intArray[i] ? maxSub : i;
        return maxSub;
    }
}

插入排序

/**
 * 插入排序
 */
public class InsertSort {
    public static void main(String[] args) {
        int[] arr = { 5, 4, 3, 7, 6, 9, 8, 1, 2, 0 };
        for (int i : insertSort(arr)) {
            System.out.print(i);
            System.out.print(" ");
        }
    }

    /**
     * 插入排序,从头依次检查每个位置的数,插入到其前面最适当的位置
     *
     * @param intArray 目标数组
     * @return 结果数组
     */
    public static int[] insertSort(int[] intArray) {
        for (int i = 1; i < intArray.length; i++) {
            int temp = intArray[i];// 要插入的值
            int m = i;// 拷贝需多次赋值变量
            while (m != 0 && intArray[m - 1] > temp) {
                intArray[m] = intArray[m - 1];
                m--;
            }
            intArray[m] = temp;
        }
        return intArray;
    }

}

时间复杂度 O(n log n)

 

希尔排序

(如果将希尔排序的初始增量设置为1,则就是简单的插入排序)

/**
 * 希尔排序
 */
public class HillSort {
    public static void main(String[] args) {
        int[] arr = { 5, 4, 3, 7, 6, 9, 8, 1, 2, 0 };
        for (int i : hillSort(arr)) {
            System.out.print(i);
            System.out.print(" ");
        }
    }

    /**
     * 希尔排序
     * 
     * @param intArray 目标数组
     * @return 结果数组
     */
    public static int[] hillSort(int[] intArray) {
        int increment = intArray.length / 2; // 初始增量
        while (increment > 0) {
            intArray = hillSortSubFunction(intArray, increment);
            increment /= 2;
        }
        return intArray;
    }

    /**
     * 根据增量进行插入排序
     *
     * @param intArray  目标数组
     * @param increment 增量
     * @return 结果数组
     */
    public static int[] hillSortSubFunction(int[] intArray, int increment) {
        for (int i = 0; i < increment; i++) {// 根据增量分的组数
            for (int j = i + increment; j < intArray.length; j += increment) {
                int temp = intArray[j];
                int m = j;
                while ((m - increment) > -1 && intArray[m - increment] > temp) {
                    intArray[m] = intArray[m - increment];
                    m -= increment;
                }
                intArray[m] = temp;
            }
        }
        return intArray;
    }
}

归并排序

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:

  • 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
  • 自下而上的迭代;
/**
 * 归并排序
 */
public class MergeSort {
    public static void main(String[] args) {
        int[] arr = { 5, 4, 3, 7, 6, 9, 8, 1, 2, 0 };
        int[] temp = new int[arr.length];
        mergeSort(arr, 0, arr.length-1, temp);
        for (int i : arr) {
            System.out.print(i);
            System.out.print(" ");
        }
    }

    public static void mergeSort(int[] intArray, int start, int end, int[] temp) {
        if (start < end) {
            int middle = (start + end) / 2;
            mergeSort(intArray, start, middle, temp);
            mergeSort(intArray, middle + 1, end, temp);
            merge(intArray, start, end, temp);
        }
    }

    /**
     * 将数组内两部分有序数列合并,合并后的数组放在 intArray[leftStart] ~ intArray[leftStart]中
     *
     * @param intArray  目标数组
     * @param leftStart 左数组的第一个数下标
     * @param rightEnd  右数组最后一个元素的下标
     * @param temp      大小和intArray一样的临时数组
     */
    public static void merge(int[] intArray, int leftStart, int rightEnd, int[] temp) {
        int leftEnd = (leftStart + rightEnd) / 2;
        // 两标记的开始位置
        int i = leftStart, j = leftEnd + 1;
        // 临时数组的填充起始位置
        int m = leftStart;
        // 如果两边还有没排的数,循环
        while (i <= leftEnd || j <= rightEnd) {
            // 只剩右数组有数
            if (i > leftEnd) {
                temp[m] = intArray[j];
                j++;
            }
            // 只剩左数组有数
            else if (j > rightEnd) {
                temp[m] = intArray[i];
                i++;
            }
            // 两数组都有数
            else {
                if (intArray[i] < intArray[j]) {
                    temp[m] = intArray[i];
                    i++;
                } else {
                    temp[m] = intArray[j];
                    j++;
                }
            }
            m++;
        }
        // 将合并后的数组赋值到元素组对应的位置
        for (int x = leftStart; x <= rightEnd; x++)
            intArray[x] = temp[x];
    }

}

 

快速排序

快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。快速排序就是快,而且效率高!它是处理大数据最快的排序算法之一了。虽然 Worst Case 的时间复杂度达到了 O(n²),但是人家就是优秀,在大多数情况下都比平均时间复杂度为 O(n logn) 的排序算法表现要更好

(将数组的第一个元素作为基准,放到一个合适的位置,使它左边的所有数小于它,右边所有的数大于它)分别在左右两边的的数组进行括号里的操作,递归下去)

/**
 * 快速排序
 */
public class FastSort {
    public static void main(String[] args) {
        int[] arr = { 5, 4, 3, 7, 6, 9, 8, 1, 2, 0 };
        sortByBenchmark(arr, 0, arr.length - 1);
        for (int i : arr) {
            System.out.print(i);
            System.out.print(" ");
        }
    }

    /**
     * 将数组指定起始到末尾看作一个数组arr,使arr第一个数到达arr基准位置(左边全小于基准,右边全大于基准)
     *
     * @param intArray
     * @param start    起始地址(包含)
     * @param end      终止地址(包含)
     * @return 最终基准值的位置(绝对位置 )
     */
    public static void sortByBenchmark(int[] intArray, int start, int end) {
        if (start < end) {
            int benchmark = intArray[start];// 存储基准值
            int begin = start;// 排查的起始位置
            for (int check = start + 1; check < end + 1; check++) {
                if (intArray[check] < benchmark) {
                    swap(intArray, check, ++begin);
                }
            }
            swap(intArray, start, begin);
            sortByBenchmark(intArray, start, begin - 1);
            sortByBenchmark(intArray, begin + 1, end);
        }
    }

    /**
     * 交换i,j俩个位置的数
     */
    public static void swap(int[] intArray, int i, int j) {
        int temp = intArray[i];
        intArray[i] = intArray[j];
        intArray[j] = temp;
    }
}

 

堆排序

(对选择排序的选择方式的一个升级)

堆排序就是将数组按照完全二叉树的进行数组表示,其中分为两类:

  • 大顶堆 :堆的父节点总是大于它的子节点
  • 小顶堆:堆的父节点总是小于它的子节点

此处还需了解完全二叉树的一个特性,当使用数组表示一个完全二叉树时:

  • 左节点对应的数组下标=(其父节点对应的数组下标)* 2 + 1
  • 右节点对应的数组下标=(其父节点对应的数组下标)* 2 + 2

此处我们使用大顶堆来举例,其步骤如下:

一.构建初始堆

这部不用使用代码进行构建,因为可以将数组的默认顺序看作初始堆

二.构建大顶堆

将初始堆进行整理,使所有的父节点大于子节点,最终堆顶的元素(数组的一个元素)将是此数组中最大的值

三.将待排数与堆顶元素进行替换

将数组第一个元素与最后一个元素对换位置

四.将被替换的堆顶元素下沉,使其未排序堆重新成为大顶堆

五.重复三,四,两步,直至未排序列长度为1,

/**
 * 堆排序
 */
public class HeapSort {
    public static void main(String[] args) {
        int[] arr = { 5, 4, 3, 7, 6, 9, 8, 1, 2, 0 };
        heapSort(arr);
        for (int i : arr) {
            System.out.print(i);
            System.out.print(" ");
        }
    }

    /**
     * 堆排序
     *
     * @param intArray
     */
    public static void heapSort(int[] intArray) {
        int count = intArray.length;
        // 初始化数组(大顶堆)
        buildMaxHeap(intArray);
        while (count > 1) {
            // 将待排数与堆顶元素进行替换
            swap(intArray, 0, count - 1);
            // 将堆顶元素下沉
            sink(intArray, 0, count - 1);
            count--;
        }
    }

    /**
     * 构建大顶堆
     *
     * @param intArray 初始堆
     */
    public static void buildMaxHeap(int[] intArray) {
        // 获取从下往上的第一个父节点
        int firstFatherNode = (intArray.length - 2) / 2;
        // 从堆底的第一个父节点开始,逐次往上下沉每一个父节点
        for (int i = firstFatherNode; i > -1; i--)
            sink(intArray, i, intArray.length);

    }

    /**
     * 对特定元素在数组的特定范围内下沉
     *
     * @param intArray 初始堆
     * @param i        目标元素的下标
     * @param len      下沉长度范围
     */
    public static void sink(int[] intArray, int i, int len) {
        // 左右子节点下标
        int leftSub = 2 * i + 1;
        int rightSub = 2 * i + 2;
        // 最大值下标
        int maximumSub = i;

        // 如果在范围内有左子,且大于目标节点
        if (leftSub < len && intArray[leftSub] > intArray[maximumSub]) {
            maximumSub = leftSub;
        }

        if (rightSub < len && intArray[rightSub] > intArray[maximumSub]) {
            maximumSub = rightSub;
        }

        if (maximumSub != i) {
            swap(intArray, i, maximumSub);
            sink(intArray, maximumSub, len);
        }
        // 如不满足上述条件,停止下沉
    }

    /**
     * 交换i,j俩个位置的数
     */
    public static void swap(int[] intArray, int i, int j) {
        int temp = intArray[i];
        intArray[i] = intArray[j];
        intArray[j] = temp;
    }
}

四种常用排序时间复杂度的比较

小编分别对四种数量级大小的数组进行了上述的排序方式,排序时间如下图

可见快速排序还是很牛批的,不过因为归并排序是稳定排序,他们的实力也算是不相上下了

非比较排序

计数排序

由于计数排序不是比较排序,所以它的速度比任何比较排序都快,由于要以数组中最大元素作为大小申请数组内存空间,所以对于数据范围大的数组,此方法会很占用内存

代码示例:

/**
 * 非比较排序:计数排序
 */
public class CountSort {
    public static void main(String[] args) {
        int[] arr = { 5, 4, 3, 7, 6, 9, 8, 1, 2, 0 };
        countSort(arr);
        for (int i : arr) {
            System.out.print(i);
            System.out.print(" ");
        }
    }

    /**
     * 计数排序
     *
     * @param arr
     */
    public static void countSort(int[] arr) {
        int maxValue = findTheMax(arr);
        int bucketLen = maxValue + 1;
        int[] bucket = new int[bucketLen];//新建一个比最大数多一的一个数组(也成为桶)

        for (int value : arr) {
            bucket[value]++;//将目标数组的值作为计数数组的下标,使此元素加一
        }

        int sortedIndex = 0;
        for (int j = 0; j < bucketLen; j++) {
            while (bucket[j] > 0) {
                arr[sortedIndex++] = j;
                bucket[j]--;
            }
        }

    }

    /**
     *返回数组最大值
     */
    public static int findTheMax(int[] arr) {
        int maxValue = arr[0];
        for (int value : arr) {
            if (maxValue < value) {
                maxValue = value;
            }
        }
        return maxValue;
    }
   
}

基数排序

import java.util.Arrays;

/**
 * 非比较排序:基数排序
 */
public class RadixSort {
    public static void main(String[] args) {
        int[] arr = { 5, 4, 3, 7, 6, 9, 8, 1, 2, 0 };
        radixSort(arr);
        for (int i : arr) {
            System.out.print(i);
            System.out.print(" ");
        }
    }

    /**
     * 基数排序
     *
     * @param arr
     * @return
     */
    public static void radixSort(int[] arr) {
        int maxDigit = getMaxDigit(arr);
        int mod = 10;
        int dev = 1;

        // 根据最大数的位数进行基数排序
        for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
            // 考虑负数的情况,这里扩展一倍队列数,其中 [0-9]对应负数,[10-19]对应正数 (bucket + 10)
            int[][] counter = new int[mod * 2][0];

            for (int j = 0; j < arr.length; j++) {
                int bucket = ((arr[j] % mod) / dev) + mod;
                counter[bucket] = arrayAppend(counter[bucket], arr[j]);
            }

            int pos = 0;
            for (int[] bucket : counter) {
                for (int value : bucket) {
                    arr[pos++] = value;
                }
            }
        }
    }

    /**
     * 获取数组中最大元素的位数
     */
    public static int getMaxDigit(int[] arr) {
        // 获取最大元素的值
        int maxValue = arr[0];
        for (int value : arr) {
            if (maxValue < value) {
                maxValue = value;
            }
        }
        if (maxValue == 0) {
            return 1;
        }
        // 判断该元素是几位数
        int lenght = 0;
        for (long temp = maxValue; temp != 0; temp /= 10) {
            lenght++;
        }
        return lenght;
    }

    /**
     * 重新开辟一个比原数组大一的数组,将值添加到末尾
     *
     * @param arr
     * @param value
     */
    public static int[] arrayAppend(int[] arr, int value) {
        arr = Arrays.copyOf(arr, arr.length + 1);
        arr[arr.length - 1] = value;
        return arr;
    }

}

 

                                                                                          觉得OK点个赞呗!😁

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值