一、希尔排序
1.1 API设计
类名 | ShellSort |
---|---|
构造方法 | ShellSort():创建ShellSort对象 |
成员方法 | 1.public static void sort(Comparable[] a):对数组内的元素进行排序 2.private static boolean greater(Comparable v,Comparable w):判断v是否大于w 3.private static void exch(Comparable[] a,int i,int j):交换a数组中,索引i和索引j处的值 |
1.2 实现
public class ShellSort {
// 希尔排序是插入排序的一种,它是针对直接插入排序算法的改进。
public static void sort(Comparable[] a) {
// 确定增长量gap的最大值
int gap = 1;
while (gap < a.length / 2) {
gap = gap * 2 + 1;
}
// 当增长量gap小于1,排序结束
while (gap >= 1) {
// 找到待插入的元素
for (int i = gap; i < a.length; i++) {
// a[i]就是待插入的元素
// 把a[i]插入到a[i-h],a[i-2h],a[i-3h]...序列中
for (int j = i; j >= gap; j -= gap) {
// a[i]就是待插入的元素素,依次和a[j-h],a[j-2h],a[j-3h]进行比较,
// 如果a[j]小,那么 交换位置,如果不小于,a[j]大,则插入完成。
if (greater(a[j - gap], a[j])) {
exch(a, j, j - gap);
} else {
break;
}
}
}
gap/=2;
}
}
// 比较v是否大于w
private static boolean greater(Comparable v, Comparable w) {
return v.compareTo(w) > 0;
}
// 交换
private static void exch(Comparable[] a, int i, int j) {
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
}
1.3 测试
public class ShellSortTest {
public static void main(String[] args) {
String[] arr = {"aa","bb","mm","zz","dd","cc"};
ShellSort.sort(arr);
for (String s : arr) {
System.out.print(s+" ");
}
}
}
二、归并排序
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
2.1 API设计
类名 | MergeSort |
---|---|
构造方法 | MergeSort():创建MergeSort对象 |
成员方法 | 1.public static void sort(Comparable[] a):对数组内的元素进行排序 2.private static void sort(Comparable[] a, int lo, int hi):对数组a中从索引lo到索引hi之间的元素进行排序 3.private static void merge(Comparable[] a, int lo, int mid, int hi):从索引lo到所以mid为一个子组,从索引mid+1到索引hi为另一个子组,把数组a中的这两个子组的数据合并成一个有序的大组(从索引lo到索引hi) 4.private static boolean less(Comparable v,Comparable w):判断v是否小于w 5.private static void exch(Comparable[] a,int i,int j):交换a数组中,索引i和索引j处的值 |
成员变量 | 1.private static Comparable[] assist:完成归并操作需要的辅助数组 |
2.2 实现
/**
* 归并排序是分治思想的最典型的例子
*/
public class MergeSort {
private static Comparable[] assist;//归并所需要的辅助数组
// 排序
public static void sort(Comparable[] a) {
assist = new Comparable[a.length];
int lo = 0;
int hi = a.length - 1;
sort(a, lo, hi);
}
// 对数组a中从lo到hi的元素进行排序
private static void sort(Comparable[] a, int lo, int hi) {
if (hi <= lo) {
return;
}
int mid = lo + (hi - lo) / 2;
// 对lo到mid之间的元素进行排序
sort(a, lo, mid);
// 对mid+1到hi之间的元素进行排序
sort(a, mid + 1, hi);
// 对lo到mid这组数据和mid到hi这组数据进行归并
merge(a, lo, mid, hi);
}
// 对数组中,从lo到mid为一组,从mid+1到hi为一组,对这两组数据进行归并
private static void merge(Comparable[] a, int lo, int mid, int hi) {
// lo到mid这组数据和mid+1到hi这组数据归并到辅助数组assist对应的索引处
int i = lo; // 定义一个指针,指向assist数组中开始填充数据的索引
int p1 = lo; // 定义一个指针,指向第一组数据的第一个元素
int p2 = mid + 1; // 定义一个指针,指向第二组数据的第一个元素
// 比较左边小组和右边小组中的元素大小,哪个小,就把哪个数据填充到assist数组中
while (p1 <= mid && p2 <= hi) {
if (less(a[p1], a[p2])) {
assist[i++] = a[p1++];
} else {
assist[i++] = a[p2++];
}
}
// 上面的循环结束后,如果推出循环的条件是p1<=mid,则证明左边小组中的数据已经归并完毕,如果退出循环的条件是p2<=hi,则证明
// 右边小组的数据已经填充完毕
// 所以需要把未填充完毕的数据继续填充到ssist中,下面两个循环,会执行其中的一个
while (p1 <= mid) {
assist[i++] = a[p1++];
}
while (p2 <= hi) {
assist[i++] = a[p2++];
}
// 到现在为止,assist数组中,从lo到hi的数组是有序的,再把数据拷贝到a数组中对应的索引处
for (int index=lo;index<=hi;index++){
a[index] = assist[index];
}
}
// 比较
private static boolean less(Comparable v, Comparable w) {
return v.compareTo(w) < 0;
}
// 交换
private static void exch(Comparable[] a, int i, int j) {
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
}
2.3 测试
public class MergeSortTest {
public static void main(String[] args) {
String[] arr = {"aa","bb","mm","zz","dd","cc"};
MergeSort.sort(arr);
for (String s : arr) {
System.out.print(s+" ");
}
}
}
三、快速排序
快速排序是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
3.1 API设计
类名 | QuickSort |
---|---|
构造方法 | QuickSort():创建QuickSort对象 |
成员方法 | 1.public static void sort(Comparable[] a):对数组内的元素进行排序 2.private static void sort(Comparable[] a, int lo, int hi):对数组a中从索引lo到索引hi之间的元素进行排序 3.public static int partition(Comparable[] a,int lo,int hi):对数组a中,从索引 lo到索引 hi之间的元素进行分组,并返回分组界限对应的索引 4.private static boolean less(Comparable v,Comparable w):判断v是否小于w 5.private static void exch(Comparable[] a,int i,int j):交换a数组中,索引i和索引j处的值 |
3.2 实现
public class QuickSort {
// 排序
public static void sort(Comparable[] a) {
int lo = 0;
int hi = a.length - 1;
sort(a, lo, hi);
}
// 对数组a中从索引lo到索引hi之间的元素进行排序
private static void sort(Comparable[] a, int lo, int hi) {
if (hi <= lo) {
return;
}
// 对a数组中,从lo到hi的元素进行切分
int partition = partition(a, lo, hi);
// 对左边分组中的元素进行排序
sort(a, lo, partition - 1);
// 对右边分组中的元素进行排序
sort(a, partition + 1, hi);
}
// 对数组a中,从索引 lo到索引 hi之间的元素进行分组,并返回分组界限对应的索引
public static int partition(Comparable[] a, int lo, int hi) {
Comparable key = a[lo];// 把最左边的元素当做基准值
int left = lo;// 定义一个左侧指针,初始指向最左边的元素
int right = hi + 1;// 定义一个右侧指针,初始指向左右侧的元素下一个位置
//进行切分
while (true) {
// 先从右往左扫描,找到一个比基准值小的元素
while (less(key, a[--right])) {//循环停止,证明找到了一个比基准值小的元素
if (right == lo) {
break; //已经扫描到最左边了,无需继续扫描
}
}
//再从左往右扫描,找一个比基准值大的元素
while (less(a[++left], key)) {//循环停止,证明找到了一个比基准值大的元素
if (left == hi) {
break;//已经扫描到了最右边了,无需继续扫描
}
}
if (left >= right) {
//扫描完了所有元素,结束循环
break;
} else {
//交换left和right索引处的元素
exch(a, left, right);
}
}
//交换最后rigth索引处和基准值所在的索引处的值
exch(a, lo, right);
return right;//right就是切分的界限
}
// 比较
private static boolean less(Comparable v, Comparable w) {
return v.compareTo(w) < 0;
}
// 交换
private static void exch(Comparable[] a, int i, int j) {
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
}
3.3 测试
public class QuickSortTest {
public static void main(String[] args) {
String[] arr = {"aa","bb","mm","zz","dd","cc"};
QuickSort.sort(arr);
for (String s : arr) {
System.out.print(s+" ");
}
}
}