本文根據個人需要,相對排序算法進行學習。
且主要分爲兩部分:
常用排序算法實現(快速、二分查找、計數排序)
多種算法比較
————————————————————————————————————
1、快速排序
主要思想:選取一個關鍵數據(隔板),依次遍歷數據,如果數據比隔板大,則放到隔板後面,如果比隔板小,則放到隔板前面。這樣一趟排序就可以把隔板元素的最終位置確定下來,然後依次遞歸確定其他元素位置。
快速排序關鍵的地方在於隔板函數partition的實現,它可以確定隔板元素的最終位置並返回最終下標。
這裏有兩種實現方法
第一種:劍指offer中
public int partition(int data[],int start,int end){
if(data==null||data.length<1||start<0||end>data.length-1)
return -1;
//small爲每次遞歸開始的下標前一個位置,這樣只有有滿足小於隔板值纔會移動
int small=start-1;
//i<=end也沒用 只會增加一次循環,因爲不滿足data[end]<data[end]
for(int i=start;i<end;i++){
//不能等於 只能小於 因爲small代表小於其值的最右下標,否則 直接跨過 出現data[end]左邊值爲等於和小於data[end],多餘的計算比較
//如果中間有>=隔板元素data[end]的值,則small不會++,除非後面有<data[end]的元素,然後small++,並交換>=和小於data[end]值交換,此時small值仍是最右小於隔板元素的下標。
if(data[i]<data[end]){
++small;
if(i!=small){
swap(data,i,small);
}
}
}
//small的值爲最右邊小於隔板值得下標,所以small+1就是隔板元素的最終下標
++small;
swap(data,small,end);
return small;
}
第二種:最簡單常見的
public int partition(int data[],int start,int end){
if(data==null||data.length<1||start<0||end>data.length-1)
return -1;
int l=start;
int h=end;
int povit=data[start];
while(l<h){
while(data[h]>=povit&&l<h)
h--;
if(l<h){
swap(data,l,h);
l++;
}
while(data[l]<=povit&&l<h)
l++;
if(l<h){
swap(data,l,h);
h--;
}
}
return l;
}
快速排序
public void quickSort(int data[],int start,int end){
//遞歸結束條件
if(start==end)
return;
int index=partition(data,start,end);
if(index>start)
quickSort(data,start,index-1);
if(index<end)
quickSort(data,index+1,end);
}
2、二分查找
public class BinarySearch {
public static int binarySearch(int data[],int des){
if(data==null||data.length<1)
return -1;
int l=0;
int h=data.length-1;
//<=包含等於是可能有這種情況 小標爲3和4 mid=3,但是3<key(4),l++=h 這個時候如果不能等於則會丟失可能找不到
while(l<=h){
int mid=(l+h)/2;
if(data[mid]==des)
return mid;
else if(data[mid]>des)
h=mid-1;
else
l=mid+1;
}
return -1;
}
3、計數排序
一般適用於輸入數組值取值範圍一定,比如取值0-k或者年齡小於100等
例題:輸入一個長度爲n的非負整數數組,取值範圍爲0-k,請用線性時間複雜度完成排序
public int [] countingSort(int data[],int k){
if(data==null||data.length<1||k<0)
return null;
int numbers[]=new int[k+1];
int result[]=new int[data.length];
for(int i=0;i<data.length;i++){
numbers[data[i]]++;
}
for(int i=1;i<=k;i++){
numbers[i]=numbers[i]+numbers[i-1];
}
for(int i=data.length-1;i>=0;i--){
result[numbers[data[i]]-1]=data[i];
numbers[data[i]]--;
}
return result;
}
不需要額外存儲空間
public int [] countSort(int data[],int k){
if(data==null||data.length<1||k<0)
return null;
int numbers[]=new int[k+1];
for(int i=0;i<data.length;i++){
numbers[data[i]]++;
}
int index=0;
for(int i=0;i<=k;i++){
for(int j=0;j<numbers[i];j++){
data[index]=i;
index++;
}
}
return data;
}
各個算法的比較
冒泡排序與選擇排序區別:冒泡排序每次選擇剩餘最大的放在後面,比較進行交換,在這過程中可能會發生多次交換,而選擇排序可以選擇剩餘比較小的放在前面,但是過程中發生交換次數比較少,基本是最後找到剩餘最小的放在對應的位置。
插入排序與選擇排序區別:插入排序也是從前面開始有序區,但是前面有序區並非元素最終位置,會根據後面元素大小來調位置,而選擇則是最終位置。