数据结构之排序查找

主要介绍二分查找,插值查找,斐波那契查找,起泡排序,归并排序
算法描述请见注释
归并排序算法描述可以参考http://www.cnblogs.com/jillzhang/archive/2007/09/16/894936.html

/**
 * 数组结构
 * 先排序,后查找
 * @author asdc
 *
 */
public class Array {

     public final static int MAXSIZE = 20;

    /**
     * 二分查找,返回key的位置,没查到返回<0  时间复杂度为O(logN)
     * @param a
     * @param key
     * @return
     */
    public static int binarySearch(long[] a, long key){

        int lo = 0;//起始位置
        int hi = a.length - 1;//终止位置

        while(lo < hi){

            int mid = (lo + hi)/2;//中间位置

            if(key == a[mid]){

                return mid;

            }else if(key > a[mid]){

                lo = mid + 1;

            }else if(key < a[mid]){

                hi = mid - 1;

            }

        }

        return -1;

    }

    /**
     * 插值查找
     * @param a
     * @param key
     * @return
     */
    public static int interpolationSearch(long[] a, long key){

        //插值查找其实跟二分查找差不多,适合大数据量的查找,数据量小的话采用二分查找或者顺序查找效率更高,差值插找主要使用一个公式
        //二分查找公式   mid = (lo + hi)/2
        //公式转换  mid = lo/2 + hi/2    ---->    mid = lo + hi/2 - lo/2  ----> mid = lo + (hi - lo)/2
        //mid = lo + (1/2)(hi - lo)  将1/2换成插值公式    (key - a[lo])/(a[hi] - a[lo])
        //得出结果   mid = lo + (hi - lo) * (key - a[lo])/(a[hi] - a[lo])  这就是插值查找的算法  替换到二分查找中即可

        int lo = 0;//起始位置
        int hi = a.length - 1;//终止位置

        while(lo < hi){

            int mid = (int) (lo + (hi - lo) * (key - a[lo])/(a[hi] - a[lo]));//中间位置

            if(key == a[mid]){

                return mid;

            }else if(key > a[mid]){

                lo = mid + 1;

            }else if(key < a[mid]){

                hi = mid - 1;

            }

        }

        return -1;

    }

    /**
     * 斐波那契查找
     * @param a
     * @param key
     * @return
     */
    public static int fibonacciSearch(long[] a,long key){

        int lo = 0;
        int hi = a.length - 1;

        int[] f = fibonacci();

        int k = 0;//黄金分割下标

        while(a.length > f[k] - 1){

            k++;

        }

        long[] temp = new long[f[k] - 1];
        for(int i = 0; i < a.length; i++){

            temp[i] = a[i];

        }

        // 序列补充至f[k]个元素  
        // 补充的元素值为最后一个元素的值 
        for (int i = a.length; i < f[k] - 1; i++) {  
            temp[i] = temp[hi];  
        }  

        while (lo <= hi) {  
            // low:起始位置  
            // 前半部分有f[k-1]个元素,由于下标从0开始  
            // 则-1 获取 黄金分割位置元素的下标  
            int mid = lo + f[k - 1] - 1;  

            if (temp[mid] > key) {  
                // 查找前半部分,高位指针移动  
                hi = mid - 1;  
                // (全部元素) = (前半部分)+(后半部分)  
                // f[k] = f[k-1] + f[k-2]  
                // 因为前半部分有f[k-1]个元素,所以 k = k-1  
                k = k - 1;  
            } else if (temp[mid] < key) {  
                // 查找后半部分,高位指针移动  
                lo = mid + 1;  
                // (全部元素) = (前半部分)+(后半部分)  
                // f[k] = f[k-1] + f[k-2]  
                // 因为后半部分有f[k-1]个元素,所以 k = k-2  
                k = k - 2;  
            } else {  
                // 如果为真则找到相应的位置  
                if (mid <= hi) {  
                    return mid;  
                } else {  
                    // 出现这种情况是查找到补充的元素  
                    // 而补充的元素与high位置的元素一样  
                    return hi;  
                }  
            }  
        }  
        return -1;  


    } 


    /**
     * 构建斐波那契数列
     * @return
     */
    public static int[] fibonacci(){

        int[] f = new int[MAXSIZE];
        f[0] = 1;
        f[1] = 1;
        for(int i = 2; i < MAXSIZE; i++){

            f[i] = f[i - 1] + f[i - 2];

        }

        return f;

    }

    //查找总结
    //折半查找:进行加法与除法的运算mid = (lo + hi)/2
    //插值查找:进行复杂的四则运算mid = lo + (hi - lo)*(key-a[lo])/(a[hi]-a[lo])
    //斐波那契查找:进行最简单的加减法运算mid = low + f[k-1] - 1 又称换进分割   比值
    //在海量数据查找过程中,这种细微的差别可能会影响最终的效率
    //三种查找方式本质区别为分割点选择不同,各有优劣,实际开发时可根据数据特点进行选择


    /**
     * 气泡排序 低效版
     * @param a
     * @return
     */
    public static void bubbleSort(long[] a){

        boolean isSort = true;//判断是否还有紧邻逆序对

        for(int j = a.length - 1; j > 0; j--){

            for(int i = 0; i < j; i++){

                if(a[i] > a[i + 1]){

                    isSort = false;

                    //交换
                    long temp = a[i + 1];
                    a[i + 1] = a[i];
                    a[i] = temp;

                }

            }

            if(isSort == true){

                break;

            }

        }

    }

    /**
     * 归并排序 算法
     * @param a
     * @param lo
     * @param hi
     */
    public static void Merger(long[] a, int lo, int hi, int mid){

        long[] temp = new long[hi - lo];//临时数组  存放归并比较时的值

        int indexA = lo;
        int indexB = mid;//两端的启示值

        //从两端开始比较大小  将小的值放入temp数组中
        int i = 0;
        while(indexA < mid && indexB < hi){

            if(a[indexA] > a[indexB]){

                temp[i++] = a[indexB++];

            }else{

                temp[i++] = a[indexA++];

            }

        }

        //将剩余的值放入temp中
        while(indexA < mid){

            temp[i++] = a[indexA++];

        }
        while(indexB < hi){

            temp[i++] = a[indexB++];

        }

        //更改a数组
        for (int k2 = 0; k2 < temp.length; k2++) {  
            a[k2 + lo] = temp[k2];  
        }  


    }

    public static void MergerSort(long[] a, int lo, int hi){
        if (hi > lo) //hi - lo > 1
        {
            int mid = (lo + hi) / 2;
            System.out.println("左" + lo + "," + mid);
            MergerSort(a, lo, mid);
            System.out.println("右" + (mid+1) + "," + hi);
            MergerSort(a, mid + 1, hi);
            Merger(a, lo, hi, mid);
        }
    } 

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值