冒泡、选择、插入排序的效率都是O(N^2),但插入排序稍微快一些
归并排序的效率是O(NlogN),希尔排序的效率大约是O(N(logN)2),快速排序需要O(N*logN)时间,希尔排序效率不稳定O(N*N(1.3~2)),理论上归并比快速还要快,但归并要创建新的数组临时存储数据减慢了速度,一般归并和快速速度不相上下。
1.希尔排序
通过加大插入排序中元素之间的间隔,并在这些有间隔的元素中进行插入排序,从而能使数据项能大跨度地移动。当这些数据项排过一趟序后,希尔排序算法减小数据项的间隔再进行排序,并依此下去。
public void shellSort(){
int inner,outer;
long temp;
int h = 1;
while (h<=nElems/3)
h=h*3+1;
while(h>0){
for(outer = h; outer <nElems; outer++){
temp = theArray[outer];
inner = outer;
while(inner>h-1 && theArray[inner-h]>temp){
theArray[inner] = theArray[inner-h];
inner-=h;
}
theArray[inner] = temp;
}
h = (h-1)/3;
}
}
递减序列中的数字互质被认为很重要,这个约束能避免每一趟的排序更有可能保持前一趟排序的效果。
2.快速排序
把数组或者子数组划分成左右两边分别进行划分算法排序,并递归的对左右两边进行排序。
public void recQuickSor(int left,int right){
int size = right-left+1;
if(size<10) {
insertionSort(left, right);
}else{
long median = medianOf3(left,right);
int partition = partitionIt(left,right,median);
recQuickSor(left,partition-1);
recQuickSor(partition+1,right);
}
}
public long medianOf3(int left,int right){
int center = (left+right)/2;
if(theArray[left]>theArray[center]){
swap(left,center);
}
if(theArray[left]>theArray[right]){
swap(left,right);
}
if (theArray[center] > theArray[right]) {
swap(center,right);
}
swap(center,right-1);
return theArray[right-1];
}
public void swap(int dex1,int dex2){
long temp = theArray[dex1];
theArray[dex1] = theArray[dex2];
theArray[dex2] = temp;
}
public int partitionIt(int left,int right,long pivot){
int leftPtr = left;
int rightPtr = right-1;
while (true){
while(theArray[++leftPtr]<pivot);
while (theArray[--rightPtr]>pivot);
if(leftPtr >= rightPtr)
break;
else
swap(leftPtr,rightPtr);
}
swap(leftPtr,right-1);
return leftPtr;
}
public void insertionSort(int left,int right){
int in,out;
for(out = left+1;out<=right;out++){
long temp = theArray[out];
in = out;
while (in>left && theArray[in-1]>=temp){
theArray[in] = theArray[in-1];
--in;
}
theArray[in] = temp;
}
}
枢纽的选用,常见的有采用数组最右端的数据项作为枢纽,而“三数据项取中”可以有效避免枢纽过大或过小产生的效率低下,本例中也是选用“三数据取中”的方式。
3.归并排序
归并算法的中心是归并两个已经有序的数组。通过反复地分割数组,直到的到的子数组只含有一个数据项,然后再用递归的方式归并这些数组。
public void mergeSort(){
long[] workSpace = new long[nElems];
recMergeSort(workSpace,0,nElems-1);
}
public void recMergeSort(long[] workSpace,int lowerBound,int upperBound){
if(lowerBound == upperBound){
return;
}else{
int mid = (lowerBound+upperBound)/2;
recMergeSort(workSpace,lowerBound,mid);
recMergeSort(workSpace,mid+1,upperBound);
merge(workSpace, lowerBound, mid + 1, upperBound);
}
}
public void merge(long[] workSpace,int lowPtr,int highPtr,int upperBound){
int j = 0;
int lowerBound = lowPtr;
int mid = highPtr-1;
int n = upperBound-lowerBound+1;
while (lowPtr<=mid && highPtr<=upperBound){
if(theArray[lowPtr]<theArray[highPtr]){
workSpace[j++] = theArray[lowPtr++];
}else{
workSpace[j++] = theArray[highPtr++];
}
}
while (lowPtr<=mid){
workSpace[j++] = theArray[lowPtr++];
}
while (highPtr<=upperBound){
workSpace[j++] = theArray[highPtr++];
}
for(j=0;j<n;j++){
theArray[lowerBound+j] = workSpace[j];
}
}