七种排序的实现


1. 冒泡排序

时间复杂度:最好O(n),平均和最坏情况O(n2)
空间复杂度:O(1)
稳定排序
原理:从第一个元素开始,依次比较相邻两个元素,如果前者比后者大,那么就交换者两个元素,然后处理下一组,依次类推,直到排序完成。
实现:

public void bubbleSort(int[] arr){
    boolean isChanged = false;
    for(int i = 0; i < arr.length - 1; i++){
        isChanged = false;
        for(int j = 0; j < arr.length - 1 - i; j++){
            if(arr[j] > arr[j+1]){
                int tmp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
                isChanged = true;
            }
        }
        if(!isChanged) break; //本次没有发生交换,说明已经排好序了
    }
}

2. 选择排序

时间复杂度:最好、平均和最坏情况O(n2)
空间复杂度:O(1)
不是稳定排序
原理:从第一个元素开始,每次逐一扫描选择未排序部分的最小值,排在已排序部分后面,然后从下一个位置开始,继续进行相同的操作,直到排序完成。
实现:

/**
* 选择排序
*/
public static void sort(int[] arr){
    //判断arr是否为空
    if(arr == null) return;
    int minIndex;
    for(int i = 0; i < arr.length - 1; i++){
        minIndex = i;
        for (int j = i + 1; j < arr.length; j++){
            if (arr[j] < arr[minIndex]){
                minIndex = j;
            }
        }
        if (minIndex != i){               //最小值不是当前值,需要交换
            int tmp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = tmp;
        }
    }
}

3. 快速排序

时间复杂度:最好、平均情况O(nlogn),最坏情况O(n2)
空间复杂度:平均情况O(logn),最坏情况O(n)
不是稳定排序
原理:每次选择一个数,将数组按照这个数分成左右两个部分,右边的比它大,左边的比他小然后对左右两部分分别进行同样的操作,直到数组排序完成
实现:

public static void sort(int[] arr){
    sortCore(arr, 0, arr.length - 1);
}

/**
 * @param arr 排序的数组
 * @param start 开始位置
 * @param end 结束位置
 */
private static void sortCore(int[] arr, int start, int end) {

    int poiv = partion(arr, start, end);
    if (poiv > start){
        sortCore(arr, start, poiv - 1);
    }
    if (poiv >= start && poiv < end){
        sortCore(arr, poiv + 1, end);
    }

}

private static int partion(int[] arr, int start, int end) {

    int tmp = arr[start];

    while (start < end){
        while (start < end && arr[end] >= tmp) end--;

        if (start < end) {
            arr[start] = arr[end];
        }

        while (start < end && arr[start] < tmp) start++;

        if (start < end){
            arr[end] = arr[start];
        }
    }

    arr[start] = tmp;

    return start;
}

4. 归并排序

时间复杂度:最好、平均和最坏情况O(nlogn)
空间复杂度:O(n)
稳定排序
原理:首选将要排序的数组对半分,对各自部分进行排序。每部分继续进行相同的操作,直至最底层。然后合并两个相邻的部分,直到所有元素都排序完成
实现:

public static void sort(int[] arr){
  //创建数组,辅助排序
  int[] copy = new int[arr.length];
  sortCore(arr, copy, 0, arr.length - 1);
}

/**
 * 归并排序核心实现
  * @param arr 排序的数组
  * @param copy 辅助空间
  * @param start 开始位置
  * @param end 结束位置
  * @param offset 索引相对于原数组的偏移
  */
private static void sortCore(int[] arr, int[] copy, int start, int end) {
    if (start == end) {
        copy[start] = arr[start];
 return;  }

    int mid = (end - start) / 2 + start;

  //分成两部分,递归
  sortCore(arr, copy, start, mid);
  sortCore(arr, copy, mid + 1, end);

  //合并两个部分,将合并结果存入
  int forward = mid;
 int behand = end;

 int last = end;

 while (forward >= start && behand > mid){
        if (copy[forward] > copy[behand]){
            arr[last --] = copy[forward --];
  }else {
            arr[last --] = copy[behand --];
  }
    }

    while (forward >= start){
        arr[last --] = copy[forward --];
  }

    while (behand > mid){
        arr[last --] = copy[behand --];
  }

    //拷贝到copy数组
  for (int i = start; i <= end; i++){
        copy[i] = arr[i];
  }

}

