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

【问题】一个长度为 n(n≥1) 的升序序列 S,处在第 n/2 个位置的数称为序列 S 的中位数(median number),例如,序列 S1={11,13,15,17,19} 的中位数是 15。两个序列的中位数是它们所有元素的升序序列的中位数,例如,S2={2,4,6,8,20},则 S1 和 S2 的中位数是11。现有两个等长升序序列 A 和 B,试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列的中位数。

【想法】算法的基本思想如下。

(1)分别求出两个序列的中位数,记为 a 和 b 。

(2)比较 a 和 b,有下列三种情况:
a=b,则 a 即为两个序列的中位数;
a<b,则中位数只能出现在 a 和 b 之间,在序列 A 中舍弃 a 之前的元素得到序列 A1,在序列 B 中舍弃 b 之后的元素得到序列 B1;
a>b,则中位数只能出现在 b 和 a 之间,在序列 A 中舍弃 a 之后的元素得到序列 A1,在序列 B 中舍弃 b 之前的元素得到序列 B1。

(3)在 A1 和 B1 中分别求出中位数,重复上述过程,直到两个序列中只有一个元素,则较小者即为所求。

例如,对于两个给定的序列 A={11,13,15,17,19},B={2,4,10,15,20},求序列 A 和 B 的中位数的过程如下表所示,在求解过程中注意保持两个序列的长度相等。


 

【算法】减治法求解两个序列中位数的算法用伪代码描述如下。

算法:两个序列中位数 SearchMid

输入:两个长度为 n 的有序序列 A 和 B

输出:序列 A 和 B 的中位数

1.循环直到序列 A 和序列 B 均只有一个元素

    1.1 a=序列 A 的中位数;

    1.2 b=序列 B 的中位数;

    1.3 比较 a 和 b,执行下面三种情况之一:

        1.3.1 若a=b,则返回 a,算法结束;

        1.3.2 若a<b,则在序列 A 中舍弃 a 之前的元素,在序列 B 中舍弃 b 之后的元素,转步骤1;

        1.3.3 若a>b,则在序列 A 中舍弃 a 之后的元素,在序列 B 中舍弃 b 之前的元素,转步骤1,

2.序列 A 和序列 B 均只有一个元素,返回较小者。

【算法分析】由于每次求两个序列的中位数后,得到的两个子序列的长度都是上一个序列的一半,因此,循环共执行log_{2}n次,时间复杂性为O(log_{2}n)。算法除简单变量外没有额外开辟临时空间,因此,空间复杂性为O(1)。

【算法实现】为了记载序列 A 和序列 B 在不断查找过程中的变化,用下标 s1 和 e1 表示序列 A 的上下界,用下标 s2 和 e2 表示序列 B 的上下界,算法用JAVA语言描述如下:

public class lgxldzws {
    public static void main(String[] args)
    {
        int A[]={1,2,3,5,7};
        int B[]={2,4,6,8,10};
        int mid=SearchMid(A,B,5);
        System.out.println("两个序列的中位数是:"+mid);
    }
    static int SearchMid(int A[], int B[], int n)
    {
        int s1 = 0, e1 = n - 1, s2 = 0, e2 = n-1;           //初始化两个序列的上下界
        int mid1, mid2;
        while (s1 < e1 && s2 < e2)                   //循环直到区间只有一个元素
        {
            mid1= (s1 + e1)/2;                        //序列A的中位数的下标
            mid2 = (s2 + e2)/2;                       //序列B的中位数的下标
            if (A[mid1] == B[mid2]) return A[mid1];     //第①种情况
            if (A[mid1] < B[mid2])                    //第②种情况
            {
                if ((s1 + e1) % 2 == 0)
                    s1 = mid1;
                else
                    s1 = mid1 + 1;                    //保证两个子序列的长度相等
                e2 = mid2;
            }
            else
            {
                if ((s2 + e2) % 2 == 0)
                    s2 = mid2;
                else
                    s2 = mid2 + 1;                       //保证两个子序列的长度相等
                e1 = mid1;

            }
        }
        if (A[s1] < B[s2]) return A[s1];              //较小者为所求
        else return B[s2];
    }

}

运行结果如下:

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

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值