• 排序算法


    名称 最好 平均 最坏 空间 稳定性 类别
    冒泡排序 $ O(n) $ $ O(n^2) $ $ O(n^2) $ $ O(1) $ 交换排序
    选择排序 (O(n^2)) (O(n^2)) (O(n^2)) (O(1)) 选择排序
    插入排序 (o(n)) (o(n^2)) (o(n^2)) (o(1)) 插入排序
    希尔排序 (o(n)) (o(n^{1~3})) (o(n^2)) (o(1)) 插入排序
    归并排序 (o(nlog_2n)) (o(nlog_2n)) (o(nlog_2n)) (o(n))
    快速排序 (o(nlog_2n)) (o(nlog_2n)) (o(n^2)) (o(nlog_2n)) 交换排序
    基数排序 (o(d(n+r))) (d=最大的数的位数,r为基数10,o(d(n+r))) (o(d(n+r))) (o(n+r))
    堆排序 (o(nlog_2n)) (o(nlog_2n)) (o(nlog_2n)) (o(1)) 选择排序
    计数排序 (k=最大的数值,o(n+k)) (o(n+k))
    桶排序 (n=M,o(n)) (O(n+nlog_2n-nlog_2M)) (o(n+M))
    // 冒泡排序
    public static void bubbleSort(int arr[]) {
        for(int i =0 ; i<arr.length-1 ; i++) {
            for(int j=0 ; j<arr.length-1-i ; j++) {
                if(arr[j]>arr[j+1]) {
                    int temp = arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                }
            }
        }
    }
    
    //选择排序
    public static void selectSort(int arr[]){
        for(int i = 0; i < arr.length-1; i++){
            int min = i;
            for(int j = i+1; j <arr.length ;j++){
                if(arr[j]<arr[min]){
                    min = j;
                }
            }
            if(min!=i){
                int temp = arr[min];
                arr[min] = arr[i];
                arr[i] = temp;
            }
        }
    }
    
    // 插入排序
    public static void insertsort(int arr[]){
        for (int i=1;i<arr.length;i++) {
            for(int j=i;j>0&&(arr[j]<arr[j-1]);j--) {
                int temp=arr[j];
                arr[j]=arr[j-1];
                arr[j-1]=temp;
            }
        }
    }
    
    // 希尔排序
    public static void shellSort(int arr[]){
        int gap = arr.length;
        while (true) {
            gap /= 2;   //增量每次减半
            for (int i = 0; i < gap; i++) {
                for (int j = i + gap; j < arr.length; j += gap) {//这个循环里其实就是一个插入排序
                    int temp = arr[j];
                    int k = j - gap;
                    while (k >= 0 && arr[k] > temp) {
                        arr[k + gap] = arr[k];
                        k -= gap;
                    }
                    arr[k + gap] = temp;
                }
            }
            if (gap == 1)
                break;
        }
    }
    
    // 归并排序
    public static int[] mergeSort(int arr[], int l, int r) {
        if (l == r)
            return new int[] { arr[l] };
        int mid = l + (r - l) / 2;
        int[] leftArr = mergeSort(arr, l, mid); //左有序数组
        int[] rightArr = mergeSort(arr, mid + 1, r); //右有序数组
        int[] newNum = new int[leftArr.length + rightArr.length]; //新有序数组
        int m = 0, i = 0, j = 0;
        while (i < leftArr.length && j < rightArr.length) {
            newNum[m++] = leftArr[i] < rightArr[j] ? leftArr[i++] : rightArr[j++];
        }
        while (i < leftArr.length)
            newNum[m++] = leftArr[i++];
        while (j < rightArr.length)
            newNum[m++] = rightArr[j++];
        return newNum;
    }
    
    // 快速排序
    public static int[] quickSort(int arr[],int start,int end) {
        int pivot = arr[start];
        int i = start;
        int j = end;
        while (i<j) {
            while ((i<j)&&(arr[j]>pivot)) {
                j--;
            }
            while ((i<j)&&(arr[i]<pivot)) {
                i++;
            }
            if ((arr[i]==arr[j])&&(i<j)) {
                i++;
            } else {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        if (i-1>start) arr=quickSort(arr,start,i-1);
        if (j+1<end) arr=quickSort(arr,j+1,end);
        return (arr);
    }
    
    // 基数排序
    public static void radixSort(int[] arr, int d){ //d表示最大的数有多少位
        int k = 0;
        int n = 1;
        int m = 1; //控制键值排序依据在哪一位
        int[][]temp = new int[10][arr.length]; //数组的第一维表示可能的余数0-9
        int[]order = new int[10]; //数组orderp[i]用来表示该位是i的数的个数
        while(m <= d) {
            for(int i = 0; i < arr.length; i++) {
                int lsd = ((arr[i] / n) % 10);
                temp[lsd][order[lsd]] = arr[i];
                order[lsd]++;
            }
            for(int i = 0; i < 10; i++) {
                if(order[i] != 0)
                    for(int j = 0; j < order[i]; j++) {
                        arr[k] = temp[i][j];
                        k++;
                    }
                order[i] = 0;
            }
            n *= 10;
            k = 0;
            m++;
        }
    }
    
    // 堆排序
     public static int[] heapSort(int[] array) {
         //这里元素的索引是从0开始的,所以最后一个非叶子结点array.length/2 - 1
         for (int i = array.length / 2 - 1; i >= 0; i--) {
             adjustHeap(array, i, array.length);  //调整堆
         }
    
         // 上述逻辑,建堆结束
         // 下面,开始排序逻辑
         for (int j = array.length - 1; j > 0; j--) {
             // 元素交换,作用是去掉大顶堆
             // 把大顶堆的根元素,放到数组的最后;换句话说,就是每一次的堆调整之后,都会有一个元素到达自己的最终位置
             swap(array, 0, j);
             // 元素交换之后,毫无疑问,最后一个元素无需再考虑排序问题了。
             // 接下来我们需要排序的,就是已经去掉了部分元素的堆了,这也是为什么此方法放在循环里的原因
             // 而这里,实质上是自上而下,自左向右进行调整的
             adjustHeap(array, 0, j);
         }
         return array;
     }
    /**
         * 整个堆排序最关键的地方
         * @param array 待组堆
         * @param i 起始结点
         * @param length 堆的长度
         */
    public static void adjustHeap(int[] array, int i, int length) {
        // 先把当前元素取出来,因为当前元素可能要一直移动
        int temp = array[i];
        for (int k = 2 * i + 1; k < length; k = 2 * k + 1) {  //2*i+1为左子树i的左子树(因为i是从0开始的),2*k+1为k的左子树
            // 让k先指向子节点中最大的节点
            if (k + 1 < length && array[k] < array[k + 1]) {  //如果有右子树,并且右子树大于左子树
                k++;
            }
            //如果发现结点(左右子结点)大于根结点,则进行值的交换
            if (array[k] > temp) {
                swap(array, i, k);
                // 如果子节点更换了,那么,以子节点为根的子树会受到影响,所以,循环对子节点所在的树继续进行判断
                i  =  k;
            } else {  //不用交换,直接终止循环
                break;
            }
        }
    }
    /**
         * 交换元素
         * @param arr
         * @param a 元素的下标
         * @param b 元素的下标
         */
    public static void swap(int[] arr, int a, int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
    
    // 计数排序
    public static int[] countSort(int arr[]){
        int b[] = new int[arr.length];
        int max = arr[0],min = arr[0];
        for(int i:arr){
            if(i>max){
                max=i;
            }
            if(i<min){
                min=i;
            }
        }//这里k的大小是要排序的数组中,元素大小的极值差+1
        int k=max-min+1;
        int c[]=new int[k];
        for(int i=0;i<arr.length;++i){
            c[arr[i]-min]+=1;//优化过的地方,减小了数组c的大小
        }
        for(int i=1;i<c.length;++i){
            c[i]=c[i]+c[i-1];
        }
        for(int i=arr.length-1;i>=0;--i){
            b[--c[arr[i]-min]]=arr[i];//按存取的方式取出c的元素
        }
        return b;
    }
    
    // 桶排序
    public static void bucketSort(int arr[]) {
        int n=arr.length;
        int bask[][]=new int[10][n];
        int index[]=new int[10];
        int max=Integer.MIN_VALUE;
        for(int i=0;i<n;i++) {
            max=max>(Integer.toString(arr[i]).length())?max:(Integer.toString(arr[i]).length());
        }
        String str;
        for(int i=max-1;i>=0;i--) {
            for(int j=0;j<n;j++) {
                str="";
                if(Integer.toString(arr[j]).length()<max) {
                    for(int k=0;k<max-Integer.toString(arr[j]).length();k++)
                        str+="0";
                }
                str+=Integer.toString(arr[j]);
                bask[str.charAt(i)-'0'][index[str.charAt(i)-'0']++]=arr[j];
            }
            int pos=0;
            for(int j=0;j<10;j++) {
                for(int k=0;k<index[j];k++) {
                    arr[pos++]=bask[j][k];
                }
            }
            for(int x=0;x<10;x++)index[x]=0;
        }
    }
    
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,如有问题, 可评论咨询.
  • 相关阅读:
    递归的效率问题以及递归与循环的比较
    malloc/free与new/delete的区别
    类的综合案例——纯虚函数与抽象类( 加强对接口与多态,以及派生类构造函数的理解 )
    对象移动、右值引用详解
    深入理解类成员函数的调用规则(理解成员函数的内存为什么不会反映在sizeof运算符上、类的静态绑定与动态绑定、虚函数表)
    为什么NULL指针也能访问成员函数?(但不能访问成员变量)
    洛谷P1656 炸铁路
    Vijos1901 学姐的钱包
    洛谷P2327 [SCOI2005] 扫雷
    洛谷P1993 小 K 的农场
  • 原文地址:https://www.cnblogs.com/Dean0731/p/14476543.html
Copyright © 2020-2023  润新知