常见排序算法总结

废话不多说,直接看代码

import java.util.ArrayList;

public class Sort {
    static int[] a= {-1,1,41,3,3,3,1,2,5,23,345,12,3,4,53,2,41};
    //static int[] a = {2, 1,-1};
    public static void main(String[] args){
        quickSort(a);
        printArray();

    }


    /** *冒泡排序 *1.从第一个开始比较相邻的元素。如果后置位比前置位小,进行交换。 *2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。 *3.重复步骤1,每次遍历长度减一(末尾的数已经有序,不需要进行交换)。 */

    public static void bubbleSort(int[] a){
        for(int i = 0; i<a.length; i++){
            boolean sorted= true;
            for(int j = 0; j<a.length-1-i; j++){
                if(a[j]>a[j+1]){
                    sorted = false;
                    int temp = a[j];
                    a[j] = a[j+1];
                    a[j+1] = temp;
                }
            }
            if(sorted){
                break;    //所有数已经有序,可退出循环
            }
        }
    }

    /** *插入排序 *1.从第一元素,将第一个元素归为已排序集合A *2.取出下一个元素temp,在已经排序的元素集合中中从后向前遍历 *3.比较当前元素与temp的大小,若temp元素小于当前元素,则当前元素后移,否则将temp插入当前元素之后 *********************** * 复杂度分析 * 最优情况,数组已排好序,复杂度O(n) * 平均时间复杂度,O(n^2) */

    public static void insertionSort(int[] a) {
        int length = a.length;
        for (int i = 1; i < length; i++) {
            int temp = a[i];
            int j;
            for (j = i; j >0 && temp<a[j-1]; j--) {
                a[j] = a[j-1];
            }
            a[j] = temp;
        }
    }

    /** * 选择排序 *每次遍历从未排序数组中选出最小值放到已排序数组的末尾 * ************** * 复杂度分析 * 需要完整进行两次遍历,时间复杂度O(n^2) */


    public static void selectionSort(int[] a) {
        int length = a.length;
        for (int i = 0; i < length; i++) {
            int min = i;
            for (int j = i + 1; j < length; j++) {
                if (a[j]-a[min]< 0) {
                    min = j;
                }
            }
            int temp = a[min];
            a[min] = a[i];
            a[i] = temp;
        }
    }

    /** * 希尔排序 * 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本,希尔排序是非稳定排序算法 * 步上的选择是希尔排序的重要组成部分 * ********** * 算法复杂度和步长的选择相关,详细可参阅维基百科,希尔排序在小数组中比快速排序和堆排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢 */
    public static void shellSort(int[] a){
        int gap = 1, i, j, len = a.length;
        int temp;
        while(gap<len/3) {
            gap = gap * 3 + 1;   //1,4,7,10,13
        }
        for(;gap>0;gap/=3){
            for(i=gap;i<len;i++){
                temp =a[i];
                for(j = i-gap;j>=0&&a[j]>temp;j-=gap){
                    a[j+gap] = a[j];
                }
                a[j+gap] = temp;
            }
        }

    }

    /* 堆树的定义如下: (1)堆树是一颗完全二叉树; (2)堆树中某个节点的值总是不大于或不小于其孩子节点的值; (3)堆树中每个节点的子树都是堆树。 当父节点的键值总是大于或等于任何一个子节点的键值时为最大堆。 当父节点的键值总是小于或等于任何一个子节点的键值时为最小堆。如下图所示,左边为最大堆,右边为最小堆。 */

    /** *1.将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无序区; *2.将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n]; *3.由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将堆顶R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。 * ********** * 利用堆排序可以很容易地从无序中选择最大记录(大堆排序)或最小记录(小堆排序) * ********** * 复杂度分析: * 时间复杂度:o(nlogn) ,最优时间复杂度o(nlogn),平均时间复杂度o(nlogn) */

    public static void heapSort(int[] a){
        int len = a.length;
        int temp;
        for (int i = 0;i<len;i++){
            buildHeap(a,len-i);
            temp = a[0];    //取出堆顶(最大数)
            a[0] = a[len-i-1];
            a[len-i-1] = temp;
        }
    }

    //最后一个非叶子节点索引是(size-2)/2
    public static void buildHeap(int[] a,int size){
        int leftChild;
        int rightChild;
        int temp;
        for(int i=(size-2)>>1; i>=0; i--){
            leftChild = (i<<1)+1;
            rightChild = (i<<1)+2;
            if((rightChild>=size||a[rightChild]<a[leftChild])&&a[i]<a[leftChild]){  //没有右孩子节点
                temp = a[i];
                a[i] = a[leftChild];
                a[leftChild] = temp;
            }else if(rightChild<size&&a[rightChild]>a[i]){
                temp = a[i];
                a[i] = a[rightChild];
                a[rightChild] = temp;
            }
        }
    }

    /** *归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 *************** * 算法复杂度: * 时间复杂度:O(nlogn),最优时间复杂度:O(n),平均时间复杂度:O(nlogn),空间复杂度O(n) */

    //先看合并算法,a,b合并到c ,a[first,mid] b(mid,last]
    public static void mergeArray(int[] a, int first, int mid, int last){
        int i = first, j = mid+1 ,k=0;
        int[] temp =new int[last-first+1];
        while(i<=mid&&j<=last){
            if(a[i]>a[j]){
                temp[k++] = a[j++];
            }else{
                temp[k++] = a[i++];
            }
        }
        while(i<=mid){
            temp[k++] = a[i++];
        }
        while(j<=last){
            temp[k++] = a[j++];
        }
        int len = temp.length;
        for(k = 0;k<len;k++){
            a[first+k] = temp[k];
        }
    }

    //再看分治算法
    public static void mergeSort(int[] a){
        mergeSort(a,0,a.length-1);
    }

    public static void mergeSort(int[] a,int first,int last){
        if(first<last){
            int mid = (first+last)>>1;
            mergeSort(a,first,mid);
            mergeSort(a,mid+1,last);
            mergeArray(a,first,mid,last);
        }
    }

    /** * 快速排序 *1.从数列中挑出一个元素,称为"基准"(pivot), *2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。 *3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。 */
    public static void quickSort(int[] a){
        quickSort(a,0,a.length-1);
    }

    private static void quickSort(int[] a,int lo, int hi){
        if(hi<=lo){
            return;
        }
        int i = partition(a, lo, hi);
        quickSort(a, lo, i - 1);
        quickSort(a, i + 1, hi);
    }


    private static int partition(int[] a,int lo, int hi){
        int i = lo, j=hi;
        int pivot = a[lo];
        int temp;
        while(true) {
            while (i<j) {
                if(a[j]<=pivot){
                    a[i] = a[j];
                    break;
                }
                j--;
            }
            while(i<j){
                if(a[i]>pivot){
                    a[j] = a[i];
                    break;
                }
                i++;
            }
            if(i>=j){
                a[i] = pivot;
                break;
            }
        }
        return i;  //返回基准位置
    }


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