一、插入排序
1.1基本思想
 
1.2直接插入排序
 
 示例代码如下:
class Sort{
    public static void insertSort(int[] array){
        //排序完成条件
        for (int i = 1; i < array.length ; i++) {
            //用于比较大小
            int tmp = array[i];
            //j的起始位置
            int j =i-1;
            //单次比较的结束条件
            for(;j>=0;j--){
                if(array[j]>tmp){
                    array[j+1]=array[j];
                }else{
                    //由于前面的元素经排序后已经有序,故直接将tmp的值放入对应位置后,j无需在遍历前面的元素进行比较,
                    //直接跳出循环即可。
                    array[j+1]=tmp;
                    break;
                }
            }
            array[j+1]=tmp;
        }
    }
}
 
 
1.3希尔排序(缩小增量排序)

思路有了,代码如何实现?如何分组?

代码如下:
 public static void shellSort(int[] array){
        int gap=array.length;
        while(gap>1){
            gap/=2;
            shell(array,gap);
        }
    }
    private static void shell(int[] array, int gap) {
        for (int i = gap; i <array.length ; i++) {
            //增量为i++,使排序过程分组交替进行
            int tmp = array[i];
            int j = i-gap;
            for (; j >=0 ; j-=gap) {
                if(array[j]>tmp){
                    array[j+gap]=array[j];
                }else{
                    array[j+gap]=tmp;
                    break;
                }
            }
            array[j+gap]=tmp;
        }
    }
 
二、选择排序
2.1直接选择排序
2.1.1基本思想

2.2.2代码实现
图示:

代码演示:
public static void selectSort(int[] array){
        for (int i = 0; i < array.length; i++) {
            //每轮比较默认i下标的值为最小值
            int minIndex=i;
            for (int j =i+1; j <array.length ; j++) {
                if(array[j]<array[minIndex]){
                    minIndex=j;
                }
            }
            int tmp=array[i];
            array[i]= array[minIndex];
            array[minIndex]=tmp;
        }
    } 
  2.2堆排序
堆排序思路在前面已经了解到,详情见文章中“堆的应用”部分。
https://blog.csdn.net/zhakakqns/article/details/141531282?spm=1001.2014.3001.5501
https://blog.csdn.net/zhakakqns/article/details/141531282?spm=1001.2014.3001.5501
 public static void heapSort(int[] array){
        createHeap(array);
        int end=array.length-1;
        while(end>0) {
            int tmp = array[0];
            array[0] = array[end];
            array[end] = tmp;
            siftDown(array, 0, end);
            end--;
        }
    }
   private static void createHeap(int[] array){
        //创建堆
       for (int parent = (array.length-1-1)/2; parent >=0 ; parent--) {
           siftDown(array,parent,array.length);
       }
   }
   private static void siftDown(int[] array,int parent,int length){
        //向下调整
        int child = parent+1;
        while(child<length){
            if(child+1<length && array[child]<array[child+1]){
                child++;
            }
            if(array[child]>array[parent]){
                int tmp=array[parent];
                array[parent]=array[child];
                array[child]=tmp;
                parent=child;
                child=2*parent+1;
            }else{
                break;
            }
        }
   } 
 
三、交换排序
3.1冒泡排序
3.1.1普通冒泡排序

public static void bubbleSort(int[] array){
       for (int i = 0; i <array.length-1 ; i++) {
           for (int j = 0; j < array.length-i-1; j++) {
               if(array[j]>array[j+1]){
                   int tmp=array[j];
                   array[j]=array[j+1];
                   array[j+1]=tmp;
               }
           }
       }
   } 
3.1.2冒泡排序优化
如果一组数据本身有序,或者在经过几趟冒泡排序后已经有序,就可以直接退出,不用继续执行代码。
 public static void bubbleSort(int[] array){
       for (int i = 0; i <array.length-1 ; i++) {
           boolean flg=false;//用于判断是否发生交换,若没有交换,则已经有序直接退出
           for (int j = 0; j < array.length-i-1; j++) {
               if(array[j]>array[j+1]){
                   int tmp=array[j];
                   array[j]=array[j+1];
                   array[j+1]=tmp;
                   flg=true;//发生交换,置为true
               }
           }
           if(!flg){
               break;
           }
       }
   } 
!!!一般我们所说的冒泡排序的时间复杂度是指未优化过的冒泡排序。
3.2快速排序
3.2.1快速排序
基本思想:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
3.2.1.1Hoare版


