Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用二进制搜索查找丢失的数字_C++_Algorithm_Binary Search - Fatal编程技术网

C++ 使用二进制搜索查找丢失的数字

C++ 使用二进制搜索查找丢失的数字,c++,algorithm,binary-search,C++,Algorithm,Binary Search,我正在读一本关于编程珍珠的书 问:给定一个最多包含40亿的顺序文件 32位整数按随机顺序,查找不在中的32位整数 文件(必须至少缺少一个)。这个问题必须解决 如果我们有几百字节的主内存和几个 顺序文件 解决方案:要将其设置为二进制搜索,我们必须定义一个范围, 范围内元素的表示和探测 方法来确定范围的哪一半包含缺少的整数。 我们如何做到这一点 我们将使用已知至少包含一个整数的序列作为范围 缺少一个元素,我们将用一个文件表示范围 包含其中的所有整数。我们的见解是,我们可以探索 通过计算其中点上方和下

我正在读一本关于编程珍珠的书

问:给定一个最多包含40亿的顺序文件 32位整数按随机顺序,查找不在中的32位整数 文件(必须至少缺少一个)。这个问题必须解决 如果我们有几百字节的主内存和几个 顺序文件

解决方案:要将其设置为二进制搜索,我们必须定义一个范围, 范围内元素的表示和探测 方法来确定范围的哪一半包含缺少的整数。 我们如何做到这一点

我们将使用已知至少包含一个整数的序列作为范围 缺少一个元素,我们将用一个文件表示范围 包含其中的所有整数。我们的见解是,我们可以探索 通过计算其中点上方和下方的元素来确定范围:或 上限或下限的元素总数为atmost的一半 范围因为总范围缺少一个元素,所以较小的一半 还必须有错误的元素。这些都是最重要的成分 上述问题的二进制搜索算法

上面的文字是Jon Bently从编程珍珠书中的副本

以下链接提供了一些信息


我们如何使用二进制搜索进行旁路搜索,而不遵循上面链接中给出的示例?请帮助我理解只有5个整数的逻辑,而不是百万个整数来理解逻辑。

这个想法是为了解决更简单的问题:

是范围[minVal,X]或(X,maxVal)中缺少的值。 如果您知道这一点,您可以移动X并再次检查

例如,您有3、4、1、5(缺少2)。 你知道minVal=1,maxVal=5

  • 范围=[1,5],X=3,范围[1,3]中应有3个整数,范围[4,5]中应有2个整数。范围[1,3]中只有2个,因此您正在范围[1,3]中查找
  • 范围=[1,3],X=2。范围[1,2]中只有1个值,因此您正在范围[1,2]中查找
  • 范围=[1,2],X=1。范围[2,2]中没有值,因此这是您的答案
  • 编辑:一些伪C++代码:

    minVal = 1, maxVal = 5; //choose correct values
    while(minVal < maxVal){
        int X = (minVal + maxVal) / 2
        int leftNumber = how much in range [minVal, X]
        int rightNumber = how much in range [X + 1, maxVal]
        if(leftNumber < (X - minVal + 1))maxVal = X
        else minVal = X + 1
    }
    
    minVal=1,maxVal=5//选择正确的值
    while(minVal
    为什么不重新阅读帖子中的答案呢。它根据您的要求解释了5个整数的处理过程。
    其思想是解析每个列表,并根据第一位中的值将其分成2个(二进制部分就是从这里来的)单独的列表

    即显示实际数字的二进制表示 原始列表“”:001、010、110、000、100、011、101=>(分为几个部分)
    (我们删除第一位并将其附加到新列表的“名称”中)
    为了形成下面的每个列表,我们从上面的列表中选取以[0或1]开头的值
    列表“0”:01、10、00、11(通过删除第一位并将其附加到新列表的“名称”中,从列表“”的子集001、010、000、011中形成)
    列表“1”:10,00,01(通过删除第一位并将其附加到新列表的“名称”中,从列表“”的子集110,100,101形成)

    现在依次选择一个结果列表并重复此过程:
    列表“0”成为您的原始列表,您可以将其拆分为
    列出“0***0**”和
    列表“0***1**”(粗体数字再次是列表中被打断的数字的1[剩余]位)

    继续,直到你得到一张空名单为止

    编辑
    逐步处理:
    列表“”:001、010、110、000、100、011、101=>
    列表“0”:01、10、00、11(来自列表“”的子集001、010、000、011)=>
    列表“00”:1,0(来自列表“0”的子集01,00”)=>
    列表“000”:0[最终结果](来自列表“00”的子集0”)
    列表“001”:1[最终结果](来自列表“00”的子集1”)
    列表“01”:0,1(来自列表“0”的子集10,11”)=>
    列表“010”:0[最终结果](来自列表“01”的子集0”)
    列表“011”:1[最终结果](来自列表“01”的子集1”)
    列表“1”:10,00,01(来自列表“”的子集110,100,101)=>
    列表“10”:0,1(来自列表“1”的子集00,01)=>
    列表“100”:0[最终结果](来自列表“10”的子集0”)
    列表“101”:1[最终结果](来自列表“10”的子集1)
    列表“11”:0(来自列表“1”的子集10)=>
    列表“110”:0[最终结果](来自列表“11”的子集0”)
    列表“111”:不存在[最终结果](来自列表“11”的子集

    此方法的优点是,它允许您查找集合中缺失的任何数字,即,如果有多个缺失


    p.S.AFAIR对于完整范围之外的单个缺失数,有更优雅的XOR all数解决方案。

    这里有一个简单的C解决方案,可以说明该技术。为了消除任何繁琐的文件I/O细节,我假设存在以下三个函数:

    • unsigned long next\u number(void)
      从文件中读取一个数字并返回它。再次调用时,将返回文件中的下一个数字,依此类推。遇到文件结尾时的行为未定义

    • int numbers\u left(void)
      如果使用
      next\u number()
      可以读取更多的数字,则返回真值;如果已到达文件末尾,则返回假值

    • void return\u to\u start(void)
      将读取位置倒带到文件的开头,以便下次调用
      next\u number()
      返回文件中的第一个数字
      sum = (a + b) * (b - a + 1) / 2
      
      long sum1 = 0;
      for (int i = 0; i < b - a; i++)
      sum1 += arr[i];
      
      uint32_t binaryHistogram[32], *list4BILLION, answer, placesChecked[32];
      uint64_t limit = 4294967296;
      uint32_t halfLimit = 4294967296/2;
      int i, j, done
      
      //General method to point to list since this detail is not important to the question.
      list4BILLION = 0000000000h;
      
      
      //Initialize array to zero. This array represents the number of 1s seen as you parse through the list
      for(i=0;i<limit;i++)
      {   
          binaryHistogram[i] = 0;
      }
      
      //Only sum up for first half of the 4 billion numbers
      for(i=0;i<halfLimit;i++)
      {
          for(j=0;j<32;j++)
          {
              binaryHistogram[j] += ((*list4BILLION) >> j);
          }
      }
      
      //Check each ith digit to see if all halfLimit values have been parsed
      for(i=halfLimit;i<limit;i++)
      {
          for(j=0;j<32;j++)
          {
              done = 1;   //Dont need to continue to the end if placesChecked are all 
              if(placesChecked[j] != 0) //Dont need to pass through the whole list
              {
                  done = 0; //
                  binaryHistogram[j] += ((*list4BILLION) >> j);
                  if((binaryHistogram[j] > halfLimit)||(i - binaryHistogram[j] == halfLimit))
                  {
                      answer += (1 << j);
                      placesChecked[j] = 1;
                  }
              }
          }
      }