减治法在查找算法中的应用(JAVA)--快速查找

减治法在查找算法中的应用

快速查找:选择问题是求一个n个数列表的第k个最小元素的问题,这个数k被称为顺序统计量。对于k=1或k=n来说,这并没有什么意义,我们通常会要找出这样的元素:该元素比列表中一半元素大,比另一半元素小,这样的元素被称为中值。我们当然可以对列表进行排序,之后找出对应下标的值,但是!!!这样一个查找问题,反而要对整个列表排序,是不是有点多余了呢?

这里引入划分的概念我们可以标定一个枢轴(任意元素,一般为首个元素),使得左半部分元素均小于枢轴,右半部分均大于枢轴。划分的方法由两种,Lomuto划分和Hoare划分。这里仅介绍Lomuto。

我们假设有一个数组a[0, n-1],其子数组为a[l, r](0 <= l <= r <= n-1),假定首个元素为枢轴p,将该数组分为三段,顺序放在p之后,依次为,第一段[元素小于p],第二段[元素大于等于p],第三段[尚未处理元素]。算法开始时前两段均为空。

从i = l+1开始,从左到右扫描子数组a[l, r],将第三段的首个元素与p比较,若a[i]>=p,执行i+1,这就相当于将a[i]划入了第二段,同时缩小了第三段;若a[i]<p,需要将s+1(s始终指向第一段的末位元素),同时交换a[i]与a[s],之后i+1。直到第三段为空,交换a[p]与a[s]。

下图为Lomuto划分示意图:


熟悉快速排序的读者估计看出来了,这就是快速排序中的一部分函数,只不过没有接触过Lomuto这种叫法而已。

当然,我们这里使用的方法就是快速选择(“快速”这一方法一开始并非用于排序,而是查找),下面给出查找第k小元素的代码:

public class Main {
    static int[] a= {89, 45, 68, 90, 29, 34, 17};
    static int k = 2;
    public static void main(String[] args) {
        System.out.println(fastsort(0, a.length-1, k));

        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i] + " ");
        }
    }

    private static int Lomuto(int l, int r) {
        int p = a[l];
        int s = l;
        for (int i = l+1; i <= r; i++) {
            if (a[i] < p) {
                s = s+1;
                int temp = a[s];
                a[s] = a[i];
                a[i] = temp;
            }
        }
        int temp = a[l];
        a[l] = a[s];
        a[s] = temp;
        return s;
    }
    private static int fastsort(int l, int r, int k) {
        int s = Lomuto(l, r);
        /**
         * s在划分之后变成了枢轴所在的位置下标,如果s=k,输出a[s]
         * 这里要写成l+k-1,如果划分到右侧,只写k会出问题
         * */
        if (s == l + k - 1) {
            return a[s];
        }else if (s > l + k - 1){
            return fastsort(l, s-1, k);
        } else {
            return fastsort(s+1, r, l+k-1-s);
        }
    }
}
不幸的是,这样的算法时间复杂度为O(n^2),比之前基于排序的方法实际上更糟糕,但是分析表明,这种方法的平均情况下效率是线性的。而且基于划分的算法不仅可以查找第k小的元素,还可以给出列表中k个最小元素和n-k个最大元素。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值