Loading

算法和数据结构 2 二分

二分

关于二分的基本原则

我们首先希望二分算法有这样的性质:当二分范围内有 2 个或以上元素时,他必定会收缩到只剩 1 个元素,而只剩 1 个元素时,二分范围

  1. 不再变化,进入不动点
  2. 或者变为 0退出或者进入不动点

然后,我们可能关心二分中点是否被保留下来,也就是说:二分范围 [l..mid..r],在下一个迭代周期当中

  • 是变为 [l..mid][mid..r]
  • 还是变为 [l..mid-1][mid+1..r]

又或者能更灵活地视情况而定,选取为

  • [l..mid][mid+1..r]
  • 或者 [l..mid-1][mid..r]

这四种情况完全由 l, r, mid 的更新方式来决定,下面具体分析

例 1

STL 的迭代器采用的是这样的边界:

对于数组 int a[10]int l = 0, r = 10

这样的边界选取在二分查找中有怎样的性质呢?

规定

  • mid 的更新方式 int mid = (l+r)/2
  • 同时规定二分边界这样收紧:l = midr = mid

那么我们可以得到以下三条:

  1. n >= 1 时恒有 l < r
    • 假设还有 n >= 2 个元素,那么 l + n = r,此时计算 mid:

    \[\begin{aligned} mid &= \lfloor(l+r)/2 \rfloor \\ &= \lfloor (2l + n)/2 \rfloor \\ &= l+ \lfloor n/2 \rfloor \end{aligned}\\ \downarrow\\ \begin{aligned} mid = &\begin{cases} l+(n-1)/2& odd & (n \ge 3) \\ l+n/2 & even & (n \ge 2) \end{cases}\\ = &\begin{cases} r-(n+1)/2& odd & (n \ge 3) \\ r-n/2 & even & (n \ge 2) \end{cases} \end{aligned}\\ \downarrow\\ \]

\[ l+1 \le mid \le r-1 \tag{1} \]

所以当边界更新时
- l = mid,此时 l <= r-1 故还有至少一个元素
- r = mid,此时 l+1 <= r 故至少还有一个元素

  • 因此 2 个以上元素都不会越过只剩 1 个元素的情形,收敛到只剩 0 个元素。同时由不等式 \((1)\) 可知 l, rn >= 2 的情形下是严格单调增减的。
    因而必然收敛到 n = 1
    n = 1 时:l+1=r,计算 mid 必有:

    \[mid=l \]

    l 不会有变化,算法到达不动点,r 会缩减到 l,下一次迭代时进入不动点
  1. n >= 1 时恒有 mid < r
    由上面的计算显然

  2. 恒有 l <= mid
    这个即使 n=0 时也成立

例 2

将上面例子的 r = mid 改为 r = mid+1,这样二分中点 mid 每次都会被保留在下一次迭代的二分范围当中

此时 n=1 时,下一个迭代周期不会退出,而是进入不动点。
但要注意的是 n=2 时,也可能进入不动点

posted @ 2021-10-29 14:11  人中之人  阅读(53)  评论(0)    收藏  举报