【问题标题】:Performing binary-search for points intervals对点间隔执行二进制搜索
【发布时间】:2013-12-12 02:46:00
【问题描述】:

我将尽可能清楚地解释我的问题。 Point[] right 是一个有序的点数组,每个Point 对象是一对Long x, y

现在,这是我的目标。给定一个Point p 和它的p.y 坐标,我必须找到几个点Point p1, p2,其中(根据y 坐标)p 包括在内,显然是使用二分搜索。这是我的迭代实现。

        /* Binary search for leftmost edge intersected by p */
        Point p1, p2;
        long px = p.x, py = p.y;
        long div = 2;
        long index = (left.length-1)/div;
        while(true) {
//          System.out.println("Left search-index:"+index+" Div: "+div);
            if(left[(int) index].y.compareTo(p.y) >= 0){
                if(left[(int) (index+1)].y.compareTo(p.y) <= 0){    
                    p1 = left[(int) index];
                    p2 = left[(int) (index + 1)];
//                  System.out.println("p1 "+p1.x+" "+p1.y+"; p2 "+p2.x+" "+p2.y);
                    break;
                }
                else {
                    if(index/div == 0)
                        index = index + 1;
                    else
                        index = index + index/div;
                }
            }
            else {
                if(index/div == 0)
                    index = index - 1;
                else index = index - index/div;
            }
            div = 2*div;
        }

现在,问题:

  1. 这实际上是二分搜索吗?
  2. div 会溢出吗?我知道在运行时它会引发异常,但我不知道是什么以及由谁。 (这个问题发生在 SPOJ 提交上,我拥有的唯一信息是 NZEC Runtime Error)。
  3. 有什么方法可以提高性能?我期待一个包含 5000-10000 点的数组。

我尝试了一个超过 75 个条目的数组,并且有执行的痕迹。 (请注意,此搜索是在 leftright 两个不同的数组上执行的,每个数组大约包含 75/2 个元素)

Left search-index:20 Div: 2
Left search-index:10 Div: 4
Left search-index:12 Div: 8
Left search-index:13 Div: 16
Left search-index:14 Div: 32
Left search-index:15 Div: 64
Left search-index:16 Div: 128
Left search-index:17 Div: 256
Left search-index:18 Div: 512
Right search-index:17 Div: 2
Right search-index:9 Div: 4
Right search-index:11 Div: 8
Right search-index:12 Div: 16
Right search-index:13 Div: 32
Right search-index:14 Div: 64
Right search-index:15 Div: 128
Right search-index:16 Div: 256
true
Left search-index:20 Div: 2
Left search-index:10 Div: 4
Left search-index:12 Div: 8
Left search-index:13 Div: 16
Left search-index:14 Div: 32
Left search-index:15 Div: 64
Left search-index:16 Div: 128
Left search-index:17 Div: 256
false
Left search-index:20 Div: 2
Left search-index:30 Div: 4
Left search-index:23 Div: 8
Left search-index:25 Div: 16
Right search-index:17 Div: 2
Right search-index:9 Div: 4
Right search-index:11 Div: 8
Right search-index:12 Div: 16
false

【问题讨论】:

    标签: java search binary overflow


    【解决方案1】:

    这个实现有一个二分搜索的想法。二分搜索维护两个边界:左和右,你只有一个。所以这可能会导致一些无限循环,当它退回到一行时:

    else index = index - index/div;
    

    即index 是 100,你已经检查了 90,所以答案在 90 到 100 之间,但它会回落到 50 并且可以无限循环,就像它已经在这个区域一样。

    编程中的许多错误并不那么容易找到:Nearly All Binary Searches and Mergesorts are Broken

    所以你可以使用标准方法(注意pos 可以是负数):

    int pos = Arrays.binarySearch(p);
    

    它会给你一个需要的位置,答案是(A[pos - 1], A[pos])(A[pos], A[pos + 1])

    线性搜索也可以在这里工作,因为只有 10.000 个元素。

    JavaDoc:

    > Returns: 
    > index of the search key, if it is contained in the array;
    > otherwise, (-(insertion point) - 1). The insertion point is defined as
    > the point at which the key would be inserted into the array: the index
    > of the first element greater than the key, or a.length if all elements
    > in the array are less than the specified key. Note that this
    > guarantees that the return value will be >= 0 if and only if the key
    > is found.
    

    【讨论】:

    • 能否链接相关的binarySearch(p)方法javadoc?
    • 谢谢老兄。在下面检查我自己的答案。
    【解决方案2】:

    index/div==0 为真的唯一方法是当索引为 0 时,index=index-1 将导致 -1 值,这是一个非法索引或索引小于 div 大时间。
    Java 中一个重要的事情是数组的索引和长度是 int 而不是 long

    【讨论】:

      【解决方案3】:

      我用严格的二分搜索写了一个新版本。你怎么看?它不断返回正确的值,但在 SPOJ 上不起作用。

          low = 0; high = right.length - 1;
          mid = 0;
      
          while(low <= high) {
              mid = (low + high) >>> 1;
              System.out.println("MID: "+mid);
              c1 = right[mid].y;
              c2 = right[mid+1].y;
      
              if(py >= c1 && py <= c2) {
                  p3 = right[mid];
                  p4 = right[mid +1];
                  break;
              }
      
              else if(py < c1)
                  high = mid - 1;
      
              else
                  low = mid + 1;
          }
      

      【讨论】:

        猜你喜欢
        • 2010-11-01
        • 2012-04-18
        • 2015-03-30
        • 2012-06-27
        • 1970-01-01
        • 1970-01-01
        • 2017-02-10
        • 2011-11-14
        • 1970-01-01
        相关资源
        最近更新 更多