未提示來源的算法步驟皆來自於http://kb.cnblogs.com/page/210687/
來源:百度百科之快速排序算法
一.快速排序:
快速排序(Quicksort)是對冒泡排序的一種改進。
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。
算法介紹:
設要排序的數組是A[0]……A[N-1],首先任意選取一個數據(通常選用數組的第一個數)作爲關鍵數據,然後將所有比它小的數都放到它前面,所有比它大的數都放到它後面,這個過程稱爲一趟快速排序。值得注意的是,快速排序不是一種穩定的排序算法,也就是說,多個相同的值的相對位置也許會在算法結束時產生變動。
一趟快速排序的算法是:
1)設置兩個變量i、j,排序開始的時候:i=0,j=N-1;
2)以第一個數組元素作爲關鍵數據,賦值給key,即key=A[0];
3)從j開始向前搜索,即由後開始向前搜索(j–),找到第一個小於key的值A[j],將A[j]和A[i]互換;
4)從i開始向後搜索,即由前開始向後搜索(i++),找到第一個大於key的A[i],將A[i]和A[j]互換;
5)重複第3、4步,直到i=j; (3,4步中,沒找到符合條件的值,即3中A[j]不小於key,4中A[i]不大於key的時候改變j、i的值,使得j=j-1,i=i+1,直至找到爲止。找到符合條件的值,進行交換的時候i, j指針位置不變。另外,i==j這一過程一定正好是i+或j-完成的時候,此時令循環結束)。
排序演示:可參見百度百科中的排序演示。很容易看懂和理解。
快速排序算法步驟:
1從數列中挑出一個元素,稱爲“基準”(pivot),
2重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分區退出之後,該基準就處於數列的中間位置。這個稱爲分區(partition)操作。
3遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。
遞歸的最底部情形,是數列的大小是零或一,也就是永遠都已經被排序好了。雖然一直遞歸下去,但是這個算法總會退出,因爲在每次的迭代(iteration)中,它至少會把一個元素擺到它最後的位置去。
代碼來源:百度百科快速排序算法之Java版本
/**
* 快速排序法,最基本版,效率很低
* 成功通過測試
@param array
* @param low
* @param high
*/
public static void quickSort1(int[] array,int low,int high)
{
int l=low;
int h=high;
int pivot=array[low];
int n=array.length-1;
while(l<h)
{
while(l<h && array[h]>=pivot)
{
h--;
}
if(l<h)
{
int temp=array[h];
array[h]=array[l];
array[l]=temp;
l++;
}
while(l<h&& array[l]<=pivot)
{
l++;
}
if(l<h)
{
int temp=array[h];
array[h]=array[l];
array[l]=temp;
h--;
}
}
print(array);
System.out.print("low="+(low+1)+",h="+(high+1)+",pivot="+pivot+"\n");
if(l>low)quickSort1(array,low,l-1);
if(h<high)quickSort1(array,l+1,high);
}
///*///方式二//////*/
//更高效---- 因對泛型使用比較生疏,所以部分內容沒能修改完善。
public <T extends Comparable<? super T>>T[]quickSort2(T[] targetArr,int start,int end)
{
int i=start+1,j=end;
T key=targetArr[start];
SortUtil<T> sUtil=new SortUtil<T>();
if(start>=end)return(targetArr);
/*從i++和j--兩個方向搜索不滿足條件的值並交換
*
*條件爲:i++方向小於key,j--方向大於key*/
while(true)
{
while(targetArr[j].compareTo(key)>0)j--;
while(targetArr[i].compareTo(key)<0&&i<j)i++;
if(i>=j)break;
sUtil.swap(targetArr,i,j);
if(targetArr[i]==key)
{
j--;
}
else
{
i++;
}
}
//關鍵數據放到‘中間’
sUtil.swap(targetArr,start,j);
if(start<i-1)
{
this.quickSort2(targetArr,start,i-1);
}
if(j+1<end)
{
this.quickSort2(targetArr,j+1,end);
}
return targetArr;
}
/*///////方式三:減少交換次數,提高效率////////*/
//因對泛型掌握不夠,測試未能有效
private <T extends Comparable<? super T>> void quickSort3(T[]targetArr,int start,int end)
{
int i=start,j=end;
T key=targetArr[start];
while(i<j)
{
/*按j--方向遍歷目標數組,直到比key小的值爲止*/
while(j>i&&targetArr[j].compareTo(key)>=0)
{
j--;
}
if(i<j)
{
/*targetArr[i]已經保存在key中,可將後面的數填入*/
targetArr[i]=targetArr[j];
i++;
}
/*按i++方向遍歷目標數組,直到比key大的值爲止*/
while(i<j&&targetArr[i].compareTo(key)<=0)
/*此處一定要小於等於零,假設數組之內有一億個1,0交替出現的話,而key的值又恰巧是1的話,那麼這個小於等於的作用就會使下面的if語句少執行一億次。*/
{
i++;
}
if(i<j)
{
/*targetArr[j]已保存在targetArr[i]中,可將前面的值填入*/
targetArr[j]=targetArr[i];
j--;
}
}
/*此時i==j*/
targetArr[i]=key;
/*遞歸調用,把key前面的完成排序*/
this.quickSort3(targetArr,start,i-1);
/*遞歸調用,把key後面的完成排序*/
this.quickSort3(targetArr,j+1,end);
}
二.堆排序
堆排序(Heapsort)是指利用堆積樹(堆)這種數據結構所設計的一種排序算法,它是選擇排序的一種。可以利用數組的特點快速定位指定索引的元素。堆分爲大根堆和小根堆,是完全二叉樹。大根堆的要求是每個節點的值都不大於其父節點的值,即A[PARENT[i]] >= A[i]。在數組的非降序排序中,需要使用的就是大根堆,因爲根據大根堆的要求可知,最大的值一定在堆頂。(摘自百度百科)
算法步驟:
1.創建一個堆H[0..n-1]
2.把堆首(最大值)和堆尾互換
3.把堆的尺寸縮小1,並調用shift_down(0),目的是把新的數組頂端數據調整到相應位置
4.重複步驟2,直到堆的尺寸爲1
代碼來源:百科-未測試
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);
}
}
代碼:來源http://blog.csdn.net/yunshuixiliu/article/details/21015161
未測試
package sort;
import java.util.Random;
public class HeapSort extends AbstractSort {
public static void sort(Comparable[] a){
buildHeap(a); // 建立堆
for(int i= a.length - 1 ; i >=1 ; i--){
exch(a,0,i);
adjust(a,0,i); //注意i 的值,開始的時候爲length -1
}
}
/**
* 建立大頂堆
* @param a
*/
private static void buildHeap(Comparable[] a){
int length = a.length ;
for(int i = length/2 -1 ; i >= 0 ;i--)
adjust(a,i,length);
}
/*@name adjust
* @Function: 調整以節點 i 爲頂點的堆
*/
private static void adjust(Comparable[] a ,int i,int length){
int left = 2*i + 1,
right= 2*i + 2 ;
if(left >= length && right >= length) return ;
int max = i;
if(left < length && less(a[max],a[left]))
max = left;
if(right <length && less(a[max],a[right]))
max = right ;
if(max!=i){
exch(a,i,max);
adjust(a,max,length);
}
}
public static void main(String[] args){
int N = 10 ;
Integer[] a = new Integer[N];
Random random = new Random();
for(int i = 0; i < N; i++)
a[i] = random.nextInt(30);
sort(a);
show(a);
}
}
三.歸併排序
歸併排序(MERGE-SORT)是建立在歸併操作上的一種有效的排序算法,該算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲二路歸併。
歸併過程爲:比較a[i]和b[j]的大小,若a[i]≤b[j],則將第一個有序表中的元素a[i]複製到r[k]中,並令i和k分別加上1;否則將第二個有序表中的元素b[j]複製到r[k]中,並令j和k分別加上1,如此循環下去,直到其中一個有序表取完,然後再將另一個有序表中剩餘的元素複製到r中從下標k到下標t的單元。歸併排序的算法我們通常用遞歸實現,先把待排序區間[s,t]以中點二分,接着把左邊子區間排序,再把右邊子區間排序,最後把左區間和右區間用一次歸併操作合併成有序的區間[s,t]。(以上摘自百科)
算法步驟:
1.申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列
2.設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置
3.比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置
4.重複步驟3直到某一指針達到序列尾
5.將另一序列剩下的所有元素直接複製到合併序列尾
代碼來源:百科Java未測試
package algorithm;
public class MergeSort {
// private static long sum = 0;
/**
* * <pre>
* * 二路歸併
* * 原理:將兩個有序表合併和一個有序表
* * </pre>
* *
* * @param a
* * @param s
* * 第一個有序表的起始下標
* * @param m
* * 第二個有序表的起始下標
* * @param t
* * 第二個有序表的結束小標
* *
*/
private static void merge(int[] a, int s, int m, int t) {
int[] tmp = new int[t - s + 1];
int i = s, j = m, k = 0;
while (i < m && j <= t) {
if (a[i] <= a[j]) {
tmp[k] = a[i];
k++;
i++;
} else {
tmp[k] = a[j];
j++;
k++;
}
}
while (i < m) {
tmp[k] = a[i];
i++;
k++;
}
while (j <= t) {
tmp[k] = a[j];
j++;
k++;
}
System.arraycopy(tmp, 0, a, s, tmp.length);
}
/**
* *
* * @param a
* * @param s
* * @param len
* * 每次歸併的有序集合的長度
*/
public static void mergeSort(int[] a, int s, int len) {
int size = a.length;
int mid = size / (len << 1);
int c = size & ((len << 1) - 1);
// -------歸併到只剩一個有序集合的時候結束算法-------//
if (mid == 0)
return;
// ------進行一趟歸併排序-------//
for (int i = 0; i < mid; ++i) {
s = i * 2 * len;
merge(a, s, s + len, (len << 1) + s - 1);
}
// -------將剩下的數和倒數一個有序集合歸併-------//
if (c != 0)
merge(a, size - c - 2 * len, size - c, size - 1);
// -------遞歸執行下一趟歸併排序------//
mergeSort(a, 0, 2 * len);
}
public static void main(String[] args) {
int[] a = new int[]{4, 3, 6, 1, 2, 5};
mergeSort(a, 0, 1);
for (int i = 0; i < a.length; ++i) {
System.out.print(a[i] + " ");
}
}
}
代碼來源::http://blog.csdn.net/yunshuixiliu/article/details/21015161未測試
package sort;
import java.util.Random;
public class MerageSort extends AbstractSort {
private static Comparable[] temp ;
public static void sort(Comparable[] a){
temp = new Comparable[a.length] ;
sort(a,0,a.length - 1);
}
/**
* 自底向上歸併
* @param a
*/
public static void sortBU(Comparable[] a){
temp = new Comparable[a.length] ;
int N = a.length ;
for(int step = 1 ;step < N ;step+=step )
for(int left = 0 ;left < N -step ;left += step +step)
merage(a,left,left+step-1,Math.min(left+step+step-1, N-1));
}
/**
* 自頂向下歸併排序
* @param a
* @param left
* @param right
*/
private static void sort(Comparable[] a ,int left ,int right){
if(left >= right) return ;
int mid = left + (right - left ) / 2;
sort(a,left,mid);
sort(a,mid+1,right) ;
// merage(a,left,mid,right);
merageWithoutTemp(a,left,mid,right);
}
/**
* 非原地歸併排序,需要輔助數組
* @param a
* @param left
* @param mid
* @param right
*/
private static void merage(Comparable[] a ,int left,int mid,int right){
int i = left , j = mid + 1;
for(int k = left ; k <= right ; k++)
temp[k] = a[k] ;
for(int k = left ; k <= right ; k++){
if(i > mid) a[k] = temp[j++];
else if(j > right ) a[k] = temp[i++] ;
else if(less(temp[i],temp[j])) a[k] = temp[i++];
else a[k] = temp[j++] ;
}
}
/**
* 原地歸併排序,不需要輔助數組,節省空間
* @param a
* @param left
* @param mid
* @param right
*/
private static void merageWithoutTemp(Comparable[] a ,int left ,int mid , int right ){
int i = left ,j = mid + 1,k =right ;
int step = 0 ;
while(i < j && j <= k){
while(i < j && less(a[i],a[j])) i++;
while(j <= k && less(a[j],a[i])){j++;step++;}
exchang(a,i,j,step);
}
}
private static void exchang(Comparable[] a, int i, int j, int step) {
reverse(a,j-step,j-1);
reverse(a,i,j-step-1);
reverse(a,i,j-1);
}
private static void reverse(Comparable[] a, int begin ,int end){
while(begin <end)
exch(a,begin++,end--);
}
public static void main(String[] args){
int N = 10 ;
Integer[] a = new Integer[N];
Random random = new Random();
for(int i = 0; i < N; i++)
a[i] = random.nextInt(30);
sortBU(a);
show(a);
}
}
四.二分查找算法
二分查找算法是一種在有序數組中查找某一特定元素的搜索算法。搜素過程從數組的中間元素開始,如果中間元素正好是要查找的元素,則搜素過程結束;如果某一特定元素大於或者小於中間元素,則在數組大於或小於中間元素的那一半中查找,而且跟開始一樣從中間元素開始比較。如果在某一步驟數組爲空,則代表找不到。這種搜索算法每一次比較都使搜索範圍縮小一半。折半搜索每次把搜索區域減少一半,時間複雜度爲Ο(logn) 。
五.BFPRT(線性查找算法)
算法步驟:
1.將n個元素每5個一組,分成n/5(上界)組。
2.取出每一組的中位數,任意排序方法,比如插入排序。
3.遞歸的調用selection算法查找上一步中所有中位數的中位數,設爲x,偶數箇中位數的情況下設定爲選取中間小的一個。
4.用x來分割數組,設小於等於x的個數爲k,大於x的個數即爲n-k。
5.若i==k,返回x;若i