简体   繁体   English

什么会导致算法具有O(log n)复杂度?

[英]What would cause an algorithm to have O(log n) complexity?

My knowledge of big-O is limited, and when log terms show up in the equation it throws me off even more. 我对big-O的了解是有限的,当日志术语出现在等式中时,它会让我更加惊讶。

Can someone maybe explain to me in simple terms what a O(log n) algorithm is? 有人可以用简单的语言向我解释一下O(log n)算法是什么吗? Where does the logarithm come from? 对数来自哪里?

This specifically came up when I was trying to solve this midterm practice question: 当我试图解决这个中期练习题时,这个问题就出现了:

Let X(1..n) and Y(1..n) contain two lists of integers, each sorted in nondecreasing order. 设X(1..n)和Y(1..n)包含两个整数列表,每个整数以非递减顺序排序。 Give an O(log n)-time algorithm to find the median (or the nth smallest integer) of all 2n combined elements. 给出O(log n)-time算法以找到所有2n个组合元素的中值(或第n个最小整数)。 For ex, X = (4, 5, 7, 8, 9) and Y = (3, 5, 8, 9, 10), then 7 is the median of the combined list (3, 4, 5, 5, 7, 8, 8, 9, 9, 10). 例如,X =(4,5,7,8,9)和Y =(3,5,8,9,10),那么7是组合列表的中位数(3,4,5,5,7) ,8,8,9,9,10)。 [Hint: use concepts of binary search] [提示:使用二分搜索的概念]

I have to agree that it's pretty weird the first time you see an O(log n) algorithm... where on earth does that logarithm come from? 我必须同意,第一次看到O(log n)算法时,这很奇怪......这个对数来自何处? However, it turns out that there's several different ways that you can get a log term to show up in big-O notation. 但是,事实证明,有几种不同的方法可以让日志术语以big-O表示法显示。 Here are a few: 以下是一些:

Repeatedly dividing by a constant 反复划分常数

Take any number n; 拿任何数字n; say, 16. How many times can you divide n by two before you get a number less than or equal to one? 比方说,16。在得到小于或等于1的数字之前,你可以将n除以2的次数? For 16, we have that 对于16岁,我们有

16 / 2 = 8
 8 / 2 = 4
 4 / 2 = 2
 2 / 2 = 1

Notice that this ends up taking four steps to complete. 请注意,这最终需要完成四个步骤。 Interestingly, we also have that log 2 16 = 4. Hmmm... what about 128? 有趣的是,我们还有那个日志2 16 = 4.嗯...... 128怎么样?

128 / 2 = 64
 64 / 2 = 32
 32 / 2 = 16
 16 / 2 = 8
  8 / 2 = 4
  4 / 2 = 2
  2 / 2 = 1

This took seven steps, and log 2 128 = 7. Is this a coincidence? 这需要七个步骤,并记录2 128 = 7.这是巧合吗? Nope! 不! There's a good reason for this. 这是有充分理由的。 Suppose that we divide a number n by 2 i times. 假设我们将数n除以2次i次。 Then we get the number n / 2 i . 然后我们得到数字n / 2 i If we want to solve for the value of i where this value is at most 1, we get 如果我们想要求解这个值最多为1的i的值,我们得到

n / 2 i ≤ 1 n / 2个I≤1

n ≤ 2 i N≤2 I

log 2 n ≤ i 日志2 N≤我

In other words, if we pick an integer i such that i ≥ log 2 n, then after dividing n in half i times we'll have a value that is at most 1. The smallest i for which this is guaranteed is roughly log 2 n, so if we have an algorithm that divides by 2 until the number gets sufficiently small, then we can say that it terminates in O(log n) steps. 换句话说,如果我们选择我整数,使得I≥日志2 n,则除以n的一半了i次后,我们将有一个值,该值至多为1.我指此保证最小的大致2登录n,所以如果我们有一个除以2的算法直到数字变得足够小,那么我们就可以说它终止于O(log n)步骤。

