先定义一个排序对象,用于测试稳定性。
package sort;
import java.util.Random;
public class SortObj {
private int value;
private String name;
public SortObj(int v) {
this.value = v;
this.name = String.valueOf(v);
}
public SortObj(int v, String n) {
this.value = v;
this.name = n;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
return value;
}
@Override
public boolean equals(Object obj) {
if(null == obj) {
return false;
}
if(!(obj instanceof SortObj)) {
return false;
}
else {
return this.value == ((SortObj)obj).getValue();
}
}
public static SortObj[] genArr() {
Random r = new Random(3);
int size = 10;
SortObj[] arr = new SortObj[size];
for(int i=0; i<size; i++) {
arr[i] = new SortObj(r.nextInt());
}
return arr;
}
public static SortObj[] genArr(int size) {
Random r = new Random(50);
SortObj[] arr = new SortObj[size];
for(int i=0; i<size; i++) {
arr[i] = new SortObj(r.nextInt());
}
return arr;
}
public boolean isLarger(SortObj sortObj) {
return this.value > sortObj.getValue();
}
public boolean isSmaller(SortObj sortObj) {
return this.value < sortObj.getValue();
}
@Override
public String toString() {
return name + ": " + String.valueOf(value);
}
}
插入排序(Insert Sort)
基本思路是,遍历数组,认为左边的元素已经排序,将后面的元素从右往左比较,找到对应的位置,进行插入操作。
类似于插入扑克牌,左手的牌已经排好序,右手摸牌,插到左手的牌中。
//Insert directly.
public static SortObj[] insertSort(SortObj[] objArr) {
if (null == objArr) {
return null;
}
SortObj[] r = clone(objArr);
if (r.length == 1) {
return r;
}
int k;
SortObj s;
for (int i = 1; i < r.length; i++) {
s = r[i];
k = i - 1;
while (k >= 0 && r[k].isLarger(s)) {
r[k + 1] = r[k];
k--;
}
r[k + 1] = s;
}
return r;
}
可以利用二分法进行比较,减少比较次数。
希尔排序(Shell Sort)
基本原理:给定数组,选取步长,以步长为间隔将给定数组抽象地分解为若干子数组并在子数组内部进行插入排序,然后不断将步长缩短并循环上一步至步长为1,此时即为普通的插入排序。
代码诠释(严格按照原理)
public static SortObj[] shellSort(SortObj[] objArr) {
if (null == objArr) {
return null;
}
SortObj[] r = clone(objArr);
if (r.length == 1) {
return r;
}
int h = 0;
while ((h * 3 + 1) < r.length) {
h = h * 3 + 1;
}
SortObj s;
while (h > 0) {
for (int i = 0; i < h; i++) { // Loop sub arrays.
for (int j = i + h; j < r.length; j += h) { // Insert sort for
// sub array.
for (int k = i; k < j; k += h) { // Loop inside sub array.
// Perform an insert
// sort.
if (r[k].isLarger(r[j])) { // Found the position that
// current element should be
// placed in the sub array
s = r[j];
for (int l = j; l > k; l -= h) {
r[l] = r[l - h];
}
r[k] = s;
}
}
}
}
h = (h - 1) / 3;
}
return r;
}
可以将分组合并的顺序做调整,缩减代码。缩减代码后:
//Mainly shorten code. Same algorithm of restrictedShellSort method.
//One nested loop less than the restricted one.
public static SortObj[] optimizedShellSort(SortObj[] objArr) {
if (null == objArr) {
return null;
}
SortObj[] r = clone(objArr);
if (r.length == 1) {
return r;
}
// The DI.
int h = 0;
while ((h * 3 + 1) < r.length) {
h = h * 3 + 1;
}
while (h > 0) {
for (int i = h; i < r.length; i++) {
int p = i - h;
SortObj s = r[i];
while (p >= 0 && r[p].isLarger(s)) {
r[p + h] = r[p];
p -= h;
}
r[p + h] = s;
}
h = (h - 1) / 3;
}
return r;
}
归并排序
归并排序基本思路是将两个已经排好序的数组合并成一个排序数组,利用指针同时遍历两个数组,取出两个数值,将数值较小的数放在结果内,然后该指针向后移动一位,另外一个指针不变,直至其中一个数组达到末尾,而后将另一数组的剩下元素复制到结尾。
此方法一般使用递归算法,将无序数组拆递归分成两个无序数组,直至数组长度为1时,认为该数组已经排好序,不再拆分,开始递归回调。
递归算法实现代码:
public static SortObj[] recursiveMergeSort(SortObj[] objArr) {
if (null == objArr) {
return null;
}
SortObj[] r = clone(objArr);
if (r.length == 1) {
return r;
}
int lLen = r.length / 2;
int rLen = r.length - lLen;
SortObj[] left = new SortObj[lLen];
SortObj[] right = new SortObj[rLen];
for (int i = 0; i < lLen; i++) {
left[i] = r[i];
}
for (int i = 0; i < rLen; i++) {
right[i] = r[lLen + i];
}
left = recursiveMergeSort(left);
right = recursiveMergeSort(right);
int m = 0, n = 0;
for (; m < left.length && n < right.length;) {
if (left[m].isLarger(right[n])) {
r[m + n] = right[n];
n++;
} else {
r[m + n] = left[m];
m++;
}
}
for (; m < left.length; m++) {
r[m + n] = left[m];
}
for (; n < right.length; n++) {
r[m + n] = right[n];
}
return r;
}