Arrays 具有未知项数的二进制搜索

Arrays 具有未知项数的二进制搜索,arrays,algorithm,binary-search,Arrays,Algorithm,Binary Search,假设您不知道正在搜索的元素的数量,并且给定了一个API,该API接受索引,如果超出了范围(在这里使用getWordFromDictionary方法实现),那么如何执行二进制搜索并为客户端程序实现IsWordIndicationary()方法 这个解决方案是可行的,但我最终在找到初始高索引值的级别上进行了一次串行搜索。通过较低范围的值进行搜索的灵感来自。我也在Reflector(C#decompiler)中查看了BinarySearch,但它有一个已知的列表长度,因此仍在寻找填补空白的方法 pri

假设您不知道正在搜索的元素的数量,并且给定了一个API,该API接受索引,如果超出了范围(在这里使用getWordFromDictionary方法实现),那么如何执行二进制搜索并为客户端程序实现IsWordIndicationary()方法

这个解决方案是可行的,但我最终在找到初始高索引值的级别上进行了一次串行搜索。通过较低范围的值进行搜索的灵感来自。我也在Reflector(C#decompiler)中查看了BinarySearch,但它有一个已知的列表长度,因此仍在寻找填补空白的方法

private static string[] dictionary;

static void Main(string[] args)
{
    dictionary = System.IO.File.ReadAllLines(@"C:\tmp\dictionary.txt");

    Console.WriteLine(isWordInDictionary("aardvark", 0));
    Console.WriteLine(isWordInDictionary("bee", 0));
    Console.WriteLine(isWordInDictionary("zebra", 0));
    Console.WriteLine(isWordInDictionaryBinary("aardvark"));
    Console.WriteLine(isWordInDictionaryBinary("bee"));
    Console.WriteLine(isWordInDictionaryBinary("zebra"));
    Console.ReadLine();
}

static bool isWordInDictionaryBinary(string word)
{
    // assume the size of the dictionary is unknown

    // quick check for empty dictionary
    string w = getWordFromDictionary(0);
    if (w == null)
        return false;

    // assume that the length is very big.
    int low = 0;
    int hi = int.MaxValue;

    while (low <= hi)
    {
        int mid = (low + ((hi - low) >> 1));
        w = getWordFromDictionary(mid);

        // If the middle element m you select at each step is outside 
        // the array bounds (you need a way to tell this), then limit
        // the search to those elements with indexes small than m.
        if (w == null)
        {
            hi = mid;
            continue;
        }

        int compare = String.Compare(w, word);
        if (compare == 0)
            return true;

        if (compare < 0)
            low = mid + 1;
        else
            hi = mid - 1;
    }

    // punting on the search above the current value of hi 
    // to the (still unknown) upper limit
    return isWordInDictionary(word, hi);
}


// serial search, works good for small number of items
static bool isWordInDictionary(string word, int startIndex) 
{
    // assume the size of the dictionary is unknown
    int i = startIndex;
    while (getWordFromDictionary(i) != null)
    {
        if (getWordFromDictionary(i).Equals(word, StringComparison.OrdinalIgnoreCase))
            return true;
        i++;
    }

    return false;
}

private static string getWordFromDictionary(int index)
{
    try
    {
        return dictionary[index];
    }
    catch (IndexOutOfRangeException)
    {
        return null;
    }
}
私有静态字符串[]字典;
静态void Main(字符串[]参数)
{
dictionary=System.IO.File.ReadAllLines(@“C:\tmp\dictionary.txt”);
Console.WriteLine(iswordindicationary(“aardvark”,0));
Console.WriteLine(iswordindicationary(“bee”,0));
Console.WriteLine(iswordindicationary(“zebra”,0));
控制台写入线(IsWordIndicationary(“aardvark”);
控制台。WriteLine(iswordindicationary(“bee”);
控制台。WriteLine(iswordindicationary(“斑马”);
Console.ReadLine();
}
静态bool iswordindicationBynary(字符串字)
{
//假设字典的大小未知
//快速检查空字典
字符串w=getWordFromDictionary(0);
如果(w==null)
返回false;
//假设长度非常大。
int低=0;
int hi=int.MaxValue;
而(低>1));
w=getWordFromDictionary(mid);
//如果在每个步骤中选择的中间元素m在外部
//数组边界(您需要一种方法来说明这一点),然后限制
//对索引小于m的元素的搜索。
如果(w==null)
{
高=中;
继续;
}
int compare=String.compare(w,word);
如果(比较==0)
返回true;
如果(比较<0)
低=中+1;
其他的
hi=mid-1;
}
//在hi当前值上方的搜索上下注
//达到(仍然未知)上限
返回iswordindicational(word,hi);
}
//串行搜索,适用于少量项目
静态bool iswordindicationary(字符串字,int startIndex)
{
//假设字典的大小未知
int i=起始索引;
while(getWordFromDictionary(i)!=null)
{
if(getWordFromDictionary(i).Equals(word,StringComparison.OrdinalIgnoreCase))
返回true;
i++;
}
返回false;
}
私有静态字符串getWordFromDictionary(int索引)
{
尝试
{
返回字典[索引];
}
捕获(IndexOutOfRangeException)
{
返回null;
}
}
回答后的最终代码

static bool isWordInDictionaryBinary(string word)
{
    // assume the size of the dictionary is unknown

    // quick check for empty dictionary
    string w = getWordFromDictionary(0);
    if (w == null)
        return false;

    // assume that the number of elements is very big
    int low = 0;
    int hi = int.MaxValue;

    while (low <= hi)
    {
        int mid = (low + ((hi - low) >> 1));
        w = getWordFromDictionary(mid);

        // treat null the same as finding a string that comes 
        // after the string you are looking for
        if (w == null)
        {
            hi = mid - 1;
            continue;
        }

        int compare = String.Compare(w, word);
        if (compare == 0)
            return true;

        if (compare < 0)
            low = mid + 1;
        else
            hi = mid - 1;
    }

    return false;
}
static bool iswordindicationary二进制(字符串字)
{
//假设字典的大小未知
//快速检查空字典
字符串w=getWordFromDictionary(0);
如果(w==null)
返回false;
//假设元素的数量非常大
int低=0;
int hi=int.MaxValue;
而(低>1));
w=getWordFromDictionary(mid);
//将null视为查找出现的字符串
//在你要找的绳子后面
如果(w==null)
{
hi=mid-1;
继续;
}
int compare=String.compare(w,word);
如果(比较==0)
返回true;
如果(比较<0)
低=中+1;
其他的
hi=mid-1;
}
返回false;
}

因此,我不确定从您的描述中是否完全理解了这个问题,但我假设您正在尝试搜索长度未知的排序的数组以查找特定字符串。我还假设实际数组中没有空值;仅当请求超出范围的索引时,数组才会返回null

如果这些都是真的,那么解决方案应该只是一个标准的二进制搜索,尽管是在整个整数空间中搜索,并且将null视为查找所查找字符串后面的字符串。本质上,只要想象一下,N个字符串的排序数组实际上是一个INT_MAX字符串的排序数组,最后是null


我不太明白的是,您似乎已经基本上做到了这一点(至少粗略地看一下代码),因此我认为我可能无法完全理解您的问题。

因此,我不确定我是否完全理解您描述的问题,但我假设您正在尝试搜索长度未知的排序的数组以查找特定字符串。我还假设实际数组中没有空值;仅当请求超出范围的索引时,数组才会返回null

如果这些都是真的,那么解决方案应该只是一个标准的二进制搜索,尽管是在整个整数空间中搜索,并且将null视为查找所查找字符串后面的字符串。本质上,只要想象一下,N个字符串的排序数组实际上是一个INT_MAX字符串的排序数组,最后是null


我不太明白的是,您似乎已经基本上做到了这一点(至少粗略地看一下代码),因此我想我可能无法完全理解您的问题。

当然可以。从索引1开始,将查询索引加倍,直到找到比查询词(Edit:或null)更大的单词。然后可以再次缩小搜索空间,直到找到索引,或者返回false


编辑:请注意,这不会添加到渐进运行时,它仍然是O(logN),其中N是序列中的项数。

当然可以。从索引1开始,将查询索引加倍,直到找到
bool isPresentPhase1(string word)
{
  int l = 0, d = 1;
  while( true ) // you should eventually reach an index out of bounds
  {
    w = getWord(l + d);
    if( w == null )
      return isPresentPhase2(word, l, l + d - 1);
    int c = String.Compare(w, word);
    if( c == 0 )
      return true;
    else if( c < 0 )
      isPresentPhase2(value, l, l + d - 1);
    else
    {
      l = d + 1;
      d *= 2;
    } 
  }
}

bool isPresentPhase2(string word, int lo, int hi)
{
    // normal binary search in the interval [lo, hi]
}