An important detail is that it doesn't matter what constant you're dividing n by (as long as it's greater than one); 一个重要的细节是,你将n除以的是什么常数并不重要(只要它大于1); if you divide by the constant k, it will take log k n steps to reach 1. Thus any algorithm that repeatedly divides the input size by some fraction will need O(log n) iterations to terminate. 如果除以常数k,则需要log k n步才能达到1.因此,任何重复将输入大小除以某个分数的算法都需要O(log n)次迭代才能终止。 Those iterations might take a lot of time and so the net runtime needn't be O(log n), but the number of steps will be logarithmic. 那些迭代可能需要花费很多时间,因此净运行时不必是O(log n),但步数将是对数的。

So where does this come up? 那么这会出现在哪里? One classic example is binary search , a fast algorithm for searching a sorted array for a value. 一个典型的例子是二进制搜索 ,这是一种快速算法,用于搜索排序数组中的值。 The algorithm works like this: 该算法的工作方式如下:

  • If the array is empty, return that the element isn't present in the array. 如果数组为空,则返回元素不在数组中。
  • Otherwise: 除此以外:
    • Look at the middle element of the array. 查看数组的中间元素。
    • If it's equal to the element we're looking for, return success. 如果它等于我们正在寻找的元素,那么返回成功。
    • If it's greater than the element we're looking for: 如果它大于我们正在寻找的元素:
      • Throw away the second half of the array. 扔掉阵列的后半部分。
      • Repeat 重复
    • If it's less than the the element we're looking for: 如果它小于我们正在寻找的元素:
      • Throw away the first half of the array. 扔掉阵列的前半部分。
      • Repeat 重复

For example, to search for 5 in the array 例如,要在数组中搜索5

1   3   5   7   9   11   13

We'd first look at the middle element: 我们先来看看中间元素:

1   3   5   7   9   11   13
            ^

Since 7 > 5, and since the array is sorted, we know for a fact that the number 5 can't be in the back half of the array, so we can just discard it. 从7> 5开始,由于数组已经排序,我们知道数字5不能在数组的后半部分,所以我们可以放弃它。 This leaves 这离开了

1   3   5

So now we look at the middle element here: 所以现在我们来看看这里的中间元素:

1   3   5
    ^

Since 3 < 5, we know that 5 can't appear in the first half of the array, so we can throw the first half array to leave 由于3 <5,我们知道5不能出现在数组的前半部分,所以我们可以抛出前半部分数组离开

        5

Again we look at the middle of this array: 我们再次看一下这个数组的中间部分:

        5
        ^

Since this is exactly the number we're looking for, we can report that 5 is indeed in the array. 由于这正是我们正在寻找的数字,我们可以报告5确实在数组中。

So how efficient is this? 那么效率如何呢? Well, on each iteration we're throwing away at least half of the remaining array elements. 好吧,在每次迭代中,我们丢弃了至少一半剩余的数组元素。 The algorithm stops as soon as the array is empty or we find the value we want. 一旦数组为空或我们找到我们想要的值,算法就会停止。 In the worst case, the element isn't there, so we keep halving the size of the array until we run out of elements. 在最坏的情况下,元素不存在,所以我们将数组的大小减半,直到元素耗尽为止。 How long does this take? 这需要多长时间? Well, since we keep cutting the array in half over and over again, we will be done in at most O(log n) iterations, since we can't cut the array in half more than O(log n) times before we run out of array elements. 好吧,既然我们一遍又一遍地将数组切成两半,我们将在大多数O(log n)次迭代中完成,因为在运行之前我们不能将数组切割为O(log n)次的一半以上超出数组元素。

Algorithms following the general technique of divide-and-conquer (cutting the problem into pieces, solving those pieces, then putting the problem back together) tend to have logarithmic terms in them for this same reason - you can't keep cutting some object in half more than O(log n) times. 按照一般分治技术(将问题分解成碎片,解决这些碎片,然后将问题重新组合在一起)的算法往往会出于对数术语出于同样的原因 - 你不能继续削减一些对象比O(log n)倍多一半。 You might want to look at merge sort as a great example of this. 您可能希望将merge sort视为一个很好的例子。

Processing values one digit at a time 一次处理一位数值

How many digits are in the base-10 number n? 基数为10的数字是多少位? Well, if there are k digits in the number, then we'd have that the biggest digit is some multiple of 10 k . 好吧,如果数字中有k个数字,那么我们的最大数字是10 k的倍数。 The largest k-digit number is 999...9, k times, and this is equal to 10 k + 1 - 1. Consequently, if we know that n has k digits in it, then we know that the value of n is at most 10 k + 1 - 1. If we want to solve for k in terms of n, we get 最大的k位数是999 ... 9,k次,这等于10 k + 1 - 1.因此,如果我们知道n中有k个数字,那么我们知道n的值是最多10 k + 1 - 1.如果我们想用n求解k,我们得到

n ≤ 10 k+1 - 1 n≤10k + 1 - 1

n + 1 ≤ 10 k+1 n +1≤10k + 1

log 10 (n + 1) ≤ k + 1 log 10 (n + 1)≤k+ 1

(log 10 (n + 1)) - 1 ≤ k (log 10 (n + 1)) - 1≤k

From which we get that k is approximately the base-10 logarithm of n. 从中我们得到k大约是n的基数-10对数。 In other words, the number of digits in n is O(log n). 换句话说,n中的位数是O(log n)。

For example, let's think about the complexity of adding two large numbers that are too big to fit into a machine word. 例如,让我们考虑添加两个太大而不适合机器字的大数字的复杂性。 Suppose that we have those numbers represented in base 10, and we'll call the numbers m and n. 假设我们将这些数字表示在基数10中,我们将数字称为m和n。 One way to add them is through the grade-school method - write the numbers out one digit at a time, then work from the right to the left. 添加它们的一种方法是通过小学 - 学校方法 - 一次写出一位数字,然后从右到左工作。 For example, to add 1337 and 2065, we'd start by writing the numbers out as 例如,要添加1337和2065,我们首先将数字写为

    1  3  3  7
+   2  0  6  5
==============

We add the last digit and carry the 1: 我们添加最后一位数字并带1:

          1
    1  3  3  7
+   2  0  6  5
==============
             2

Then we add the second-to-last ("penultimate") digit and carry the 1: 然后我们添加倒数第二个(“倒数第二个”)数字并携带1:

       1  1
    1  3  3  7
+   2  0  6  5
==============
          0  2

Next, we add the third-to-last ("antepenultimate") digit: 接下来,我们添加倒数第三个(“antepenultimate”)数字:

       1  1
    1  3  3  7
+   2  0  6  5
==============
       4  0  2

Finally, we add the fourth-to-last ("preantepenultimate"... I love English) digit: 最后,我们添加倒数第四个(“preantepenultimate”......我爱英语)数字:

       1  1
    1  3  3  7
+   2  0  6  5
==============
    3  4  0  2

Now, how much work did we do? 现在,我们做了多少工作? We do a total of O(1) work per digit (that is, a constant amount of work), and there are O(max{log n, log m}) total digits that need to be processed. 我们每个数字总共进行O(1)工作(即,一定量的工作),并且有需要处理的O(max {log n,log m})总数。 This gives a total of O(max{log n, log m}) complexity, because we need to visit each digit in the two numbers. 这给出了总共O(max {log n,log m})的复杂度,因为我们需要访问两个数字中的每个数字。

Many algorithms get an O(log n) term in them from working one digit at a time in some base. 许多算法在某些基础上一次只能处理一个数字,从而获得O(log n)项。 A classic example is radix sort , which sorts integers one digit at a time. 一个典型的例子是基数排序 ,它一次对一个数字排序整数。 There are many flavors of radix sort, but they usually run in time O(n log U), where U is the largest possible integer that's being sorted. 有许多种基数排序,但它们通常在时间O(n log U)中运行,其中U是被排序的最大可能整数。 The reason for this is that each pass of the sort takes O(n) time, and there are a total of O(log U) iterations required to process each of the O(log U) digits of the largest number being sorted. 这样做的原因是排序的每次传递花费O(n)时间,并且处理被排序的最大数字的每个O(log U)数字所需的总共O(log U)次迭代。 Many advanced algorithms, such as Gabow's shortest-paths algorithm or the scaling version of the Ford-Fulkerson max-flow algorithm , have a log term in their complexity because they work one digit at a time. 许多高级算法,例如Gabow的最短路径算法Ford-Fulkerson最大流算法的缩放版本,在其复杂性方面具有对数项,因为它们一次只能处理一个数字。


As to your second question about how you solve that problem, you may want to look at this related question which explores a more advanced application. 至于你关于如何解决这个问题的第二个问题,你可能想看看这个探讨更高级应用程序的相关问题 Given the general structure of problems that are described here, you now can have a better sense of how to think about problems when you know there's a log term in the result, so I would advise against looking at the answer until you've given it some thought. 鉴于此处描述的问题的一般结构,当您知道结果中存在对数项时,您现在可以更好地了解如何思考问题,因此我建议您不要在给出答案之前查看答案。一些想法。

Hope this helps! 希望这可以帮助!

When we talk about big-Oh descriptions, we are usually talking about the time it takes to solve problems of a given size . 当我们谈论大哦描述时,我们通常谈论解决给定大小的问题所花费的时间 And usually, for simple problems, that size is just characterized by the number of input elements, and that's usually called n, or N. (Obviously that's not always true-- problems with graphs are often characterized in numbers of vertices, V, and number of edges, E; but for now, we'll talk about lists of objects, with N objects in the lists.) 通常,对于简单的问题,这个大小只是以输入元素的数量为特征,并且通常称为n或N.(显然,这并不总是正确的 - 图形的问题通常以顶点数量为特征,V和边数E;但是现在,我们将讨论对象列表,列表中有N个对象。)

We say that a problem "is big-Oh of (some function of N)" if and only if : 当且仅在以下情况下,我们说问题“是(N的某些功能)的大哦”

For all N > some arbitrary N_0, there is some constant c, such that the runtime of the algorithm is less than that constant c times (some function of N.) 对于所有N>某个任意N_0,存在一些常数c,使得算法的运行时间小于常数c次(N的某个函数)。

In other words, don't think about small problems where the "constant overhead" of setting up the problem matters, think about big problems. 换句话说,不要考虑设置问题的“持续开销”很重要的小问题,考虑大问题。 And when thinking about big problems, big-Oh of (some function of N) means that the run-time is still always less than some constant times that function. 在考虑大问题时,(O的某些函数)的大哦意味着运行时间仍然总是小于函数的某些常数。 Always. 总是。

In short, that function is an upper bound, up to a constant factor. 简而言之,该函数是一个上限,直到一个常数因子。

So, "big-Oh of log(n)" means the same thing that I said above, except "some function of N" is replaced with "log(n)." 因此,“log-n of log(n)”意味着与上述相同,除了“N的某些功能”被“log(n)”替换。

So, your problem tells you to think about binary search, so let's think about that. 所以,你的问题告诉你考虑二元搜索,所以让我们考虑一下。 Let's assume you have, say, a list of N elements that are sorted in increasing order. 假设您有一个按递增顺序排序的N个元素的列表。 You want to find out if some given number exists in that list. 您想知道该列表中是否存在某个给定的数字。 One way to do that which is not a binary search is to just scan each element of the list and see if it's your target number. 一种不是二分搜索的方法是只扫描列表中的每个元素,看看它是否是你的目标号码。 You might get lucky and find it on the first try. 你可能会很幸运,并在第一次尝试时找到它。 But in the worst case, you'll check N different times. 但在最坏的情况下,你会检查N次。 This is not binary search, and it is not big-Oh of log(N) because there's no way to force it into the criteria we sketched out above. 这不是二进制搜索,它不是log(N)的大哦,因为没有办法强制它进入我们在上面勾勒出的标准。

You can pick that arbitrary constant to be c=10, and if your list has N=32 elements, you're fine: 10*log(32) = 50, which is greater than the runtime of 32. But if N=64, 10*log(64) = 60, which is less than the runtime of 64. You can pick c=100, or 1000, or a gazillion, and you'll still be able to find some N that violates that requirement. 你可以选择那个任意常数为c = 10,如果你的列表中有N = 32个元素,你就可以了:10 * log(32)= 50,它大于32的运行时间。但是如果N = 64 ,10 * log(64)= 60,小于64的运行时间。你可以选择c = 100,或1000,或者gazillion,你仍然可以找到一些违反该要求的N. In other words, there is no N_0. 换句话说,没有N_0。

If we do a binary search, though, we pick the middle element, and make a comparison. 但是,如果我们进行二分搜索,我们选择中间元素,并进行比较。 Then we throw out half the numbers, and do it again, and again, and so on. 然后我们扔出一半的数字,然后再次,再次,等等。 If your N=32, you can only do that about 5 times, which is log(32). 如果您的N = 32,那么您只能执行约5次,即log(32)。 If your N=64, you can only do this about 6 times, etc. Now you can pick that arbitrary constant c, in such a way that the requirement is always met for large values of N. 如果你的N = 64,那么你只能做6次左右等等。现在你可以选择那个任意常数c,这样就可以满足大N值的要求。

With all that background, what O(log(N)) usually means is that you have some way to do a simple thing, which cuts your problem size in half. 在所有这些背景下,O(log(N))通常意味着你有一些方法可以做一个简单的事情,它可以将你的问题大小减少一半。 Just like the binary search is doing above. 就像上面的二元搜索一样。 Once you cut the problem in half, you can cut it in half again, and again, and again. 一旦你将问题减半,你可以再次将它切成两半,一次又一次。 But, critically, what you can't do is some preprocessing step that would take longer than that O(log(N)) time. 但是,关键的是,你不能做的是一些预处理步骤需要比O(log(N))时间更长的时间。 So for instance, you can't shuffle your two lists into one big list, unless you can find a way to do that in O(log(N)) time, too. 因此,例如,除非你能在O(log(N))时间找到一种方法,否则你不能将两个列表混合到一个大的列表中。

(NOTE: Nearly always, Log(N) means log-base-two, which is what I assume above.) (注意:几乎总是,Log(N)表示log-base-two,这就是我上面假设的。)

In the following solution, all the lines with a recursive call are done on half of the given sizes of the sub-arrays of X and Y. Other lines are done in a constant time. 在下面的解决方案中,所有具有递归调用的行都在X和Y的子阵列的给定大小的一半上完成。其他行在恒定时间内完成。 The recursive function is T(2n)=T(2n/2)+c=T(n)+c=O(lg(2n))=O(lgn). 递归函数是T(2n)= T(2n / 2)+ c = T(n)+ c = O(lg(2n))= O(lgn)。

You start with MEDIAN(X, 1, n, Y, 1, n). 您从MEDIAN(X,1,n,Y,1,n)开始。

MEDIAN(X, p, r, Y, i, k) 
if X[r]<Y[i]
    return X[r]
if Y[k]<X[p]
    return Y[k]
q=floor((p+r)/2)
j=floor((i+k)/2)
if r-p+1 is even
    if X[q+1]>Y[j] and Y[j+1]>X[q]
        if X[q]>Y[j]
            return X[q]
        else
            return Y[j]
    if X[q+1]<Y[j-1]
        return MEDIAN(X, q+1, r, Y, i, j)
    else
        return MEDIAN(X, p, q, Y, j+1, k)
else
    if X[q]>Y[j] and Y[j+1]>X[q-1]
        return Y[j]
    if Y[j]>X[q] and X[q+1]>Y[j-1]
        return X[q]
    if X[q+1]<Y[j-1]
        return MEDIAN(X, q, r, Y, i, j)
    else
        return MEDIAN(X, p, q, Y, j, k)

The Log term pops up very often in algorithm complexity analysis. Log算术在算法复杂度分析中经常出现。 Here are some explanations: 以下是一些解释:

1. How do you represent a number? 你怎么代表一个数字?

Lets take the number X = 245436. This notation of “245436” has implicit information in it. 让我们取数字X = 245436.这个“245436”符号中含有隐含的信息。 Making that information explicit: 使信息明确:

X = 2 * 10 ^ 5 + 4 * 10 ^ 4 + 5 * 10 ^ 3 + 4 * 10 ^ 2 + 3 * 10 ^ 1 + 6 * 10 ^ 0 X = 2 * 10 ^ 5 + 4 * 10 ^ 4 + 5 * 10 ^ 3 + 4 * 10 ^ 2 + 3 * 10 ^ 1 + 6 * 10 ^ 0

Which is the decimal expansion of the number. 这是数字的十进制扩展。 So, the minimum amount of information we need to represent this number is 6 digits. 因此,我们需要表示此数字的最小信息量6位数。 This is no coincidence, as any number less than 10^d can be represented in d digits. 这不是巧合,因为任何小于10 ^ d的数字都可以用d位数表示。

So how many digits are required to represent X? 那么代表X需要多少位? Thats equal to the largest exponent of 10 in X plus 1. 这相当于X加1的最大指数10。

==> 10 ^ d > X ==> 10 ^ d> X.
==> log (10 ^ d) > log(X) ==> log(10 ^ d)> log(X)
==> d* log(10) > log(X) ==> d * log(10)> log(X)
==> d > log(X) // And log appears again... ==> d> log(X)//再次出现日志......
==> d = floor(log(x)) + 1 ==> d = floor(log(x))+ 1

Also note that this is the most concise way to denote the number in this range. 另请注意,这是表示此范围内数字的最简洁方法。 Any reduction will lead to information loss, as a missing digit can be mapped to 10 other numbers. 任何减少都会导致信息丢失,因为丢失的数字可以映射到其他10个数字。 For example: 12* can be mapped to 120, 121, 122, …, 129. 例如:12 *可以映射到120,121,122,...,129。

2. How do you search for a number in (0, N - 1)? 2.如何在(0,N-1)中搜索数字?

Taking N = 10^d, we use our most important observation: 考虑N = 10 ^ d,我们使用最重要的观察:

The minimum amount of information to uniquely identify a value in a range between 0 to N - 1 = log(N) digits. 唯一标识0到N-1 = log(N)位数范围内的值的最小信息量。

This implies that, when asked to search for a number on the integer line, ranging from 0 to N - 1, we need at least log(N) tries to find it. 这意味着,当被要求在整数行上搜索一个从0到N-1的数字时,我们至少需要log(N)尝试才能找到它。 Why? 为什么? Any search algorithm will need to choose one digit after another in its search for the number. 任何搜索算法都需要在搜索数字时选择一个接一个的数字。

The minimum number of digits it needs to choose is log(N). 需要选择的最小位数是log(N)。 Hence the minimum number of operations taken to search for a number in a space of size N is log(N). 因此,在大小为N的空间中搜索数字所花费的最小操作数是log(N)。

Can you guess the order complexities of binary search, ternary search or deca search? 你能猜出二元搜索,三元搜索或十进制搜索的顺序复杂性吗?
Its O(log(N))! 它的O(log(N))!

3. How do you sort a set of numbers? 3.你如何对一组数字进行排序?

When asked to sort a set of numbers A into an array B, here's what it looks like -> 当被要求将一组数字A排序到数组B中时,这就是它的样子 - >

Permute Elements 置换元素

Every element in the original array has to be mapped to it's corresponding index in the sorted array. 原始数组中的每个元素都必须映射到排序数组中的相应索引。 So, for the first element, we have n positions. 所以,对于第一个元素,我们有n个位置。 To correctly find the corresponding index in this range from 0 to n - 1, we need…log(n) operations. 要在0到n - 1的范围内正确查找相应的索引,我们需要... log(n)操作。

The next element needs log(n-1) operations, the next log(n-2) and so on. 下一个元素需要log(n-1)操作,下一个log(n-2)等等。 The total comes to be: 总数来自:

==> log(n) + log(n - 1) + log(n - 2) + … + log(1) ==> log(n)+ log(n - 1)+ log(n - 2)+ ... + log(1)

Using log(a) + log(b) = log(a * b), 使用log(a)+ log(b)= log(a * b),

==> log(n!) ==> log(n!)

This can be approximated to nlog(n) - n. 这可以近似为nlog(n) - n。
Which is O(n*log(n))! 哪个是O(n * log(n))!

Hence we conclude that there can be no sorting algorithm that can do better than O(n*log(n)). 因此我们得出结论,没有排序算法能比O(n * log(n))做得更好。 And some algorithms having this complexity are the popular Merge Sort and Heap Sort! 并且具有这种复杂性的一些算法是流行的合并排序和堆排序!

These are some of the reasons why we see log(n) pop up so often in the complexity analysis of algorithms. 这些是我们在算法的复杂性分析中经常看到log(n)弹出的一些原因。 The same can be extended to binary numbers. 同样可以扩展到二进制数。 I made a video on that here. 我在这里制作了一个视频。
Why does log(n) appear so often during algorithm complexity analysis? 为什么log(n)在算法复杂度分析期间经常出现?

Cheers! 干杯!

当解决方案基于n上的迭代时,我们称时间复杂度为O(log n),其中每次迭代中完成的工作是前一次迭代的一小部分,因为算法适用于解决方案。

Can't comment yet... necro it is! 还不能发表评论......这是坏消息! Avi Cohen's answer is incorrect, try: Avi Cohen的回答不正确,请尝试:

X = 1 3 4 5 8
Y = 2 5 6 7 9

None of the conditions are true, so MEDIAN(X, p, q, Y, j, k) will cut both the fives. 没有一个条件是真的,所以MEDIAN(X,p,q,Y,j,k)将同时削减五个。 These are nondecreasing sequences, not all values are distinct. 这些是非递减序列,并非所有值都是不同的。

Also try this even-length example with distinct values: 也尝试使用不同值的这个偶数长度示例:

X = 1 3 4 7
Y = 2 5 6 8

Now MEDIAN(X, p, q, Y, j+1, k) will cut the four. 现在MEDIAN(X,p,q,Y,j + 1,k)将削减四个。

Instead I offer this algorithm, call it with MEDIAN(1,n,1,n): 相反,我提供此算法,使用MEDIAN(1,n,1,n)调用它:

MEDIAN(startx, endx, starty, endy){
  if (startx == endx)
    return min(X[startx], y[starty])
  odd = (startx + endx) % 2     //0 if even, 1 if odd
  m = (startx+endx - odd)/2
  n = (starty+endy - odd)/2
  x = X[m]
  y = Y[n]
  if x == y
    //then there are n-2{+1} total elements smaller than or equal to both x and y
    //so this value is the nth smallest
    //we have found the median.
    return x
  if (x < y)
    //if we remove some numbers smaller then the median,
    //and remove the same amount of numbers bigger than the median,
    //the median will not change
    //we know the elements before x are smaller than the median,
    //and the elements after y are bigger than the median,
    //so we discard these and continue the search:
    return MEDIAN(m, endx, starty, n + 1 - odd)
  else  (x > y)
    return MEDIAN(startx, m + 1 - odd, n, endy)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM