# 排序算法

排序算法

复杂度比较
  • 改图摘自:菜鸟教程
    在这里插入图片描述

冒泡排序

思想
  • 每一轮从左到右,相邻元素比较,满足条件则互换位置。每一轮右侧冒出符合条件的一个元素。
  • 如果有n个数据,只需要比较n-1轮。
特点
  • 冒泡排序是稳定的,对于同样的元素相对位置是不会改变的。
例子
  • 对(7,10,4,6,3)排序

    第一趟:7,4,6,3,10

    第二趟:4,6,3,7,10

    第三趟:4,3,6,7,10

    第四趟:3,4,6,7,10

实现
@Test
public void test1(){
    // 定义一个数组
    List<Integer> list = Arrays.asList(1, 10, 3, 4, 6, 7, 8, 2, 3, 0);
    Object[] objects = list.toArray();
    int[] arr=new int[objects.length];
    for (int i = 0; i < objects.length; i++) {
        arr[i]= (int) objects[i];
    }
    // 冒泡法排序
    for (int i = 0; i < arr.length; i++) {
        // 定义临时变量并赋值为arr[0]
        int temp=arr[0];
        for (int j = 0; j < arr.length-1; j++) {
            if(arr[j]>arr[j+1]){
                temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }
        }
        System.out.println("第:"+i+":趟"+"========"+temp);
    }
    System.out.println("===========================");
    for (int i = 0; i < arr.length; i++) {
        System.out.println(arr[i]);
    }
}

选择排序

思想
  • 在一个长度为N的数组中,第一次遍历n-1个数找到最小的和第一个交换。
  • 第二次从下一个数开始遍历n-2个数,找到最小的数和第二个数交换。
  • 重复操作直到n-1次遍历最小的数和第n-1个数交换。
特点
  • 选择排序是不稳定的算法
例子
  • 对(7,10,4,6,3)排序

    第一趟:10,7,4,6,3

    第二趟:10,7,4,6,3

    第三趟:10,7,6,4,3

    第四趟:10,7,6,4,3

实现
// 选择排序
for (int i = 0; i < arr.length; i++) {
    // 假设第一个元素是最大的
    int max =arr[i];
    for (int j = i; j < arr.length; j++) {
        if(max<arr[j]){
            int temp=arr[j];
            arr[j]=max;
            max=temp;
        }
    }
    arr[i]=max;
}

快速排序

思想
  • 从数列中挑出一个元素作为基准。
  • 重新排列数列,把比基准小的放在基准前面,反之放在基准后面。
  • 通过递归调用把小于基准元素和大于基准元素的子序列进行排序。
  • 分治思想。
例子
  • 对(7,10,4,6,3)排序

    第一趟:3,10,4,6,7

    第二趟:3,10,4,6,7

    第三趟:3,6,4,10,7

    重复执行两边的

    ​ 3,4,6,7,10

特点
  • 平均性能好
  • 不稳定,初始序列有序或者基本有序时,时间复杂度下降
实现
@Test
public void test3(){
    // 定义一个数组
    List<Integer> list = Arrays.asList(1, 10, 3, 4, 6, 7, 8, 2, 3, 0);
    Object[] objects = list.toArray();
    int[] arr=new int[objects.length];
    for (int i = 0; i < objects.length; i++) {
        arr[i]= (int) objects[i];
    }
    // 快速排序:首先获得一个基准
    int low=0;
    int high=arr.length-1;
    // 定义key用于存放基准,理论上可以拿任何一个数作为基准
    int key=arr[low];
    for (int i : arr) {
        System.out.print(i);
    }
    System.out.println("排序前===================");
    unckSort(arr,low,high);
    for (int i : arr) {
        System.out.println(i);
    }
}

public static int getMiddle(int[] list, int low, int high) {
    // 数组的第一个值作为基准值(分界点或关键数据)
    int tmp = list[low];
    while (low < high) {
        while (low < high && list[high] >= tmp) {
            high--;
        }
        // 比基准值小的记录移到低端
        list[low] = list[high];
        while (low < high && list[low] <= tmp) {
            low++;
        }
        // 比基准值大的记录移到高端
        list[high] = list[low];
    }
    // 基准值记录到尾
    list[low] = tmp;
    // 返回基准值的位置
    return low;
}

public static void unckSort(int[] list,int low,int high) {
    if(low < high) {
        // 将list数组一分为二
        int middle = getMiddle(list,low,high);
        // 对低字表进行递归排序
        unckSort(list,low,middle-1);
        // 对高字表进行递归排序
        unckSort(list,middle+1,high);
    }
}

插入排序

直接插入排序
思想
  • 从第一个元素开始,如果后面的元素大于前面的元素,则标记该元素为待排序元素。
  • 从后面遍历已经排好序的元素,如果排好序的元素中最后一个大于待排序的元素,则往后移动有序队列中的这个元素,依次类推。当条件不满足时候,将待排序元素放到有序元素队列的最后面。
特点
  • 插入排序每次插入的位置都会大于或者等于前一个元素,所以为稳定排序。
例子
  • 排序(3,1,2,5,4)

    第一趟:1,3

    第二趟:1,2,3

    第三趟:1,2,3,5

    第四趟:1,2,3,4,5

实现一
@Test
public void test5(){
    // 无序数组
    int arr[]={3,1,2,5,4,7,9,5,2};
    int j; // 已排序列表下标
    int num; // 待排序元素
    for (int i = 1; i < arr.length; i++) {
        if (arr[i] < arr[i - 1]) {
            num = arr[i];
            // 赋值给待排序元素
            for (j = i - 1; j >= 0 && arr[j] > num; j--) {
                arr[j + 1] = arr[j];
                // 从后往前遍历已排序列表,逐个和待排序元素比较,如果已排序元素较大,则将它后移
            }
            arr[j + 1] = num;
            // 将待排序元素插入到正确的位置
        }
    }
    for (int i = 0; i < arr.length; i++) {
        System.out.println(arr[i]);
    }
}
实现二
public void sort(int[] arr) {
    // 从第二个元素开始
    for (int i = 1; i < arr.length; i++) {
        if (arr[i] < arr[i - 1]) {
            // 当前待排序元素为temp
            int temp = arr[i];
            int j = i;
            // 待排序元素和之前的每个元素做比较
            while (j >0 && temp < arr[j - 1]) {
                arr[j] = arr[j - 1];
                j--;
            }
            arr[j] = temp;
        }
    }
}
时间复杂度

最坏情况下,整个数组是倒序的复杂度为O(n^2),最好的情况下整个数组的顺序就是想要的结果,时间复杂度为O(n)


希尔排序(三层for循环)

思想

​ 是插入排序的一种,是对直接插入排序的一个优化。

  • 将待排序的数组元素按下标的一定增量分组,分成多个子序列,然后对各个子序列进行直接插入排序。
  • 缩减增量再排序,直到增量为1时,进行最后一次直接插入排序。
实现
public void sort(int[] arr) {
    int num;
    // temp 为增量
    for (int temp = arr.length / 2; temp > 0; temp = temp / 2) {
        for (int i = temp; i < arr.length; i++) {
            // 增量的数据互相比较交换位置
            for (int j = i; j >= temp; j = j - temp) {
                if (arr[j] < arr[j - temp]) {
                    num = arr[j - temp];
                    arr[j - temp] = arr[j];
                    arr[j] = num;
                }
            }
        }
    }
}
时间复杂度

最好元素都是有序的:O(n)

最坏和直接插入排序一样:O(n^2)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值