原文 | http://t.cn/E6oruBg
编辑 | 程序猿杂货铺
阅读文本大概需要 10 分钟。
冒泡排序是一种非常简单的初级排序算法,它每次比较相邻的两个元素,如果顺序错误就进行交换.由于最小的元素是经由不断交换慢慢浮到顶端的,所以叫做冒泡排序.
冒泡排序对 n 个元素需要 O(n^2)
次的比较次数,所以它对规模较大的数组进行排序是效率低下的.
// less与exch函数见完整代码
public static void sort(Comparable[] a) {
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - 1 - i; j++) {
if (less(a[j + 1], a[j])) {
exch(a, j, j + 1);
}
}
}
}
/**
* Bubble Sort
*
* @author SylvanasSun
*
*/
public class Bubble {
// This class should not be instantiated.
private Bubble() {
}
/**
* Rearranges the array in ascending order, using the natural order.
*
* @param a
* a the array to be sorted
*/
public static void sort(Comparable[] a) {
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - 1 - i; j++) {
if (less(a[j + 1], a[j])) {
exch(a, j, j + 1);
}
}
}
}
/**
* Rearranges the array in ascending order, using a comparator.
*
* @param a
* a the arry to be sorted
* @param comparator
* comparator the comparator specifying the order
*/
public static void sort(Object[] a, Comparator comparator) {
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - 1 - i; j++) {
if (less(comparator, a[j + 1], a[j])) {
exch(a, j, j + 1);
}
}
}
}
// a < b ?
private static boolean less(Comparable a, Comparable b) {
return a.compareTo(b) < 0;
}
// a < b ?
private static boolean less(Comparator comparator, Object a, Object b) {
return comparator.compare(a, b) < 0;
}
// exchange a[i] and a[j]
private static void exch(Object[] a, int i, int j) {
Object temp = a[i];
a[i] = a[j];
a[j] = temp;
}
// print array elements to console
public static void print(Comparable[] a) {
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
// test
public static void main(String[] args) {
String[] s = new Scanner(System.in).nextLine().split("\\s+");
Bubble.sort(s);
Bubble.print(s);
}
}
选择排序也是一种非常简单直观的初级排序算法,它的思想是不断地选择剩余元素之中的最小者.
它有以下两个特点.
public static void sort(Comparable[] a) {
for (int i = 0; i < a.length; i++) {
int min = i; // the smallest element index
for (int j = i + 1; j < a.length; j++) {
if (less(a[j], a[min]))
min = j;
exch(a, i, min);
}
}
}
插入排序与选择排序一样,当前索引左边的所有元素都是有序的,但它们的最终位置并不是确定的.它构建了一个有序序列,对于未排序的元素,在有序序列中从后向前扫描,找到相应的位置并插入.
插入排序所需的时间取决于输入模型中元素的初始顺序.当输入模型是一个部分有序的数组时,插入排序的效率会高很多.
因此插入排序对于部分有序的数组十分高效,也很适合小规模的数组.
public static void sort(Comparable[] a) {
for (int i = 0; i < a.length; i++) {
// a[i] insert to a[i-1]、a[i-2]、a[i-3]...
for (int j = i; j > 0 && less(a[j], a[j - 1]); j--) {
exch(a, j, j - 1);
}
}
}
插入排序还有很多可以优化的地方,这里例举两个案例.
public static void sort(Comparable[] a) {
int length = a.length;
for (int i = 1; i < length; i++) {
// binary search to determine index j at which to insert a[i]
Comparable v = a[i];
int lo = 0, hi = i;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (less(v, a[mid]))
hi = mid;
else
lo = mid + 1;
}
// insertion sort with "half exchanges"
// (insert a[i] at index j and shift a[j], ..., a[i-1] to right)
for (int j = i; j > lo; --j)
a[j] = a[j - 1];
a[lo] = v;
}
}
public static void sort(Comparable[] a) {
int length = a.length;
// put smallest element in position to serve as sentinel
int exchanges = 0;
for (int i = length - 1; i > 0; i--) {
if (less(a[i], a[i - 1])) {
exch(a, i, i - 1);
exchanges++;
}
}
if (exchanges == 0)
return;
// insertion sort with half-exchanges
for (int i = 2; i < length; i++) {
Comparable v = a[i];
int j = i;
while (less(v, a[j - 1])) {
a[j] = a[j - 1];
j--;
}
a[j] = v;
}
}
希尔排序,也称递减增量排序算法,它是基于插入排序的一种更高效的改进版本.由于插入排序对于大规模乱序数组效率并不高,因为它只会交换相邻的元素,因此元素只能一点一点地从数组的一端移动到另一端.而希尔排序为了加快速度简单地改进了插入排序,交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序.
希尔排序的思想是使数组中任意间隔为h的元素都是有序的,可以说一个h有序的数组就是h个互相独立的有序数组编织在一起组成的一个数组.
public static void sort(Comparable[] a) {
int h = 1;
while (h < a.length / 3) {
// h sequence 1,4,13,40,121,364,1093,...
h = h * 3 + 1;
}
while (h >= 1) {
for (int i = h; i < a.length; i++) {
// a[i] insert to a[i-h],a[i-2*h],a[i-3*h]...
for (int j = i; j >= h && less(a[j], a[j - h]); j -= h) {
exch(a, j, j - h);
}
}
h = h / 3;
}
}
限于篇幅,本次文章分了两篇,下篇将会讲解 快速排序 三向快速排序 归并排序 堆排序等算法
文中所有源码地址 https://github.com/SylvanasSun/algs4-study