捉雞的十大算法簡單學習,整理的相當亂

未提示來源的算法步驟皆來自於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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章