import java.util.Arrays;
/**
* 初级排序算法:
* 选择排序 -- N^2
* 插入排序 -- N~N^2
* 冒泡排序 -- N^2
* 希尔排序 -- NlogN ?
*
* 高级排序算法:
* 归并排序 -- NlogN
* 快速排序 -- NlogN
* 三向快速排序 -- N ~ NlogN
* 堆排序 -- NlogN
*/
public abstract class Sort {
protected Comparable[] toBeSortedArray; // 待排序的数组
public Sort(Comparable[] toBeSortedArray) {
this.toBeSortedArray = toBeSortedArray;
}
// 判断 toBeSortedArray[i] 是否小于 toBeSortedArray[j]
protected boolean less(int i, int j) {
return toBeSortedArray[i].compareTo(toBeSortedArray[j]) < 0;
}
// 交换 toBeSortedArray[i] 和 toBeSortedArray[j]
protected void exch(int i, int j) {
Comparable temp = toBeSortedArray[i];
toBeSortedArray[i] = toBeSortedArray[j];
toBeSortedArray[j] = temp;
}
// 判断数组是否有序
protected boolean isSorted() {
for (int i = 1; i < toBeSortedArray.length; i++)
if (!less(i-1,i))
return false;
return true;
}
// 抽象方法,子类一定要实现
public abstract void sort();
}
/**
* 选择排序:每次遍历整个未排序的数组选择最小的放在前面,即左边是完全整体有序的,直到整个数组有序。
* 时间复杂度:原始元素的顺序对时间几乎没有影响;对于长度为N的数组,选择排序需要大约 N^2/2 次比较和 N 次交换。
*/
class SelectionSort extends Sort {
public SelectionSort(Comparable[] toBeSortedArray) {
super(toBeSortedArray);
}
@Override
public void sort() {
for (int i = 0; i < toBeSortedArray.length; i++) {
int min = i;
for (int j = i+1; j < toBeSortedArray.length; j++) {
if (less(j,min)) // N^2/2 次比较选出最小的
min = j;
}
// 交换开头和选择出的最小值 (N次交换)
exch(i,min);
}
}
public static void main(String[] args) {
Integer[] testArray = {5,8,4,1,2,3,7,9,6,0};
SelectionSort selectionSort = new SelectionSort(testArray);
selectionSort.sort();
System.out.println(selectionSort.isSorted());
System.out.println(Arrays.toString(testArray));
}
/*
true
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
*/
}
/**
* 插入排序:从头开始一个一个插入(与相邻的比较并交换),始终保持左边的元素相对有序,后来的插入(通过与左边的不断比较和交换)到前面的有序部分,直到插完最后一个元素。
* 时间复杂度:取决于原始元素的顺序;平均情况下插入排序需要大约 N^2/4 次比较和 N^2/4 次交换,最坏情况下需要大约 N^2/2 次比较和 N^2/2 次交换,
* 但对于小数组还是挺快的。
*/
class InsertionSort extends Sort {
public InsertionSort(Comparable[] toBeSortedArray) {
super(toBeSortedArray);
}
@Override
public void sort() {
int N = toBeSortedArray.length;
for (int i = 1; i < N; i++) {
// 把 toBeSortedArray[i] 插入到 toBeSortedArray[0 ~ i-1]中
for (int j = i; j >= 1 && less(j,j-1); j--) // 这里从右往左,最右边是最大的,只要less(j,j-1)不成立就退出内层for循环了
exch(j,j-1);
}
}
public static void main(String[] args) {
Integer[] testArray = {5,8,4,1,2,3,7,9,6,0};
InsertionSort insertionSort = new InsertionSort(testArray);
insertionSort.sort();
System.out.println(insertionSort.isSorted());
System.out.println(Arrays.toString(testArray));
}
/*
true
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
*/
}
/**
* 冒泡排序:冒泡排序与插入排序拥有很多相似点,都是通过与相邻的比较,但他们的思路正好是相反的,插入排序是按序依次确定前i个元素的相对位置,而冒泡排序是
* 按序依次确定整体数组中第i个元素(从前到后确定第 i 大的),其最终的效果更类似于选择排序,但优于选择排序的地方在于在每次冒泡会把相对顺序往"好"的方向调整.
* 时间复杂度:需要大约 N^2/2 次比较和 N^2/4 次交换(交换次数取决于输入)。
* 特点:因为它的特性与插入排序类似(稳定排序,原地排序,复杂度等),而且性能不如插入排序,所以一般选用插入排序。
*/
class BubbleSort extends Sort {
public BubbleSort(Comparable[] toBeSortedArray) {
super(toBeSortedArray);
}
@Override
public void sort() {
int N = toBeSortedArray.length;
for(int i = 0 ; i < N-1; i++){ // 进行 N-1 趟冒泡
for(int j = 0 ; j < N-i-1; j++){ // N-i-1 为冒泡的右边界,因为后面已经完全整体有序了
if(less(j+1,j)){ // 如果 [j+1] 小于 [j] 就交换
exch(j,j+1);
}
}
}
}
public static void main(String[] args) {
Integer[] testArray = {5,8,4,1,2,3,7,9,6,0};
BubbleSort bubbleSort = new BubbleSort(testArray);
bubbleSort.sort();
System.out.println(bubbleSort.isSorted());
System.out.println(Arrays.toString(testArray));
}
/*
true
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
*/
}
/**
* 希尔排序:它的思想基于插入排序,但是插入排序只能一个一个和相邻的元素的交换,而希尔排序可以交换不相邻的元素,对任意间隔为 h 的元素进行插入排序,当 h 为 1 时其就是插入排序,不过它大大减少了交换的次数。
* 时间复杂度:采取不同的 h 取值其时间复杂度不同,但不会超过 N^2,一般使用递增序列 1、4、13...(3*h + 1)。
* 特点:它的优点是简洁代码量小并且运行时间可以接受,尤其是对于中型的数组,在N不是特别大的情况下那些高效的排序算法可能只比希尔排序快两倍左右。
*/
class ShellSort extends Sort {
public ShellSort(Comparable[] toBeSortedArray) {
super(toBeSortedArray);
}
@Override
public void sort() {
int N = toBeSortedArray.length;
int h = 1;
// 对 h 取值
while (h < N/3)
h = 3*h + 1;
// 遍历 h 插入排序
while (h >= 1) {
for (int i = h; i < N; i++) {
for (int j = i; j >= h && less(j,j-h); j-=h)
exch(j,j-h);
}
h = h/3; // h = (h-1)/3
}
}
public static void main(String[] args) {
Integer[] testArray = {5,8,4,1,2,3,7,9,6,0};
ShellSort shellSort = new ShellSort(testArray);
shellSort.sort();
System.out.println(shellSort.isSorted());
System.out.println(Arrays.toString(testArray));
}
/*
true
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
*/
}
1-排序之初级排序算法(选择排序、插入排序、冒泡排序、希尔排序)
最新推荐文章于 2024-08-14 22:49:08 发布