捉鸡的十大算法简单学习,整理的相当乱

未提示来源的算法步骤皆来自于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

点赞