十大排序算法总结

243 阅读4分钟

排序算法总结

冒泡排序

冒泡排序的复杂度

平均时间复杂度:O(n2)

最好时间复杂度O(N)

空间负责度O(1)

稳定排序

冒泡排序的核心思路:找最大的值

1.循环比较相邻的两个数的值,如果B>A进行转换(找最大的值)

2.每次找到第n-i的最大的值所以第二个循环的长度是(len-i)

优化方案

1.已经有序的队列,可以添加标识符如果一次循环比较都是符合顺序的数据就确定当前数组是按顺序排列的

代码


static int [] nums={2,3,9,12,3,2,5,8,3};

/**
  * 冒泡排序
  */
static void toBubleSort(){
    //不具备排序的条件
    if(nums.length<=1){
        return;
    }
    //默认有序
    boolean flag;
     for(int i=1;i<nums.length;i++){
          flag=true;
         for(int j=0;j< nums.length-i;j++){
            //进行转换
           if(nums[j]>nums[j+1]){
               int temp=nums[j];
               nums[j]=nums[j+1];
               nums[j+1]=temp;
               //进行过排序
               flag=false;
           }
           if(flag){
            break;
           }
         }

     }

 }

选择排序

复杂度

平均时间复杂度O(n2)

最好时间复杂度O(n)

空间复杂度O(1)

稳定排序

选择排序核心:查询当前列表区间最小(最大)值进行交换

进行第i次遍历找到最小的值进行最小值跟i交互操作

代码示例

static int [] nums={2,3,9,12,3,2,5,8,3};

static void selectSort(){

    int index;
    for(int i=0;i<nums.length;i++){
          index=i;
        for(int j=i;j<nums.length;j++){
          if(nums[j]<nums[index]) {
              index = j;
          }
        }
        //找到最小值
        if(index!=i){
            int temp=nums[index];
            nums[index]=nums[i];
            nums[i]=temp;
        }

    }

}

插入排序

复杂度

时间复杂度O(n2)

空间复杂o(1)

稳定排序

插入排序的核心:对集合进行遍历对第i个位置首先记录当前的值然后拿记录的值一直向前比较如果小于的情况下就进行移动(0-i的值都是有序的)

代码示例

 /**
  * 插入排序
  */
static void insertSort(){
     for(int i=1;i<nums.length;i++){
        //记录要插入的值
        int tempNum=nums[i];

        //记录下要移动的位置
        int j=i;
        while (j>0&&tempNum<nums[j-1]){
            nums[j]=nums[j-1];
            j--;
        }
        if(j!=i){
            nums[j]=tempNum;
        }

     }

 }

希尔排序(插入排序的升级)

复杂度分析

平均时间复杂度O(nlogN)

空间复杂的O(1)

最好时间复杂度O(nlogN)

非稳定排序

希尔排序的核心思想,让集合变得更有序再进行排序提高排序速度

排序步骤

让集合变得更有序的方式

1.最外层循环进行除2递减(最好步长=1)

2.第二层循环开始的位置为外层step所移动的值,进行++操作,让后面的值与前面的值准备进行比较

3.开始比较和插入排序

代码示例

static void xirSort(){
   static int [] nums={2,3,9,12,3,2,5,8,3};
   int len=nums.length;
   int temp;
    for(int step=len/2;step>0;step/=2){

        for(int i=step;i<len;i++){
            temp=nums[i];
           int j=i-step;
            while (j>0&&nums[j]>temp){
                nums[j+step]=nums[j];
                j-=step;
            }
            nums[j+step]=temp;

        }

    }
}

归并排序

核心思想:通过分治思想对集合就行余2的递归拆分再吧拆分成小的组进行排序一直到整个集合排序好。

复杂度

时间复杂度O(nlogN)

空间复杂的O(nlongN)

稳定排序

例子

static void sort(int begin,int end){
    if(end-begin<2){
        return;
    }
    int mid=end+begin>>1;
    sort(begin,mid);
    sort(mid,end);

    merge(begin,mid,end);
}


static void merge(int begin ,int mid,int end){

    int li=0,le=mid-begin;
    leftArray=new int[le];
    int ri=mid,re=end;
    int ai=begin;
    //备份左边数组
    for(int i=li;i<le;i++){
        leftArray[i]=nums[begin+i];
    }

    //如果左边还没有结束
    while (li<le){
        if(ri<re&&nums[ri]<leftArray[li]){
          nums[ai++]=nums[ri++];
        }else{
          nums[ai++]=leftArray[li++];
        }
    }

}

