【问题标题】:Binary search of a sorted array有序数组的二分查找
【发布时间】:2011-12-25 10:36:27
【问题描述】:

我正在尝试使用此二进制搜索代码搜索降序排序的数组。但是,在我对其进行排序并尝试搜索之后,它没有返回任何结果,只是一个加载图标,永远不会消失,就好像它有一个无限循环一样。我不确定问题出在哪里,因为代码看起来很合乎逻辑。

这是带有 4.0 框架的 aspx,c#。提前致谢!

    protected void Button2_Click(object sender, EventArgs e)
    {
        String item = TextBox1.Text;
        int target = Convert.ToInt16(item);
        int mid, first = 0, last = mynumbers.Length - 1;

        //for a sorted array with descending values
        while (first<=last)
        {
            mid = (first + last) / 2;
            if (target < mynumbers[mid])
                first = mid + 1;
            if (target > mynumbers[mid])
                last = mid - 1;
            else
                Label11.Text = "Target " + item + " was found at index " + mynumbers[mid];

        }

【问题讨论】:

  • 我认为...应该是first &lt; last,而不是&lt;=
  • 我也试过了。然后发生的是同样的事情,或者它做了一些奇怪的事情,只给我最后一个数字的结果。
  • 其实
  • 这让我想起了我以前在圣路易斯的夜校上用 C++ 教授算法和数据结构时的各种回忆......

标签: c# arrays binary-search


【解决方案1】:

Array 类中有二分查找:

int index = Array.BinarySearch(mynumbers, target);

对于降序,这可以通过ReverseComparer 轻松完成,易于编写如下:

    public class ReverseComparer<T> : IComparer<T>
    {
        public int Compare(T x, T y)
        {
            return Comparer<T>.Default.Compare(y, x);
        }
    }

然后:

int index = Array.BinarySearch(numbers, 7, new ReverseComparer<int>());

如果这是一项学术练习,并且您必须使用自定义搜索,那么这当然不适用。如果它必须是一个类的自定义算法,那么问题是你必须在找到时跳出循环,并且索引在mid,而不是mynumbers[mid]

    //for a sorted array with descending values
    while (first<=last)
    {
        mid = (first + last) / 2;

        if (target < mynumbers[mid])
        {
            first = mid + 1;
        }

        if (target > mynumbers[mid])
        {
            last = mid - 1;
        }

        else
        {
            // the index is mid, not mynumbers[mid], and you need to break here
            // once found or it's an infinite loop once it finds it.
            Label11.Text = "Target " + item + " was found at index " + mid;
            break;
        }
    }

实际上,我可能会设置一个 bool 标志来保持算法的纯粹性,而不是将 find 与输出问题混为一谈,这也可以让您更容易地判断如果您退出循环但未找到时发生了什么:

    bool found = false;

    //for a sorted array with descending values
    while (!found && first<=last)
    {
        mid = (first + last) / 2;

        if (target < mynumbers[mid])
        {
            first = mid + 1;
        }

        if (target > mynumbers[mid])
        {
            last = mid - 1;
        }

        else
        {
            // You need to stop here once found or it's an infinite loop once it finds it.
            found = true;
        }
    }

    Label11.Text = found 
        ? "Item " + item + " was found at position " + mid
        : "Item " + item + " was not found";

【讨论】:

  • 感谢您的回复,是的,它必须是自定义搜索
  • OP 的数组是按降序排列的。我想这就是他们自己做的原因。 (另外,你不需要显式调用泛型重载:类型推断算法会自动选择最合适的方法——即最强类型重载。)
  • @LukeH:是的,我添加了下降扭曲。如果 OP 由于下降而需要自定义,他只需要一个 ReverseComparer&lt;T&gt; 无论如何这都是一个很好的工具箱项目。但是,如果这是一项学术练习,他确实需要自定义代码。
  • @Emmanuel:你需要定制是因为它是一项学术活动,还是因为降序排列?如果因为降序,ReverseComparer&lt;T&gt; - 这是一个很好的工具箱类 - 将解决它。
  • 我正在做一个类似的任务,我想知道在target &gt; mynumbers[mid] 比较之前是否有任何理由不使用“else”?我不确定这是更有效还是浪费检查。
【解决方案2】:

在黑暗中拍摄:

if (target < mynumbers[mid]) 
   first = mid + 1; 
else if (target > mynumbers[mid]) 
   last = mid - 1; 
else 
{
    ....
    break;
}

我怀疑你在 mid+1 和 mid-1 之间来回弹跳

【讨论】:

    【解决方案3】:

    这是正确的:

    如果target&lt; mynumbers[mid],那么你必须从最后到中1, 因为我们必须在较低的范围内搜索,即第一到中间1

    while (first<=last)
            {
                mid = (first + last) / 2;
                if (target == mynumbers[mid])
                Label11.Text = "Target " + item + " was found at index " + mynumbers[mid];
    
                else if (target < mynumbers[mid])
                    last = mid - 1;
                else (target > mynumbers[mid])
                    first = mid + 1;
    
                }
    

    【讨论】:

      【解决方案4】:
      //this works fine with these Test cases    
      // has to check if (target == mynumbers[mid])    
      // this is for an array with ascending order.
      class Program
      {
      
          static void Main(string[] args)
          {
              // TEST cases:
              // for 8: item 8 was not found
              // for 4: item 4 found at Position 3
              // for 1: item 1 found at position 0
              // for 0: item 0 was not found
      
      
              int target =8;
              int searchkey = target;
      
              int[] mynumbers = { 1, 2, 3, 4, 5 };
      
              int mid=0, first = 0, last = mynumbers.Length - 1;
      
              bool found = false;
      
              //for a sorted array with ascending values
              while (!found && first <= last)
              {
                  mid = (first + last) / 2;
      
                  if (target == mynumbers[mid])
                      found = true;
                  else
                  {
      
                      if (target > mynumbers[mid])
                      {
                          first = mid + 1;
                      }
      
                      if (target < mynumbers[mid])
                      {
                          last = mid - 1;
                      }
      
                  }
      
              }
      
              String foundmsg = found
                  ? "Item " + searchkey + " was found at position " + mid
                  : "Item " + searchkey + " was not found";
              Console.WriteLine(foundmsg);
           }
      }
      

      【讨论】:

        【解决方案5】:

        它对我有用

        public static int search(int[] arr, int value)
        {
            Debug.Assert(arr.Length>0);
            var left = 0;
            var right = arr.Length - 1;
        
            while (((right - left)/2) > 0)
            {
                var middle = left + (right - left)/2;
                if (arr[middle] < value)
                    left = middle + 1;
                else
                    right = middle;
            }
            return arr[left] >= value ? left : right;
        }
        

        【讨论】:

          【解决方案6】:
          public static object BinnarySearch(int[] array,int SearchKey)
              {
                  int min = 0;
                  int max = array.Length - 1;
                  while (min <= max)
                  {
                      int mid = (min + max) / 2;
                      if (SearchKey == array[mid])
                      {
                          return mid;
                      }
                      else if (SearchKey < array[mid])
                      {
                          max = mid - 1;
                      }
                      else
                          min = mid + 1;
                  }
                  return "Not Found";
              }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-12
            • 2010-09-19
            相关资源
            最近更新 更多