【问题标题】:How to return positive occurrence如何返回积极事件
【发布时间】:2015-06-12 03:42:00
【问题描述】:

我有一个函数,当给定一个由 N 个整数组成的零索引数组 A,按非降序排序,以及某个整数 X 时,在 A 中查找 X。如果 X 存在于 A 中,则它返回一个正索引在 A 中出现 X。否则,函数返回 -1。

它应该像这样工作:

  • 如果我有 A[0]=1、A[1]=1 和 X=1,它应该返回 0,因为 A[0]=1。

但它没有返回我想要的。有人能帮我吗? 这是我的代码:

int Number(int *A, int N, int X) {
    int r, m, l;
    if (N == 0) {
        return -1;
    }
    l = 0;
    r = N - 1;
    while (l < r) {
        m = (l + r) / 2;
        if (A[m] > X)  {
            r = m - 1;
        } else {
            l = m;
        }
    }
    if (A[l] == X) {
        return l;
    }
    return -1;
}

【问题讨论】:

  • 什么是错误或错误输出

标签: c algorithm binary-search


【解决方案1】:

我尝试了一个稍微不同的策略。它似乎有效。

#include <stdio.h>

int Number(int *A, int N, int X) {
    int r, m, l;
    if (N == 0) {
        return -1;
    }
    l = 0;
    r = N; // Not N-1
    while (l < r) {
       m = (l + r) / 2;

       // Debugging output. Track how l, m, and r change.
       printf("l: %d, m: %d, r: %d\n", l, m, r);

       // A slightly different strategy for narrowing
       // the interval.
       if (A[m] < X)  {
          l = m+1;
       } else {
          r = m;
       }
    }
    if (A[l] == X) {
        return l;
    }
    return -1;
}

void test1()
{
   int A[] = {1, 1};
   printf("%d\n", Number(A, 2, 1));
}

void test2()
{
   int A[] = {0, 1, 1};
   printf("%d\n", Number(A, 3, 1));
}

void test3()
{
   int A[] = {0, 0, 1, 1, 2, 2};
   printf("%d\n", Number(A, 6, 1));
   printf("%d\n", Number(A, 5, 1));
   printf("%d\n", Number(A, 4, 1));
}

int main()
{
   test1();
   test2();
   test3();
   return 0;
}

输出:

l: 0, m: 1, r: 2
l: 0, m: 0, r: 1
0
l: 0, m: 1, r: 3
l: 0, m: 0, r: 1
1
l: 0, m: 3, r: 6
l: 0, m: 1, r: 3
l: 2, m: 2, r: 3
2
l: 0, m: 2, r: 5
l: 0, m: 1, r: 2
2
l: 0, m: 2, r: 4
l: 0, m: 1, r: 2
2

