常见的几种排序

本文章对几种常用的排序进行分析与代码实现,本文所有排序都按照从小到大的顺序排列。

冒泡排序

冒泡排序是最易学也是最简单的排序,它的实现原理是多次循环数据,两两对比取大的值和下一个数继续对比,看起来像水泡从小变大的过程,因此又称冒泡排序。

代码实现

    public void bubbleSort(int[] arr) {
        for (int i = 0;i < arr.length - 1;i++) {
            for ( int j = 1;j < arr.length - i;j++) {

                if (arr[j - 1] > arr[j]) {
                    swap(arr, j, j - 1);
                }
            }
        }
    }

swap函数用于将两数交换。
每次循环都将余下最大的数放至末尾,共进行n - 1次循环,其中最后一次无需比较。

如果排序的数组本身就是有序的,或者经过两次冒泡以后,数组已经变得有序了,冒泡排序依然会进行排序,这显然是不合理的,因此我对其做了改进

    public void bubbleSort(int[] arr) {
        for (int i = 0;i < arr.length - 1;i++) {
            boolean sorted = true;
            for ( int j = 1;j < arr.length - i;j++) {

                if (arr[j - 1] > arr[j]) {
                    sorted = false;
                    swap(arr, j, j - 1);
                }
            }
            if (sorted) return;
        }
    }

取一个标志位,如果内循环中没有进行交换数据,则认为数组已经有序,无需交换。

选择排序

选择排序每次都选择出最小的数的下标进行排序。
在第一轮遍历中,默认为第一个数是最小的,并将其下标取出保存至min变量中,然后从剩余数据中与该下标表示的数比较,如果找到更小的,就重置min为该下标,随后剩余的数继续与其比较,直至第一轮遍历完成。最后将min与0下标的数互换。
在第二轮遍历中,继续找到剩余数的最小值下标,然后与1下标的数互换。
以此类推

代码实现

    public void selSort(int[] arr) {

        int min;
        for (int i = 0;i < arr.length - 1;i++) {
            min = i;
            for (int j = i + 1;j < arr.length;j++) {
                if (arr[j] < arr[min]) {
                    min = j;
                }
            }
            swap(arr, min, i);
        }

    }

选择排序相较于冒泡排序,比较的次数是一样的,但是选择排序每次外循环遍历时只需交换一次数据。

插入排序

插入排序的原理就是将一个数插入到一个本身已经有序的数组里。
遍历一个数组,从第二个数开始,默认它前面的数有序,然后将该数放入前面它应该有的位置,直至最后一个数,完成排序
代码如下

    public void insertSort(int[] arr) {
        for (int i = 1;i < arr.length;i++) {
            if (arr[i] < arr[i - 1]) {
                //出现逆序,从i往前遍历,找到小于它的数
                int num = arr[i];
                int j = i - 1;
                while (j >= 0 && arr[j] > num) {
                    arr[j + 1] = arr[j];
                    j--;
                }
                arr[j + 1] = num;
            }
        }
    }

从上述代码看出,如果一个数组本身是比较有序的,那么该排序的效率将非常高,最好的情况只需O(n)的时间复杂度。

快速排序

作为排序算法中最有牌面的一位,常常在面试中出场,身为程序员的我们自然要好好探究一番
快速排序每次将数据分割成两部分,一堆大,一堆小,然后继续对这两对数据分割,知道无法分割为止,这时整个序列已经有序

    public void QuickSort(int[] arr, int low, int high) {
        if (low < high) {

            //分割数组,并获取下标
            int p = partition(arr, low, high);

            //分割左边
            QuickSort(arr, low, p - 1);
            //分割右边
            QuickSort(arr, p + 1, high);

        }

    }

快速排序通过递归调用自身来进行排序,编写递归时要注意递归的三大要素:1、确定递归的参数 2、递归的结束条件 3、明确递归体的逻辑,要做什么事
上述代码中首先要明确参数,快速排序是对数组不断分割的过程,因此需要确定分割后数组的边界low和high;其次,当分割到只有一个元素,即low=high时,就可以结束了,因此low < high为结束条件;那么在实现逻辑部分最重要的就是partioion函数了,它的作用是将数组分成两部分,并返回中间的数。

    public int partition(int[] arr, int low, int high) {

        int flag = arr[low];//取第一个数为标志位

        while (low < high) {
            //从末尾向前搜索
            while (low < high && arr[high] >= flag) {
                high--;
            }
            //找到比flag小的数则交换位置
            swap(arr, low, high);
            //此时从前向后搜索
            while (low < high && arr[low] <= flag) {
                low++;
            }
            //找到比flag小的数则交换位置
            swap(arr, low, high);

        }
        return low;
    }

它通过多次的交换,将序列分成两部分,代码不难,不过要注意的是,迭代的数与flag相等时指针仍然需要移动,否则会无限循环下去。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值