代码实现:
 public static void quickSort(int[] array){
        quick(array,0,array.length-1);
   }
   private static void quick(int[] array,int start,int end){
        if(start>=end){
            return;
        }
           
        //划分区域
        int pivot = partition(array,start,end);
        //递归左边
        quick(array,start,pivot-1);
        //递归右边
        quick(array,pivot+1,end);
   }
    private static int partition(int[] array, int left, int right){
        //以left下标的值作为基准
        int key = left;
        while(left<right) {
            //如果数据为3,4,5,6那么right一直--也找不到比3大的数据
            //,会导致越界,因此必须右left<right这个条件
            while (left<right && array[right] >= array[key]) {
                right--;
            }
            while (left<right && array[left] <= array[key]) {
                left++;
            }
            int tmp = array[right];
            array[right] = array[left];
            array[left] = tmp;
        }
        int tmp = array[left];
        array[left]=array[key];
        array[key]=tmp;
        return left;
    } 
3.2.1.2挖坑法

递归的思路和Hoare法一样,也就是说只需要修改Hoare法的partition方法即可。
代码如下:
private static int partition(int[] array, int left, int right){
        int tmp = array[left];
        while(left<right) {
            while (left<right && array[right] >= tmp) {
                right--;
            }
            array[left] = array[right];
            while (left<right && array[left] <= tmp) {
                left++;
            }
            array[right] = array[left];
        }
        array[left] = tmp;
        return left;
    } 
3.2.2快速排序优化
当一组数据有序时,快速排序的时间复杂度会达到O(N^2),并且当数据量过多时还会导致栈溢出,因此我们右以下几种优化方法:
(1)三数取中法选key

下面是寻找中间大小数据的方法:

 private static int getMiddleNum(int[] array,int left,int right){
        int mid = (left+right)/2;
        if(array[left]<array[right]){
            if(array[mid]<array[left]){
                return left;
            }else if(array[mid]>array[right]){
                return right;
            }else{
                return mid;
            }
        }else{
           if(array[mid]>array[left]){
               return left;
           }else if(array[mid]<array[right]){
               return right;
           }else{
               return mid;
           }
        } 
(2)递归到小的子区间时,可以考虑使用插入排序 ,但是在使用插入排序时,应注意排序的范围
i要从start+1开始,当j<start时结束该轮插入。
代码如下:
 private static void quick(int[] array,int start,int end){
        if(start>=end){
            return;
        }
        //当数据小于10个时,使用直接插入排序
        if(end-start+1<10){
            insertSortRange(array,start,end);
            return;
        }
        int pivot = partition(array,start,end);
        
        quick(array,start,pivot-1);
        
        quick(array,pivot+1,end);
   }
    private static void insertSortRange(int[] array, int start, int end) {
        for (int i = start+1; i <=end ; i++) {
            int tmp=array[i];
            int j=i-1;
            for(;j>=start;j--){
                if(array[j]>tmp){
                    array[j+1]=array[j];
                }else{
                    array[j+1]=tmp;
                    break;
                }
            }
            array[j+1]=tmp;
        }
    }
 
3.2.3快速排序非递归
 
代码如下:
public static void quickNor(int[] array,int start,int end){
        //首先先用pivot将两个子数组的start,end放入栈中
        int pivot = partition(array,start,end);
        Stack<Integer> stack = new Stack<>();
        //如果pivot<=start+1,pivot>=end-1说明只剩下一个数据,则已经有序,不用再排序
          if(pivot>start+1){
              stack.push(start);
              stack.push(pivot-1);
          }
          if(pivot<end-1){
              stack.push(pivot+1);
              stack.push(end);
          }
          while(!stack.isEmpty()){
              end=stack.pop();
              start=stack.pop();
              pivot=partition(array,start,end);
              if(pivot>start+1){
                  stack.push(start);
                  stack.push(pivot-1);
              }
              if(pivot<end-1){
                  stack.push(pivot+1);
                  stack.push(end);
              }
          }
    } 
3.2.4快速排序总结
四、归并排序
 
  public static void mergeSort(int[] array){
        mergeSortTmp(array,0,array.length-1);
    }
    private static void mergeSortTmp(int[] array, int left, int right) {
        if (left >= right) {
            return;
        }
        int mid = (left+right)/2;
        mergeSortTmp(array,left,mid);
        mergeSortTmp(array,mid+1,right);
        //分解完毕,开始合并
        merge(array,left,mid,right);
    }
    private static void merge(int[] array, int left, int mid, int right) {
        //相当于合并连个有序数组
        int[] tmp=new int[right-left+1];
        int k=0;
        int s1=left;
        int e1=mid;
        int s2=mid+1;
        int e2=right;
        while(s1<=e1 && s2<=e2){
            if(array[s1]<=array[s2]){
                tmp[k++]=array[s1++];
            }else{
                tmp[k++]=array[s2++];
            }
        }
        while(s1<=e1){
            tmp[k++]=array[s1++];
        }
        while(s2<=e2){
            tmp[k++]=array[s2++];
        }
        for (int i = 0; i < k; i++) {
            array[i+left]=tmp[i];
        }
    } 
   4. 稳定性:稳定



















