部分內容參考:http://blog.csdn.net/whuslei/article/details/6442755
常見排序算法的時間複雜度:
注:圖片來源http://blog.chinaunix.net/uid-21457204-id-3060260.html
在平均時間複雜度爲O(nlogn)的排序算法中,歸併排序是唯一穩定的。
在平均時間複雜度爲O(n*n)的排序算法中,選擇排序是唯一不穩定的。
最好時間複雜度爲O(n)的排序算法:插入排序、希爾排序、冒泡排序。
時間複雜度和數據的初始排列無關:堆排序、歸併排序、選擇排序。
快速排序、基數排序需要額外空間。
1、冒泡排序
每次遍歷比較相鄰元素大小,通過交換相鄰元素將最大元素後移。
public static void myBubbleSort(int[] arr, int len){
for(int i=0;i<len-1;i++){
boolean flag = true;
for(int j=0;j<len-1-i;j++){
if(arr[j]>arr[j+1]){
swap(arr, j, j+1);
flag = false;
}
}
if(flag)
return;
}
}
相鄰元素相等時不交換。在第一次遍歷中加上標誌位flag,才能使最好情況達到O(n)。
2、選擇排序
每次遍歷直接找出最小元素然後與首位置元素交換。
public static void mySelectSort(int[] arr, int len){
for(int i=0;i<len-1;i++){
int minNo = i;
for(int j=i+1;j<len;j++){
if(arr[j]<arr[minNo]){
minNo = j;
}
}
swap(arr, minNo, i);
}
}
3、插入排序
前n個元素已排序,現將第n+1個元素插入到前n個元素中,因此從後向前依次與前一位元素比較。若前一位小於等於元素n則停止,否則將前一位元素後移。爲了避免交換相鄰元素帶來的額外開銷,可將待插入元素暫存於temp,若前一元素大於元素n,直接賦值arr[n]=arr[n-1],覆蓋原來待插入元素即可。
public static void myInsertSort(int[] arr, int len){
for(int i=1;i<len;i++){
int temp = arr[i];
int j=i-1;
for(;j>=0;j--){
if(arr[j]<=temp){
break;
}else{
arr[j+1]=arr[j];
}
}
arr[j+1]=temp;
}
}
4、快速排序
選取一個數(通常取第一個數),將數組分成兩部分,一部分小於等於該數,一部分大於該數,然後採用遞歸思想,再對這兩部分分別拆分,當拆分後數組長度小於2時遞歸停止。
public static void myQuickSort(int[] arr, int left, int right){
if(right-left<=0){
return;
}
int pivot = arr[left];
int i = left;
int j = right;
while(i<j){
while(arr[j]>pivot&&i<j)
j--;
while(arr[i]<=pivot&&i<j)
i++;
swap(arr,i,j);
}
swap(arr,left,i);
myQuickSort(arr,left,i-1);
myQuickSort(arr,i+1,right);
}
5、希爾排序
希爾排序是插入排序的一種改進。它將記錄按下標的一定增量分組(例,選擇步長d=3,則將arr[0]、arr[3]、arr[6]作爲一組,arr[1]、arr[4]、arr[7]作爲一組,...),然後對每組進行直接插入排序。然後將步長逐步減少,每組元素個數越來越多,當步長減至1時,整個數組合成一組,排序結束。希爾排序的時間複雜度與所選步長有關,一般取初始步長d
= n/2,然後逐步減半。
示例如下,圖片來自百度百科。
public static void myShellSort(int[] arr, int len){
int d = len/2;
while(d>0){
for(int i=d;i<len;i++){
int temp = arr[i];
int j=i-d;
for(;j>=0;j=j-d){
if(arr[j]<=temp){
break;
}else{
arr[j+d]=arr[j];
}
}
arr[j+d]=temp;
}
d = d/2;
}
}
6、歸併排序
歸併排序先將數組拆成一個一個數,每個數認爲是一個有序表,然後將相鄰兩個有序表合併成一個有序表,依次兩兩合併直到只剩一個有序表。一般採用遞歸形式編寫。兩個有序表合併成一個有序表的過程中一般需要使用額外空間,因此空間複雜度爲O(n),因此上表這處有誤。
圖片來源http://www.cnblogs.com/horizonice/p/4102553.html
public static void myMergeSort(int[] arr, int st, int fh){
if(st>=fh){
return;//已經拆成一個數字
}else{
int mid = (st+fh)/2;
myMergeSort(arr, st, mid);
myMergeSort(arr, mid+1, fh);
Merge(arr, st, mid, fh);//將兩個有序表arr[st:mid]和arr[mid+1:fh]合併成一個
}
}
static int[] temp = new int[arr.length];
public static void Merge(int[] arr, int st, int mid, int fh){
int i = st; //兩個指針指向兩個子有序表的開頭
int j = mid+1;
int k = 0;
while(i<=mid&&j<=fh){
if(arr[i]<=arr[j]){
temp[k] = arr[i];
i++;
k++;
}else{
temp[k] = arr[j];
j++;
k++;
}
}
while(i<=mid){
temp[k] = arr[i];
i++;
k++;
}
while(j<=fh){
temp[k] = arr[j];
j++;
k++;
}
for(int n=0;n<k;n++){
arr[st+n] = temp[n];
}
}
7、堆排序
堆排序是利用堆這種數據結構進行排序的算法。堆這種數據結構是一種特殊的完全二叉樹,最大堆要求每個節點的值都不大於其父節點的值;反之,最小堆要求每個節點的值都不小於其父節點的值。
堆排序詳細內容見:http://www.cnblogs.com/mengdd/archive/2012/11/30/2796845.html,講的很好。
public class HeapSort{
private static int[] sort=new int[]{1,0,10,20,3,5,6,4,9,8,12,17,34,11};
public static void main(String[] args){
buildMaxHeapify(sort);
heapSort(sort);
print(sort);
}
private static void buildMaxHeapify(int[] data){
//沒有子節點的才需要創建最大堆,從最後一個的父節點開始
int startIndex=getParentIndex(data.length-1);
//從尾端開始創建最大堆,每次都是正確的堆
for(int i=startIndex;i>=0;i--){
maxHeapify(data,data.length,i);
}
}
/**
*創建最大堆
*
*@paramdata
*@paramheapSize需要創建最大堆的大小,一般在sort的時候用到,因爲最多值放在末尾,末尾就不再歸入最大堆了
*@paramindex當前需要創建最大堆的位置
*/
private static void maxHeapify(int[] data,int heapSize,int index){
//當前點與左右子節點比較
int left=getChildLeftIndex(index);
int right=getChildRightIndex(index);
int largest=index;
if(left<heapSize&&data[index]<data[left]){
largest=left;
}
if(right<heapSize&&data[largest]<data[right]){
largest=right;
}
//得到最大值後可能需要交換,如果交換了,其子節點可能就不是最大堆了,需要重新調整
if(largest!=index){
int temp=data[index];
data[index]=data[largest];
data[largest]=temp;
maxHeapify(data,heapSize,largest);
}
}
/**
*排序,最大值放在末尾,data雖然是最大堆,在排序後就成了遞增的
*
*@paramdata
*/
private static void heapSort(int[] data){
//末尾與頭交換,交換後調整最大堆
for(int i=data.length-1;i>0;i--){
int temp=data[0];
data[0]=data[i];
data[i]=temp;
maxHeapify(data,i,0);
}
}
/**
*父節點位置
*
*@paramcurrent
*@return
*/
private static int getParentIndex(int current){
return(current-1)>>1;
}
/**
*左子節點position注意括號,加法優先級更高
*
*@paramcurrent
*@return
*/
private static int getChildLeftIndex(int current){
return(current<<1)+1;
}
/**
*右子節點position
*
*@paramcurrent
*@return
*/
private static int getChildRightIndex(int current){
return(current<<1)+2;
}
private static void print(int[] data){
int pre=-2;
for(int i=0;i<data.length;i++){
if(pre<(int)getLog(i+1)){
pre=(int)getLog(i+1);
System.out.println();
}
System.out.print(data[i]+"|");
}
}
/**
*以2爲底的對數
*
*@paramparam
*@return
*/
private static double getLog(double param){
return Math.log(param)/Math.log(2);
}
}