算法设计与分析——两个序列的中位数(Java)

【问题】设无序序列 T=(r_{1}r_{2},...,r_{n}),T 的第 k(1 ≤ k ≤ n) 小元素定义为 T 按升序排列后在第 k 个位置上的元素。给定一个序列 T 和一个整数 k,寻找 T 的第 k 小元素的问题称为选择问题(choice problem)。特别地,将寻找第 n/2 小元素的问题称为中值问题( median problem)。

【想法】选择问题的一个很自然的想法是将序列 T 排序,然后取第 k 个元素就是 T 的第 k 小元素。但是这个算法的最好时间是O(nlog_{2}n)应用减治技术可以将算法的平均时间性能提高到O(n)。
       考虑快速排序的划分过程,一般情况下,设待划分的序列为 r_{i}~r_{j},选定一个轴值对序列 r_{i}~r_{j}进行划分,使得比轴值小的元素都位于轴值的左侧,比轴值大的元素都位于轴值的右侧,假定轴值的最终位置是 s,则:

(1) 若 k=s,则 r_{i} 就是第 k 小元素;

(2) 若 k<s,则第 k 小元素一定在序列 r_{i}~r_{s-1} 中;

(3) 若 k>s,则第 k 小元素一定在序列 r_{s+1}~r_{j} 中。

       无论哪种情况,或者已经得出结果,或者将选择问题的查找区间减少一半(如果轴值恰好是序列的中值)。选择问题的减治思想如下图所示。

下图给出了一个选择问题的例子(查找第4小元素)。

【算法】减治法求解选择问题的算法用伪代码描述如下。

算法:选择问题 SelectMink

输入:无序序列 {r_{1}r_{2},...,r_{n}},位置 k

输出:返回第 k 小的元素值

1.设置初始查找区间:i=1;j=n;

2.以 r_{i} 为轴值对序列 r_{i}~r_{j} 进行一次划分,得到轴值的位置 s;

3.将轴值位置 s 与 k 比较

    3.1 如果 k 等于 s,则将 r_{i} 作为结果返回;

    3.2 如果 k < s,则 j=s-1,转步骤2;

    3.3 如果 k > s,则 i=s+1,转步骤2。

【算法分析】与快速排序类似,算法 SelectMink 的效率取决于轴值的选取。如果每次划分的轴值恰好是序列的中值,则可以保证处理的区间比上一次减半,由于在一次划分后,只需处理一个子序列,所以,比较次数的递推式应该是:

       使用扩展递归技术对递推式进行推导,得到该递推式的解是O(n),这是最好情况;如果每次划分的轴值恰好是序列中的最大值或最小值(例如,在找最小元素时总是在最大元素处划分),则处理区间只能比上一次减少1个,所以,比较次数的递推式应该是:

 

       使用扩展递归技术对递推式进行推导,得到该递推式的解是O(n^{2}),这是最坏情况;平均情况下,假设每次划分的轴值是划分序列中的一个随机位置的元素,则处理区间按照一种随机的方式减少,可以证明,算法 SelectMink 可以在 O(n) 的平均时间内找出 n 个元素中的第 k 小元素。 ·

【算法实现】算法用JAVA语言描述如下:

public class SelectMink {
    public static void main(String[] args)
    {
        int r[]={5,3,8,1,10,6,9,12,17};
        int k = 3;
        int x = MinK(r,0,8,k-1);
        System.out.println("第"+k+"最小的元素是"+x);
    }

    static int Partition(int r[], int low, int high)          //划分
    {
        int i = low, j=high;                       //初始化待划分区间
        while (i < j)
        {
            while (i < j && r[i] <= r[j]) j--;          //右侧扫描
            if (i < j) {
                int temp = r[i]; r[i] = r[j]; r[j] = temp;     //将较小记录交换到前面
                i++;
            }
            while (i < j && r[i] <= r[j]) i++;         //左侧扫描
            if (i < j) {
                int temp = r[i]; r[i] = r[j]; r[j] = temp;     //将较大记录交换到后面
                j--;
            }
        }
        return i;                                // 返回轴值记录的位置
    }

    static int MinK(int r[], int low, int high, int k)  //k为第k小元素
    {
        int s;              //s为轴值位置
        s = Partition(r, low, high);
        if (s == k)
            return r[s];
        if(s > k)
            return MinK(r, low, s-1, k);
        else
            return MinK(r, s+1, high, k);
    }

}

运行结果如下:

from:算法设计与分析(第2版)——王红梅 胡明 编著——清华大学出版社

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值