归并排序

归并排序采用分治思想不断的将排序集合进行分割直至不能再分割,然后对分割的集合进行排序,这个过程结束当前序列就是有序集合。

static void sort(int begin,int end){

    if(end-begin<2){
        return;
    }

    int mid=(begin+end)>>1;
    sort(begin,mid);
    sort(mid,end);
    merge(begin,mid,end);
}

private static void merge(int begin,int mid, int end) {

    int lt=0;
    int l=begin;
    int le=mid-begin;
    int r=mid;
    int re=end;
    int[] leftArray=new int[le];
    for(int i=lt;i<le;i++){
        leftArray[i]=nums[begin+i];
    }
    //左边还没有结束
    while (lt<le){
       if(r<re&&nums[r]<leftArray[lt]){
           nums[l++]=nums[r++];
       }else{
           nums[l++]=leftArray[lt++];
       }
    }

}

快排

快拍也是采用分治思想,1.通过一个轴点元素对序列进行分割,一边小于等于轴点元素,一边大于轴点元素,以轴点当做中心元素对两边序列进行上面1的操作重复下来序列成为有序序列

public static void quictSort(int begin,int end){

    if(end-begin<2)
        return;

    int mid=pivotIndex(begin,end);

    quictSort(begin,mid);
    quictSort(mid+1,end);

}

private static int pivotIndex(int begin,int end) {

    int povit=nums[begin];
    end--;
    while (end>begin){

        while (end>begin) {
            if (povit < nums[end]) {
                end--;
            } else {
                nums[begin++] = nums[end];
                  break;
            }
        }

        if(end>begin) {

            if (povit > nums[begin]) {
                begin++;
            } else {
                nums[end--]=nums[begin];
                break;
            }
        }

    }


    nums[begin]=povit;
    return begin;

}

堆排序

堆排序的核心思想,首先对序列进行建堆,然后对堆上的元素0的位置和当前堆尾进行数据转换并且堆的总数-1,重新再对堆0进行堆排序(目的是把最大值放到堆顶)继续对堆0和堆位数据转换,重复操作到堆内的元素不大于1位置。

private static int headSize;
private static void sort() {
    headSize= nums.length;

    //建堆
    for(int i=((headSize>>1)-1);i>=0;i--){
        sfitDown(i);
    }
    while (headSize>1){
        //交换堆顶元素的位置  堆-1
        swap(0,--headSize);
        //对0位置进行siftDown(恢复堆的性质)
        sfitDown(0);
    }
}

private static void sfitDown(int index) {

     int temple=nums[index];
     //当前堆的中间值
     int half=headSize>>1;

     while (half>index){
         int childIndex=(index << 1)+1;

         int child=nums[childIndex];

         int rightIndex=childIndex+1;

         if(rightIndex<headSize&&child<nums[rightIndex]){
             child=nums[childIndex=rightIndex];
         }

         if(temple>=child)
             break;
         nums[index]=child;
         index=childIndex;
     }
     nums[index]=temple;

}

计数排序

计算排序核心是通过空间去优化时间,通过序列的数据找到最小值和最大值(计算出需要开辟多大的空间),对序列进行遍历,找到空间下标对应的index进行++,然后对空间序列进行遍历取出index的值>1元素,就是有序的了。

static void countingSort(){


    //首先找到最大,最小值
    int minNum=Integer.MAX_VALUE;
    int maxNum=Integer.MIN_VALUE;
    for (int i=0;i<nums.length;i++){
        if(minNum>nums[i]){
            minNum=nums[i];
        }
        if(maxNum<nums[i]){
            maxNum=nums[i];
        }
    }


    //创建区间(最大,最小值)集合
    int [] templeNums=new int[maxNum-minNum+1];

    //区间赋值
    for (int i=0;i<nums.length;i++){
        templeNums[nums[i]-minNum]++;
    }

    int tempIndex=0;
    //取值排序
    for(int i=0;i<templeNums.length;i++){

        if(templeNums[i]>0){
            while (templeNums[i]>0) {
                nums[tempIndex] =i+minNum;
                --templeNums[i];
                 tempIndex++;
            }
        }

    }


}

桶排序

设定桶的大小,对序列进行取区域值( 桶的数量)然后进行对序列放入对应桶,最后遍历桶进行对桶内元素排序。