【讨论】:

    【解决方案2】:

    二分搜索保证找到的位置是该数字在数组中的第一次出现。

    如果我有 A[0]=1、A[1]=1 和 X=1,它应该返回 0,因为 A[0]=1

    这意味着在这种情况下,答案“1”是正确的,因为 A[1] = 1 也是如此。

    您需要手动遍历数组以找到第一个不匹配值(或数组开头)。优化是可能的,但只有当您有一个具有大量重复值的非常大的数组时才需要优化。

    您也可以尝试默认的二进制搜索方法:

    int Number(int *A, int N, int X) {
        int r, m, l;
        if (N == 0) {
            return -1;
        }
        l = 0;
        r = N - 1;
        while (l < r) {
            m = (l + r) / 2;
            if (A[m] == X)
               return m;
            if (A[m] > X)  {
                r = m - 1;
            } else {
                l = m + 1;
            }
        }
        return -1;
    }
    

    【讨论】:

    • 说到“非常大的数组”,更喜欢m = l + (r - l)/2;以避免潜在的溢出
    • @WhozCraig 如果关注大型数组,代码是否应该使用size_t N 等?
    【解决方案3】:

    这是来自 Jon Bentley 的书 Programming Pearls, 2nd Edition 的修改后的二进制搜索:

    /*
    ** Modified binary search.
    ** Find lowest occurrence of value in array (if there is more than one)
    */
    
    #include <assert.h>
    #include <stdio.h>
    
    /*
    ** From J Bentley "Programming Pearls, 2nd Edition", Section 9.3
    ** Locate the first occurrence of t in x[0..n-1].
    ** Assume n >= 0, and the hypothetical elements x[-1] < t and x[n] > t
    ** without accessing either fictitious element.
    */
    static
    int bsearchf(const int *x, int n, int t)
    {
        int l = -1;
        int u = n;
    
        assert(n >= 0);
        while (l + 1 != u)
        {
            /* Invariant: x[l] < t && x[u] >= t && l < u */
            int m = (l + u) / 2;
            //printf("  t = %d, l = %d, u = %d, m = %d, x[%d] = %d\n",
            //       t, l, u, m, m, x[m]);
            if (x[m] < t)
                l = m;
            else
                u = m;
        }
        if (u >= n || x[u] != t)
            return -1;
        assert(u >= 0 && u < n);
        return u;
    }
    
    int main(void)
    {
        const int data[] =
        {
            0, 0, 0, 2, 2, 2,
         /* 2, 2, 2, 2, 2, 2, */
            4, 6, 6, 6, 8, 8,
        };
        enum { DATA_SIZE = sizeof(data) / sizeof(data[0]) };
    
        /* Check monotonic non-decreasing data */
        for (int j = 0; j < DATA_SIZE - 1; j++)
            assert(data[j] <= data[j+1]);
    
        /* Every starting point in the data array */
        for (int j = 0; j < DATA_SIZE; j++)
        {
            const int *base = &data[j];
            /* Every valid data length for the remainder of the data array */
            for (int k = DATA_SIZE - j; k > 0; k--)
            {
                int lo = base[0] - 1;
                int hi = base[k-1] + 2;
    
                printf("N = %d", k);
                for (int m = 0; m < k; m++)
                    printf(" A[%d]: %d", m, base[m]);
                putchar('\n');
    
                /* For every value from 1 less than the minimum to one more than the maximum */
                for (int i = lo; i < hi; i++)
                {
                    int r = bsearchf(base, k, i);
                    printf("V = %2d, : R = %2d, C = %2d : %s\n",
                            i, r, (r < 0) ? -1 : base[r],
                            (r < 0) ? "missing" : "found");
                    if (r == -1)
                    {
                        for (int n = 0; n < k; n++)
                            assert(base[n] != i);
                    }
                    assert(r == -1 || (base[r] == i && (r == 0 || base[r-1] < i)));
                }
            }
        }
    
        return 0;
    }
    

    主程序是一个测试器,它检查数组data 的每个子序列,并尝试在该数组中找到min - 1max + 1 之间的每个数字,当然其中很多都找不到,因为只有偶数数组中的值。它的输出很冗长,但有一些断言可以证明其结果:如果结果有问题,则应该触发断言。

    【讨论】:

      【解决方案4】:

      你可以通过搜索来做到!

      试试这个!

      public class MyClass {
         public static void main(String[] args) {
              int a[] = {1,2,3,4,5,6,9,12,55,123};
              int x = solution(a,1);
              System.out.println(x);
          }
          
      public static int solution(int[] A, int X) {
                      int N = A.length;
                      int r, m, l;
                      if (N == 0) {
                          return -1;
                      }
                      l = 0;
                      r = N;
                      while (l < r) {
                          m = (l +r)/2;
                           if (A[l] == X)
                          return l;
                          if (A[m] > X)  {
                              r = m - 1;
                          } else {
                              l = m ;
                          }
                      }
                      return -1;
              }
      }
      

      【讨论】:

      • 这段代码在我看来不像 C(甚至 C++)。猜测一下,我会说它是 C#——但问题中唯一的语言标签是 C。
      • @AdrianMole 是的,你说得对,我没有注意到。这是 JAVA。
      猜你喜欢
      • 2022-01-10
      • 2020-06-11
      • 2021-01-25
      • 1970-01-01
      • 1970-01-01
      • 2021-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多