一、希尔排序
希尔排序因计算机科学家Donald L. Shell得名,他在1959年发现了希尔排序算法。希尔排序基于插入排序,但是通过n-增量排序,大大地提高了插入排序的执行效率。希尔排序使用的间隔序列除了n=3n+1这样的间隔序列,也可以使用其他的间隔序列,不过必须保证一个最终条件n=1。
package com.xwiam.algorithms.advancesort;
/**
* 希尔排序
*/
public class ShellSort {
private long[] instance;
private int nElems;
public ShellSort(int maxSize) {
instance = new long[maxSize];
nElems = 0;
}
public void insert(long value) {
instance[nElems++] = value;
}
public void display() {
for (int i = 0;i < nElems;i++) {
System.out.print(instance[i] + " ");
}
System.out.println();
}
public void sort() {
int inner, outer;
long temp;
int n = 1;
while (n <= nElems / 3) {
n = n * 3 + 1;
}
while (n > 0) {
for (outer = n;outer < nElems;outer++) {
temp = instance[outer];
inner = outer;
while (inner > n - 1 && instance[inner - n] > temp) {
instance[inner] = instance[inner - n];
inner -= n;
}
instance[inner] = temp;
}
n = (n - 1) / 3 ;
}
}
public static void main(String[] args) {
int maxSize = 10;
ShellSort shellSort = new ShellSort(maxSize);
for (int i = 0;i < maxSize;i++) {
long n = (int) (Math.random() * 99);
shellSort.insert(n);
}
shellSort.display();
shellSort.sort();
shellSort.display();
}
}
希尔排序的效率
迄今为止,除了一些特殊的 情况下,还没有人能够从理论上分析希尔排序的效率。有各种各样基于试验的评估,估计它的时间级从O(N3/2)到O(N/7/6)。
二、快速排序
在大多数情况下,对于内存排序来说,快速排序是最快的。对于硬盘文件的排序,其他的排序算法可能更改好。快速排序基于分治算法,所以执行时间为O(N*logN)。
1、选择数组最右端的数据作为划分枢纽的快速排序,适用于随机排序的数组。如果数组是有序的或者逆序的,快速排序的执行时间会从O(N*logN)变为O(N2)。因为划分数组的时候基本都是n-1和1,最优的划分是划分后左右数组的大小相等或者接近。
package com.xwiam.algorithms.advancesort;
/**
* 快速排序
*/
public class QuickSort1 {
private long[] instance;
private int nElems;
public QuickSort1(int maxSize) {
instance = new long[maxSize];
nElems = 0;
}
public void insert(long value) {
instance[nElems++] = value;
}
public void display() {
for (int i = 0;i < nElems;i++) {
System.out.print(instance[i] + " ");
}
System.out.println();
}
public void quickSort() {
recQuickSort(0, nElems - 1);
}
private void recQuickSort(int left, int right) {
if (right - left <= 0) {
return;
} else {
long pivot = instance[right];
int partition = partition(left, right, pivot);
recQuickSort(left, partition - 1);
recQuickSort(partition + 1, right);
}
}
private int partition(int left, int right, long pivot) {
int leftPtr = left - 1;
int rightPtr = right;
while (true) {
while (instance[++leftPtr] < pivot) {
}
while (rightPtr > 0 && instance[--rightPtr] > pivot) {
}
if (leftPtr >= rightPtr) {
break;
} else {
swap(leftPtr, rightPtr);
}
}
swap(leftPtr, right);
return leftPtr;
}
private void swap(int left, int right) {
long temp = instance[right];
instance[right] = instance[left];
instance[left] = temp;
}
public static void main(String[] args) {
int maxSize = 10;
QuickSort1 quickSort1 = new QuickSort1(maxSize);
for (int i = 0;i < maxSize;i++) {
long n = (int) (Math.random() * 99);
quickSort1.insert(n);
}
quickSort1.display();
quickSort1.quickSort();
quickSort1.display();
}
}
2、使用三数据项取中划分方法,取数组中最左,最右和中间的数值排序后取中间值,作为枢纽值,适用于数据基本有序的数组。
package com.xwiam.algorithms.advancesort;
/**
* 快速排序+插入排序
*/
public class QuickSort2 {
private long[] instance;
private int nElems;
public QuickSort2(int maxSize) {
instance = new long[maxSize];
nElems = 0;
}
public void insert(long value) {
instance[nElems++] = value;
}
public void display() {
for (int i = 0;i < nElems;i++) {
System.out.print(instance[i] + " ");
}
System.out.println(" ");
}
public void quickSort() {
if (nElems < 10) {
insertSort();
} else {
recQuickSort(0, nElems - 1);
}
}
private void insertSort() {
int inter, outer;
long insertValue;
for (outer = 0;outer < nElems;outer++) {
insertValue = instance[outer];
inter = outer;
while (inter > 0 && instance[inter - 1] > insertValue) {
instance[inter] = instance[inter - 1];
inter--;
}
instance[inter] = insertValue;
}
}
private void recQuickSort(int left, int right) {
if (right - left <= 0) {
return;
} else {
long pivot = median(left, right);
int partition = partition(left, right, pivot);
recQuickSort(left, partition - 1);
recQuickSort(partition + 1, right);
}
}
private long median(int left, int right) {
int mid = (left + right) / 2;
if (instance[left] > instance[mid]) {
swap(left, mid);
}
if (instance[left] > instance[right]) {
swap(left,right);
}
if (instance[mid] > instance[right]) {
swap(mid, right);
}
swap(mid, right);
return instance[right];
}
private int partition(int left, int right, long pivot) {
int leftPtr = left -1;
int rightPtr = right;
while (true) {
while (instance[++leftPtr] < pivot) {
}
while (instance[--rightPtr] > pivot) {
}
if (leftPtr >= rightPtr) {
break;
} else {
swap(leftPtr, rightPtr);
}
}
swap(leftPtr, right);
return leftPtr;
}
private void swap(int left, int mid) {
long temp = instance[mid];
instance[mid] = instance[left];
instance[left] = temp;
}
public static void main(String[] args) {
int maxSize = 10;
QuickSort2 quickSort2 = new QuickSort2(maxSize);
for (int i = 0;i < maxSize;i++) {
long n = (int) (Math.random() * 99);
quickSort2.insert(n);
}
quickSort2.display();
quickSort2.quickSort();
quickSort2.display();
}
}
快速排序的效率:
快速排序的时间复杂度为O(N*logN)。数据随机的数组的划分枢纽可以选择数组最右端的值。数据基本有序的数组的划分枢纽可以选择三数据项取中划分方法。目的都是保证划分后的数组大小左右相等或者相近。