public static int[] bucketSort(int[] arr, int bucketSize) {
    if (arr.length == 0) {
        return arr;
    }

    int minValue = arr[0];
    int maxValue = arr[0];
    for (int value : arr) {
        if (value < minValue) {
            minValue = value;
        } else if (value > maxValue) {
            maxValue = value;
        }
    }

    int bucketCount = (int) Math.floor((maxValue - minValue) / bucketSize) + 1;
    int[][] buckets = new int[bucketCount][0];

    // 利用映射函数将数据分配到各个桶中
    for (int i = 0; i < arr.length; i++) {
        int index = (int) Math.floor((arr[i] - minValue) / bucketSize);
        buckets[index] = arrAppend(buckets[index], arr[i]);
    }

    int arrIndex = 0;
    for (int[] bucket : buckets) {
        if (bucket.length <= 0) {
            continue;
        }
        // 对每个桶进行排序,这里使用了插入排序
        bucket = InsertSort.insertSort(bucket);
        for (int value : bucket) {
            arr[arrIndex++] = value;
        }
    }

    return arr;
}
/**
 * 自动扩容,并保存数据
 *
 * @param arr
 * @param value
 */
private static int[] arrAppend(int[] arr, int value) {
    arr = Arrays.copyOf(arr, arr.length + 1);
    arr[arr.length - 1] = value;
    return arr;
}

桶排序

桶排序首先需要定义桶的数量,对桶进行设置值的区间,然后遍历数据放入对应桶中,对桶内数据进行排序。

public static int[] bucketSort(int[] arr, int bucketSize) {
    if (arr.length == 0) {
        return arr;
    }

    int minValue = arr[0];
    int maxValue = arr[0];
    for (int value : arr) {
        if (value < minValue) {
            minValue = value;
        } else if (value > maxValue) {
            maxValue = value;
        }
    }

    int bucketCount = (int) Math.floor((maxValue - minValue) / bucketSize) + 1;
    int[][] buckets = new int[bucketCount][0];

    // 利用映射函数将数据分配到各个桶中
    for (int i = 0; i < arr.length; i++) {
        int index = (int) Math.floor((arr[i] - minValue) / bucketSize);
        buckets[index] = arrAppend(buckets[index], arr[i]);
    }

    int arrIndex = 0;
    for (int[] bucket : buckets) {
        if (bucket.length <= 0) {
            continue;
        }
        // 对每个桶进行排序,这里使用了插入排序
        bucket = InsertSort.insertSort(bucket);
        for (int value : bucket) {
            arr[arrIndex++] = value;
        }
    }

    return arr;
}
/**
 * 自动扩容,并保存数据
 *
 * @param arr
 * @param value
 */
private static int[] arrAppend(int[] arr, int value) {
    arr = Arrays.copyOf(arr, arr.length + 1);
    arr[arr.length - 1] = value;
    return arr;
}

基数排序

基数排序对序列中每个数字的位数进行排序(由小到大,个/十/百...)并且取排序后得值此操作。

public static int[] bucketSort(int[] arr, int bucketSize) {
    if (arr.length == 0) {
        return arr;
    }

    int minValue = arr[0];
    int maxValue = arr[0];
    for (int value : arr) {
        if (value < minValue) {
            minValue = value;
        } else if (value > maxValue) {
            maxValue = value;
        }
    }

    int bucketCount = (int) Math.floor((maxValue - minValue) / bucketSize) + 1;
    int[][] buckets = new int[bucketCount][0];

    // 利用映射函数将数据分配到各个桶中
    for (int i = 0; i < arr.length; i++) {
        int index = (int) Math.floor((arr[i] - minValue) / bucketSize);
        buckets[index] = arrAppend(buckets[index], arr[i]);
    }

    int arrIndex = 0;
    for (int[] bucket : buckets) {
        if (bucket.length <= 0) {
            continue;
        }
        // 对每个桶进行排序,这里使用了插入排序
        bucket = InsertSort.insertSort(bucket);
        for (int value : bucket) {
            arr[arrIndex++] = value;
        }
    }

    return arr;
}
/**
 * 自动扩容,并保存数据
 *
 * @param arr
 * @param value
 */
private static int[] arrAppend(int[] arr, int value) {
    arr = Arrays.copyOf(arr, arr.length + 1);
    arr[arr.length - 1] = value;
    return arr;
}