关于java:常见的初级排序算法这次全搞懂

54次阅读

共计 2863 个字符,预计需要花费 8 分钟才能阅读完成。

本文已被 Github 仓库收录 https://github.com/silently9527/JavaCore

程序员罕用的 IDEA 插件:https://github.com/silently9527/ToolsetIdeaPlugin

齐全开源的淘客我的项目:https://github.com/silently9527/mall-coupons-server

微信公众号:贝塔学 Java

前言

置信所有的程序员刚开始接触到的算法都会是排序算法,因为排序在对数据处理和计算有这重要的位置,排序算法往往是其余算法的根底;本文咱们就先从高级排序算法开始学习算法。

排序算法的模板

在开始之前咱们先定义一个排序算法通用的模板,在前面的排序算法都会实现这个模板

public interface SortTemplate {void sort(Comparable[] array);

    default void print(Comparable[] array) {for (Comparable a : array) {System.out.print(a + " ");
        }
    }

    default boolean less(Comparable a, Comparable b) {return a.compareTo(b) < 0;
    }

    default void exch(Comparable[] array, int i, int j) {Comparable tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }
    
}
  • Comparable: 为了让咱们实现的排序算法更加的通用,能够排序任意的对象,所以咱们这里应用了 Comparable 数组
  • sort: 不同的排序算法实现的形式不一样,子类本人去实现
  • less: 定义的专用办法,如果 a < b 就返回 true
  • exch: 定义的专用办法,替换数组中的两个对象
  • print: 打印出数据中的每个元素

抉择排序

算法实现的思路:

  • 首先找到数组中的最小元素,
  • 其实将它和数组中的第一个元素进行替换,这样就排定了一个元素;
  • 再次找出残余元素中最小的元素与数组中的第二个元素进行替换,如此重复直到所有元素都是有序的

代码实现:

public class SelectionSort implements SortTemplate {

    @Override
    public void sort(Comparable[] array) {
        int length = array.length;
        for (int i = 0; i < length; i++) {
            int min = i;
            for (int j = i + 1; j < length; j++) {if (less(array[j], array[min])) {min = j;}
            }
            exch(array, i, min);
        }
    }

}

如果输出的数组是有序的,咱们会发现抉择排序运行的时候和未排序的工夫一样长!

对于 N 个元素的数组,应用 抉择排序的工夫复杂度是 O(n²)

抉择排序的是 数据挪动起码 的,替换的次数与数组的大小是线性关系,N 个元素的数组须要 N 次替换

冒泡排序

算法实现的思路:

  • 比拟相邻的两个元素,如果前一个比后一个大,那么就替换两个元素的地位
  • 对每一组相邻的元素执行同样的操作,直到最初一个元素,操作实现之后就能够排定一个最大的元素
  • 如此往返,直到数组中所有的元素都有序

代码实现:

public class BubbleSort implements SortTemplate {

    @Override
    public void sort(Comparable[] array) {
        int length = array.length - 1;
        for (int i = 0; i < length; i++) {for (int j = 0; j < length - i; j++) {if (less(array[j + 1], array[j])) {exch(array, j, j + 1);
                }
            }
        }
    }

}

对于 N 个元素的数组,应用 冒泡排序的工夫复杂度是 O(n²)

插入排序

设想咱们在玩扑克牌时,整顿扑克牌都是把每一张插入到右边曾经排好序的牌中适当的地位。插入排序的思路相似

算法实现的思路:

  • 初始默认第一个元素就是有序的,以后索引的地位从 0 开始
  • 先后挪动以后索引的地位,以后索引地位右边的元素是有序的,从后往前开始扫码与以后索引地位元素进行比拟
  • 当确定以后索引地位上的元素在右边有序适宜的地位之后,插入到该地位上
  • 如果当确定以后索引地位上的元素大于了已排序的最初一个元素,那么以后索引地位间接往后挪动
  • 如此重复,直到所有元素有序

代码实现:

public class InsertionSort implements SortTemplate {

    @Override
    public void sort(Comparable[] array) {
        int length = array.length;
        for (int i = 1; i < length; i++) {for (int j = i; j > 0 && less(array[j], array[j - 1]); j--) {exch(array, j, j - 1);
            }
        }
    }

}

从代码的实现咱们能够看出,当遇到了以后索引的元素大于了右边有序数组的最初一个元素时,内层循环就间接完结了,所以所咱们排序的数组中存在着局部有序,那么插入排序算法会很快。

思考最蹩脚的状况,如果输出数组是一个倒置的,那么插入排序的效率和抉择排序一样,工夫复杂度是 O(n²)

希尔排序

对于大规模的乱序数组插入排序很慢,是因为它只替换相邻的元素,元素只能一点一点的从数组中挪动到正确的地位;插入排序对于局部有序的数组排序是的效率很高;

希尔排序基于这两个特点对插入排序进行了改良;

算法实现的思路

  • 首先设置一个步长 h 用来分隔出子数组
  • 用插入排序将 h 个子数组独立排序
  • 减小 h 步长持续排序子数组,直到 h 步长为 1
  • 当步长为 1 时就成了一般的插入排序,这样数组肯定是有序的

希尔排序高效的起因,在排序之初,各个子数组都很短,子数组排序之后都是局部有序的,这两种状况都很适宜插入排序。

代码实现:

public class ShellSort implements SortTemplate {

    @Override
    public void sort(Comparable[] array) {
        int gap = 1;
        int length = array.length;

        while (gap < length / 3) {gap = 3 * gap + 1;}

        while (gap >= 1) {for (int i = gap; i < length; i++) {for (int j = i; j >= gap && less(array[j], array[j - gap]); j -= gap) {exch(array, j, j - gap);
                }
            }
            gap = gap / 3;
        }
    }

}

最初(点关注,不迷路)

文中或者会存在或多或少的有余、谬误之处,有倡议或者意见也十分欢送大家在评论交换。

最初,写作不易,请不要白嫖我哟 ,心愿敌人们能够 点赞评论关注 三连,因为这些就是我分享的全副能源起源????

文中所有源码已放入到了 github 仓库 https://github.com/silently9527/JavaCore

图片来源于网络
参考书籍:算法第四版

正文完
 0