常用排序算法

冒泡排序

1.介绍

一种交换排序,基本思想:两两比较相邻的关键字(记录),如果反序则交换,知道没有反序的记录为止。

–最简单的一种冒泡

严格来说不算标准的冒泡排序,不满足“两两比较相邻记录”的冒泡思想,更应该是最简单的交换排序而已。

//外层for循环执行一次,便找出一个最大的数。
public static void sort0(int[] arr) {
    for (int i = 0; i < arr.length; i++) {
        for (int j = i + 1; j < arr.length; j++) {
            if (arr[i] < arr[j]) {
                swap(arr, i, j);
            }
        }
    }
}

–正宗的冒泡排序

/**
 * 正宗的冒泡排序,两两相互比较
 *
 * @param arr
 */
public static void sort1(int[] arr) {
    for (int i = 0; i < arr.length; i++) {
        for (int j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] < arr[j + 1]) {
                swap(arr, j, j+1);
            }
        }
    }
}

–冒泡排序优化

上面的冒泡排序,如果说后面的数字已经有序了,算法还会将后面的数字逐一进行比较,此时并没有数据交换,后面的大量比较是多余的。
例如:{2,1,3,4,5,6,7,8,9},此时第一次比较,将2和1交换数据了,发现后面都是有序的。算法还会依次比较一次。

/**
 * 正宗的冒泡排序优化
 *
 * @param arr
 */
public static void sort2(int[] arr) {
    boolean flag = true;
    for (int i = 0; i < arr.length && flag; i++) {
        flag = false; //循环一次过后将flag置为false。
        for (int j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] < arr[j + 1]) {
                swap(arr, j, j + 1);
                flag = true; //如果有数据交换,则flag为true。
            }
        }
    }
}
时间复杂度分析

最好情况,没有数据交换,只比较n-1次,时间复杂度为O(n)

最坏情况,数据为逆序的,比较1+2+3+…+(n-1) = n(n-1) / 2,并作等量数集的移动; 时间复杂度为(n^2);


简单选择排序

1.介绍:排序时,用一个变量min记录比较过程中最小数据的下标。最后找到合适的关键字(最大,最小)在做交换,并且只移动一次就完成相应关键字的排序定位工作。

/**
 * 简单选择排序
 *
 * @param arr
 */
public static void selectSort(int[] arr) {
    int min ; //记录最小记录的位置(数组的下标)
    for (int i = 0; i < arr.length; i++) {
        min = i;
        for (int j = i; j < arr.length -1; j++) {
            if (arr[min] > arr[j + 1]) {
                min = j + 1; //如果最小位置的记录大于j+1位置的记录,将j+1的下标赋给min。
            }
        }
        if (min != i) {
            swap(arr, i, min);
        }
    }
}

优点:交换移动次数相对少,节约了相应的时间,无论最好还是最坏,比较次数一样,第i次,比较n-i次,时间复杂度为O(O^2),性能上优于冒泡。


直接插入排序

1.介绍:基本操作是将一个记录插入到已经排好序的有序表中,从而得到一个新的,记录加1的有序表(插入排序方法)。

public static void insertSort(int[] arr) {
    //从第二个数开始循环
    for (int i = 1; i < arr.length; i++) {
        //如果要插入的数即是后面的数小于前面的数,将后面的数记录下来
        if (arr[i] < arr[i - 1]) {
            int temp = arr[i];
            int j;
            //从i -1的位置依次往前遍历与要插入的数比较(temp),如果大于要插入的数,
            // 则将当前位置的数据后移,如果小于则找说明找到那个位置了则退出遍历。
            for(j = i -1;arr[j] > temp;j--) {
                arr[j + 1] = arr[j];
            }
            //将退出遍历的那个j位置后面的那个位置j+1位置填入要插入的那个数。
            arr[j+1] = temp;
        }
    }
}

最好情况,就只有比较,没有移动,时间复杂度为O(n),
总的来说,时间复杂度为O(n^2).比冒泡和简单排序性能要好一些。


希尔排序

1.介绍:对直接插入排序的改进。分割待排序记录,减少待排序记录的个数,使整个序列基本有序发展。

基本有序:最小的关键字基本在前面,大的基本在后面,不大不小的基本在中间,例如
{2,1,3,6,4,7,5,8,9}可以称为基本有序,像{1,5,9,3,7,8,2,4,6}这样9在第三位,2在倒数第三位就谈不上基本有序。

跳跃分割策略:将相距某个“增量”的记录组成一个子序列,这样才能保证在子序列内分别进行直接插入排序后得到的结果是基本有序而不是局部有序。

 /**
 * 希尔排序
 * @param arr
 */
public static void sort(int[] arr) {
    int increment = arr.length;
    do{
        increment = increment /3 +1;
        for(int i = increment +1 ;i<arr.length;i++) {
            if (arr[i] < arr[i - increment]) {
                int temp = arr[i];
                int j;
                for(j = i -increment;j>0 && arr[j] > temp ;j-=increment) {
                    arr[j+increment] = arr[j];
                }
                arr[j + increment] = temp;
            }
        }
    }while (increment >1);
}

时间复杂度为O(n^3/2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值