5. 插入排序

时间复杂度:最好O(n),平均和最外情况O(n2)
空间复杂度:O(1)
稳定排序
原理:从数组第一个元素开始,依次比较前面已经排序的部分,插入合适的位置,前面排序部分比当前值大的部分向后移动一个。
实现:

public static void sort(int[] arr){
    int tmp;  //每次排序,存储当前的值
    for(int i = 1; i < arr.length; i++){
        tmp = arr[i]; //保存当前值
        int j;
        for (j = i; j >= fromIndex && tmp < arr[j - 1]; j --){ //遇到比当前值大的元素,则元素后移一位
            arr[j] = arr[j-1];
        }
        arr[j] = tmp; |
    }
}

6. 希尔排序

时间复杂度:平均情况O(n1.25)
空间复杂度:O(1)
不是稳定排序
原理:将无序数组分割为若干个子序列,子序列不是逐段分割的,而是相隔特定的增量的子序列,对各个子序列进行插入排序;然后再选择一个更小的增量,再将数组分割为多个子序列进行排序……最后选择增量为1,即使用直接插入排序,使最终数组成为有序。
实现:

public static void sort(int[] arr){
    //checkRange(arr.length, fromIndex, toIndex);
    int adder = arr.length / 2;  //增量
    while (adder > 0){
        //从adder开始,每次排序均与前面的adder(当adder是1时就是插入排序)处的元素比较
        for (int i = adder ; i < arr.length; i++){
            int j;
            int tmp = arr[i];
            for (j = i; j >= adder && tmp < arr[j - adder]; j = j - adder){
                arr[j] = arr[j - adder];
            }
            arr[j] = tmp;
        }
        adder /= 2;
    }
}

7. 堆排序

时间复杂度:最好、平均和最坏情况均为O(nlogn)
空间复杂度:O(1)
不是稳定排序
原理:建立初始堆,从最后一个非叶结点开始,往前遍历,判断以该节点的开始的堆是否是符合,不符合则调整需要建立大顶堆,每次将子节点中较大地一个数往上移动,直到叶结点(堆:结点n的父节点为(n-1)/ 2,其左右子节点为2*n+1和2*n+2大根堆为根结点的值大于等于左右子结点的值),然后依次将堆顶值与为排序的最后一个值交换,然后调整前面的值为大顶堆,每次将最大的值排好序。
实现:

/**
 * 堆排序
 */
public static void sort(int[] arr){
    //建立初始堆,从最后一个非叶结点开始,往前遍历,判断以该节点的开始的堆是否是符合,不符合则调整
    //需要建立大顶堆,每次将子节点中较大地一个数往上移动,直到叶结点
    //节点n的父节点为(n-1)/ 2,其左右子节点为2*n+1和2*n+2
    //大根堆为根结点的值大于等于左右子结点的值
    for (int i = (arr.length - 1 - 1) / 2; i >= 0; i--){
        adjustHeap(arr, i, arr.length-1);
    }
    //依次将堆顶值与为排序的最后一个值交换,然后调整前面的值为大顶堆
    for (int i = arr.length - 1; i >= 1; i--){
        //交换
        arr[0] ^= arr[i];
        arr[i] ^= arr[0];
        arr[0] ^= arr[i];
        //调整
        adjustHeap(arr, 0, i - 1);
    }

}

/**
 * 调整为大顶堆
 * @param arr
 * @param i 以i为堆的堆顶
 * @param last 堆顶的最后一个结点的索引
 */
private static void adjustHeap(int[] arr, int i, int last) {
    //建立以i结点为根的堆,判断子结点是否大于该节点,并将较大地值拷贝,然后继续判断
    int tmp = arr[i];
    for (int j = i * 2 + 1; j <= last; j = j * 2 + 1){
        //获得左右子树中较大的一个数的下标
        if (j < last && arr[j] < arr[j+1]) j++;  //存在右子结点且右子结点较大
        if (tmp >= arr[j]) break;  //根结点比较大,则完成
        //将较大的值作为根
        arr[i] = arr[j];
        i = j;   //继续往下判断,j的位置的值是最初的根结点
    }
    arr[i] = tmp;  //最后确定的位置,没有子结点或者比子结点的值大;
}
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值