八种常用排序算法总结

八种常用排序算法分类

八种常用排序算法总结_第1张图片

时间复杂度、空间复杂度及稳定性分析

八种常用排序算法总结_第2张图片

不同应用场景下的排序算法选择

1、数据规模较小

  • 待排序列基本序的情况下,可以选择直接插入排序;
  • 对稳定性不作要求宜用简单选择排序,对稳定性有要求宜用插入或冒泡

2、数据规模不是很大

  • 完全可以用内存空间,序列杂乱无序,对稳定性没有要求,快速排序,此时要付出log(N)的额外空间;
  • 序列本身可能有序,对稳定性有要求,空间允许下,宜用归并排序

3、数据规模很大

  • 对稳定性有求,则可考虑归并排序;
  • 对稳定性没要求,宜用堆排序

4、序列初始基本有序(正序),宜用直接插入,冒泡

算法的Java实现

import java.util.ArrayList;

/**
 * 八大排序算法
 */
public class SortAlgorithms {
    //选择排序
    public static void selectionSort(int[] arr, int len){
        for (int i = 0; i < len; i++) {
            int minIndex = i;//寻找[i, len)区间里的最小值下标
            for (int j = i+1; j < len; j++) {
                if (arr[j] < arr[minIndex]){
                    minIndex = j;
                }
            }
            //将i位置的元素和最小值交换
            int temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }

    //插入排序:可以提前终止内层循环
    public static void insertionSort(int[] arr, int len){
        //第一个元素不需要进行插入操作
        for (int i = 1; i < len; i++) {
            //寻找arr[i]合适的插入位置
            int insertNum = arr[i];
            int j;
            for (j = i; j > 0 && arr[j-1] > insertNum; j--) {
                //如果当前元素比前一个元素小,则交换
                arr[j] = arr[j-1];
            }
            arr[j] = insertNum;
        }
    }

    //冒泡排序
    public static void bubbleSort(int[] arr, int len){
        boolean swapped;
        do {
            swapped = false;
            for (int i = 1; i < len; i++) {
                if (arr[i-1] > arr[i]){
                    //交换
                    int temp = arr[i];
                    arr[i] = arr[i-1];
                    arr[i-1] = temp;
                    swapped = true;
                }
            }
            len--;
        }while (swapped);
    }

    //希尔排序
    public static void shellSort(int[] arr, int len){
        int h = len/2;
        while (h>0){
            //h-sort the array
            for (int i = h; i < len; i++) {
                int insertNum = arr[i];
                int j;
                for (j = i; j >=h && insertNum < arr[j-h]; j-=h) {
                    arr[j] = arr[j-h];
                }
                arr[j] = insertNum;
            }
            h /= 2;
        }
    }

    //基于递归的归并排序
    public static void mergeSort(int[] arr, int low, int high){
        int mid = low + (high - low)/2;
        if (mid < high){
            mergeSort(arr, low, mid);//左边
            mergeSort(arr,mid+1, high);//右边
            //左右合并
            merge(arr, low, mid, high);
            //if (arr[mid] > arr[mid+1]){//这一步是一个优化操作,左右都是排好序的,只有当左边的最后一个元素比右边第一个大时才归并
            //    merge(arr, low, mid, high);
            //}
        }
    }
    //归并函数
    public static void merge(int[] arr, int low, int mid, int high){
        int mergeLen = high-low+1;
        int[] temp = new int[mergeLen];
        int left = low;
        int right = mid+1;
        int i = 0;
        //把较小的数据放到新数组
        while (left<=mid && right<=high){
            if (arr[left]temp){
                    right--;
                }
                if (left0; i--) {//只剩最后一个元素时就完成排序了
            buildMaxHeap(arr,i);
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
        }
    }

    //建立最大堆
    public static void buildMaxHeap(int[] arr, int last){
        //从最后一个非叶子开始遍历,将不满足大顶堆的元素和它的左右孩子的最大值交换
        for (int i = (last-1)/2; i >= 0; i--) {
            int k = i;//记录当前正在判断的节点
            //判断是否有左孩子,有左孩子的情况下再判断是否有右孩子,然后再判断是否需要交换
            while (2*k+1 <= last){
                int bigIndex = 2*k+1;//左孩子的索引
                if (bigIndex < last){//说明存在右孩子
                    if (arr[bigIndex] < arr[bigIndex+1]){//比较左右孩子的大小
                        bigIndex++;
                    }
                }
                if (arr[k] < arr[bigIndex]){//父节点比其左右孩子的最大值小
                    int temp = arr[k];
                    arr[k] = arr[bigIndex];
                    arr[bigIndex] = temp;
                    k = bigIndex;
                }else {
                    break;
                }
            }
        }
    }

    //基数排序
    public static void radixSort(int[] arr, int len) {
        //先算出最大数的位数;
        int max = arr[0];
        for (int i = 1; i < len; i++) {
            max = Math.max(max, arr[i]);
        }
        int maxDigit = 0;
        while (max != 0) {
            max /= 10;
            maxDigit++;
        }
        int mod = 10, div = 1;
        ArrayList> bucketList = new ArrayList<>();
        for (int i = 0; i < 10; i++)
            bucketList.add(new ArrayList<>());
        for (int i = 0; i < maxDigit; i++, mod *= 10, div *= 10) {
            for (int j = 0; j < len; j++) {
                int num = (arr[j] % mod) / div;
                bucketList.get(num).add(arr[j]);
            }
            int index = 0;
            for (int j = 0; j < bucketList.size(); j++) {
                for (int k = 0; k < bucketList.get(j).size(); k++)
                    arr[index++] = bucketList.get(j).get(k);
                bucketList.get(j).clear();
            }
        }
    }

    //生成有n个元素的随机数组,每一个元素的随机范围为[rangeL, rangeR]
    public static int[] generateRandomArray(int n, int rangeL, int rangeR){
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = rangeL +(int)(Math.random()*(rangeR-rangeL+1));
        }
        return arr;
    }
    //拷贝数组
    public static int[] copyIntArray(int[] arr, int len){
        int[] newArr = new int[len];
        for (int i = 0; i < len; i++) {
            newArr[i] = arr[i];
        }
        return newArr;
    }

    public static void main(String[] args) {
        int n = 30;
        int[] arr1 = generateRandomArray(n,0, n);
        int[] arr2 = copyIntArray(arr1, n);
        int[] arr3 = copyIntArray(arr1, n);
        int[] arr4 = copyIntArray(arr1, n);
        int[] arr5 = copyIntArray(arr1, n);
        int[] arr6 = copyIntArray(arr1, n);
        int[] arr7 = copyIntArray(arr1, n);
        int[] arr8 = copyIntArray(arr1, n);
        int[] arr9 = copyIntArray(arr1, n);

        System.out.println("-----------排序前-------------");
        for (int i = 0; i < n; i++) {
            System.out.print(arr7[i]+" ");
        }

        System.out.println("\n\n*******排序时间********");

        long startTime1 = System.currentTimeMillis();
        selectionSort(arr1, n);
        long endTime1 = System.currentTimeMillis();
        System.out.println("选择排序:\t" + (endTime1-startTime1)/1000.0 + "s");

        long startTime2 = System.currentTimeMillis();
        insertionSort(arr2, n);
        long endTime2 = System.currentTimeMillis();
        System.out.println("插入排序:\t" + (endTime2-startTime2)/1000.0 + "s");

        long startTime3 = System.currentTimeMillis();
        bubbleSort(arr3, n);
        long endTime3 = System.currentTimeMillis();
        System.out.println("冒泡排序:\t" + (endTime3-startTime3)/1000.0 + "s");

        long startTime4 = System.currentTimeMillis();
        shellSort(arr4, n);
        long endTime4 = System.currentTimeMillis();
        System.out.println("希尔排序:\t" + (endTime4-startTime4)/1000.0 + "s");

        long startTime5 = System.currentTimeMillis();
        mergeSort(arr5,0,n-1);
        long endTime5 = System.currentTimeMillis();
        System.out.println("自顶向下归并排序:\t" + (endTime5-startTime5)/1000.0 + "s");

        long startTime6 = System.currentTimeMillis();
        mergeSortBU(arr6, n);
        long endTime6 = System.currentTimeMillis();
        System.out.println("自底向上归并排序:\t" + (endTime6-startTime6)/1000.0 + "s");

        long startTime7 = System.currentTimeMillis();
        quickSort(arr7,0,n-1);
        long endTime7 = System.currentTimeMillis();
        System.out.println("快速排序:\t" + (endTime7-startTime7)/1000.0 + "s");

        long startTime8 = System.currentTimeMillis();
        heapSort(arr8, n);
        long endTime8 = System.currentTimeMillis();
        System.out.println("堆排序:\t" + (endTime8-startTime8)/1000.0 + "s");

        long startTime9 = System.currentTimeMillis();
        radixSort(arr9, n);
        long endTime9 = System.currentTimeMillis();
        System.out.println("基数排序:\t" + (endTime9-startTime9)/1000.0 + "s");

        System.out.println("\n-----------排序后-------------");
        for (int i = 0; i < n; i++) {
            System.out.print(arr3[i]+" ");
        }
    }
}
 
  

运行效果:

八种常用排序算法总结_第3张图片


你可能感兴趣的:(数据结构与算法)