C++ 使用二进制搜索查找丢失的数字
我正在读一本关于编程珍珠的书 问:给定一个最多包含40亿的顺序文件 32位整数按随机顺序,查找不在中的32位整数 文件(必须至少缺少一个)。这个问题必须解决 如果我们有几百字节的主内存和几个 顺序文件 解决方案:要将其设置为二进制搜索,我们必须定义一个范围, 范围内元素的表示和探测 方法来确定范围的哪一半包含缺少的整数。 我们如何做到这一点 我们将使用已知至少包含一个整数的序列作为范围 缺少一个元素,我们将用一个文件表示范围 包含其中的所有整数。我们的见解是,我们可以探索 通过计算其中点上方和下方的元素来确定范围:或 上限或下限的元素总数为atmost的一半 范围因为总范围缺少一个元素,所以较小的一半 还必须有错误的元素。这些都是最重要的成分 上述问题的二进制搜索算法 上面的文字是Jon Bently从编程珍珠书中的副本 以下链接提供了一些信息C++ 使用二进制搜索查找丢失的数字,c++,algorithm,binary-search,C++,Algorithm,Binary Search,我正在读一本关于编程珍珠的书 问:给定一个最多包含40亿的顺序文件 32位整数按随机顺序,查找不在中的32位整数 文件(必须至少缺少一个)。这个问题必须解决 如果我们有几百字节的主内存和几个 顺序文件 解决方案:要将其设置为二进制搜索,我们必须定义一个范围, 范围内元素的表示和探测 方法来确定范围的哪一半包含缺少的整数。 我们如何做到这一点 我们将使用已知至少包含一个整数的序列作为范围 缺少一个元素,我们将用一个文件表示范围 包含其中的所有整数。我们的见解是,我们可以探索 通过计算其中点上方和下
我们如何使用二进制搜索进行旁路搜索,而不遵循上面链接中给出的示例?请帮助我理解只有5个整数的逻辑,而不是百万个整数来理解逻辑。这个想法是为了解决更简单的问题: 是范围[minVal,X]或(X,maxVal)中缺少的值。 如果您知道这一点,您可以移动X并再次检查 例如,您有3、4、1、5(缺少2)。 你知道minVal=1,maxVal=5
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; } } } }