时间复杂度为O(n^2)的:

插入、选择(不稳定)、冒泡

时间复杂度为O(nlogn)的:

堆(不稳定),快速(不稳定),归并


一、插入排序

将数组中的所有元素依次跟前面已经排好的元素相比较,如果选择的元素比已排序的元素小,则交换,直到全部元素都比较过为止。
它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
public static void 插入排序(int[] arr)
{
    for(int i=0;i<arr.length-1;i++)
    {
        for(int j=i+1;j>0;j--)
        {
            if(arr[j-1]>arr[j])
            {
                swap(arr,j-1,j);
            }
        }
    }
    System.out.println(Arrays.toString(arr));
}

O(n^2)   稳定


二、选择排序

每次都在剩余的数组中找到最小值,把找到的最小值和头节点值交换,重复arr.length轮
最坏情况每次都必须换一下,都坏O(n^2)
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 
public static void 选择排序(int[] arr)
{
    for(int i=0;i<arr.length-1;i++)
    {
        int minIndex=i;
        for(int j=i+1;j<arr.length;j++)
        {
            if(arr[j]<arr[minIndex])
            {
                minIndex=j;
            }
        }
        if(minIndex != i)
        {
            swap(arr,minIndex,i);
        }
    }
    System.out.println(Arrays.toString(arr));
}

O(n^2), 不稳定

序列5 8 5 2 9, 这个在执行选择排序的时候,第一遍,肯定会将array[0]=5,交换到2所在的位置,也就是 2 8 5 5 9,那么很显然,之后的排序我们就会发现,array[2]中的5会出现在原先的array[0]之前,所以选择排序不是一个稳定的排序


三、冒泡排序

不解释,你学的第一个算法

public static  void 冒泡排序(int[] arr)
{
    for(int i=arr.length-1;i>0;i--) //每次需要排序的长度
    {
        for(int j=0;j<i;j++)
        {
            if(arr[j]>arr[j+1])
                swap(arr,j,j+1);
        }
    }
    System.out.println(Arrays.toString(arr));
}

O(n^2) , 稳定


四、快速排序

递归的思想,每次选择一个元素,左边的数组都小于选定元素,右边的数组都大于选定元素;

public static void 快速排序(int[] arr,int low,int high)
{
    if(arr.length<=0) return;
    if(low>=high) return;
    int left = low;
    int right = high;

    int temp = arr[low];
    while(left<right)
    {
        while(left<right && arr[right]>temp)
            right--;

        while(left<right && arr[left]<=temp)
            left++;

        swap(arr,left,right);
    }
    swap(arr,left,low);
    System.out.println("Sorting:" + Arrays.toString(arr));
    快速排序(arr,low,left-1);
    快速排序(arr,left+1,high);
}


https://www.youtube.com/watch?v=T258-Umoz9A

O(nlogn)   不稳定



五、归并排序

递归版本:

public static void  mergeSort1(int[] arr,int l, int r)
{
    if(l<r)
    {
        int m=l+(r-l)/2;
        mergeSort1(arr,l,m);
        mergeSort1(arr,m+1,r);

        merge(arr,l,m,r);
    }
}

public static void merge(int[] arr,int l,int m,int r)
{
    int n1 = m-l+1; //左子数组的长度
    int n2=r-m; //右子数组的长度
    int[] L=new int[n1];
    int[] R=new int[n2];

    for(int i=0;i<n1;i++)
        L[i] = arr[l+i];
    for(int j=0;j<n2;j++)
        R[j] = arr[m+1+j];

    int i=0,j=0,k=l;

    while(i<n1 && j<n2)
    {
        if(L[i]<=R[j])
        {
            arr[k] = L[i];
            i++;
        }else{
            arr[k]=R[j];
            j++;
        }
        k++;
    }

    while(i<n1)
    {
        arr[k] = L[i]; k++; i++;
    }

    while(j<n2)
    {
        arr[k] = R[j];k++; j++;
    }
}

O(nlogn) 稳定



六、堆排序

堆排序的思想跟选择排序类似,但是如何快速找到最小(最大)元素?——》最大最小堆
public static void heapify(int[] arr,int n,int i)
{
    int largest = i;
    int l=2*i+1;//左子树的位置
    int r=2*i+2;//右子树的位置

    if(l<n && arr[l]>arr[largest])
        largest=l;

    if(r<n && arr[r]>arr[largest])
        largest=r;
    if(largest != i)
    {
        swap(arr,i,largest);
        heapify(arr,n,largest);
    }
}

public static void 堆排序(int[] arr)
{
    int n=arr.length;
    for(int i=n/2-1;i>=0;i--)
        heapify(arr,n,i);

    for(int i=n-1;i>=0;i--)
    {
        swap(arr,0,i);
        heapify(arr,i,0);
    }
}

O(nlogn)  不稳定


堆分为大顶堆和小顶堆;大顶堆:父节点的值一定大于它的左右节点的值。
堆排序的过程:
1.构造一个大顶堆,取堆顶数字;
2. 再将剩下的数字构造一个大顶堆,取堆顶的数字
3.重复上面的操作,直到取完堆中的数字,最终得到一个从大到小排序的序列