Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.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
Ruby 如何使用二进制搜索查找数组中的插入点?_Ruby_Algorithm_Binary Search - Fatal编程技术网

Ruby 如何使用二进制搜索查找数组中的插入点?

Ruby 如何使用二进制搜索查找数组中的插入点?,ruby,algorithm,binary-search,Ruby,Algorithm,Binary Search,在数组中进行二进制搜索的基本思想很简单,但如果搜索无法找到确切的项,它可能会返回“近似”索引。(我们有时可能会返回一个索引,其值大于或小于搜索值) 为了寻找准确的插入点,似乎在获得大致位置后,我们可能需要向左或向右“扫描”以获得准确的插入位置,这样,比如说,在Ruby中,我们可以执行arr.insert(精确的索引,值) 我有下面的解决方案,但是当begin\u index>=end\u index时对零件的处理有点混乱。我想知道是否可以使用更优雅的解决方案 (如果找到精确匹配,此解决方案不关心

在数组中进行二进制搜索的基本思想很简单,但如果搜索无法找到确切的项,它可能会返回“近似”索引。(我们有时可能会返回一个索引,其值大于或小于搜索值)

为了寻找准确的插入点,似乎在获得大致位置后,我们可能需要向左或向右“扫描”以获得准确的插入位置,这样,比如说,在Ruby中,我们可以执行
arr.insert(精确的索引,值)

我有下面的解决方案,但是当
begin\u index>=end\u index
时对零件的处理有点混乱。我想知道是否可以使用更优雅的解决方案

(如果找到精确匹配,此解决方案不关心扫描多个匹配,因此为精确匹配返回的索引可能指向与值对应的任何索引…但我认为如果它们都是整数,我们可以在知道找到精确匹配后搜索
a-1
,以查找左边界,或搜索
右边界为+1

我的解决方案:

DEBUGGING = true

def binary_search_helper(arr, a, begin_index, end_index)
  middle_index = (begin_index + end_index) / 2
  puts "a = #{a}, arr[middle_index] = #{arr[middle_index]}, " +
           "begin_index = #{begin_index}, end_index = #{end_index}, " +
           "middle_index = #{middle_index}" if DEBUGGING
  if arr[middle_index] == a
    return middle_index
  elsif begin_index >= end_index
    index = [begin_index, end_index].min
    return index if a < arr[index] && index >= 0  #careful because -1 means end of array
    index = [begin_index, end_index].max
    return index if a < arr[index] && index >= 0
    return index + 1
  elsif a > arr[middle_index]
    return binary_search_helper(arr, a, middle_index + 1, end_index)
  else
    return binary_search_helper(arr, a, begin_index, middle_index - 1)
  end
end

# for [1,3,5,7,9], searching for 6 will return index for 7 for insertion
# if exact match is found, then return that index
def binary_search(arr, a)
  puts "\nSearching for #{a} in #{arr}" if DEBUGGING
  return 0 if arr.empty?
  result = binary_search_helper(arr, a, 0, arr.length - 1)
  puts "the result is #{result}, the index for value #{arr[result].inspect}" if DEBUGGING
  return result
end


arr = [1,3,5,7,9]
b = 6
arr.insert(binary_search(arr, b), b)
p arr

arr = [1,3,5,7,9,11]
b = 6
arr.insert(binary_search(arr, b), b)
p arr

arr = [1,3,5,7,9]
b = 60
arr.insert(binary_search(arr, b), b)
p arr

arr = [1,3,5,7,9,11]
b = 60
arr.insert(binary_search(arr, b), b)
p arr

arr = [1,3,5,7,9]
b = -60
arr.insert(binary_search(arr, b), b)
p arr

arr = [1,3,5,7,9,11]
b = -60
arr.insert(binary_search(arr, b), b)
p arr

arr = [1]
b = -60
arr.insert(binary_search(arr, b), b)
p arr

arr = [1]
b = 60
arr.insert(binary_search(arr, b), b)
p arr

arr = []
b = 60
arr.insert(binary_search(arr, b), b)
p arr

这是Oracles Java中包含的Java的Java.util.Arrays.binarySearch中的代码:

/**
*使用
*二进制搜索算法。数组必须按
*在进行此调用之前通过{@link#sort(int[])}方法进行
*未排序,则结果未定义。如果数组包含
*具有指定值的多个元素,不保证
*我们会找到一个。
*
*@param a要搜索的数组
*@param key要搜索的值
*@如果搜索键包含在数组中,则返回该搜索键的索引;
*否则,((插入点)-1)
*插入点定义为插入的点
*键将被插入数组中:第一个
*元素大于键,或a.length(如果全部)
*数组中的元素小于指定的键。注意
*这保证了如果
*只有找到钥匙。
*/
公共静态int二进制搜索(int[]a,int键){
返回二进制搜索0(a,0,a.length,key);
}
//与公共版本类似,但没有范围检查。
私有静态int-binarySearch0(int[]a,int-fromIndex,int-toIndex,
int键){
int low=fromIndex;
int high=toIndex-1;
而(低>>1;
int midVal=a[mid];
中频(中频<键)
低=中+1;
else if(midVal>键)
高=中-1;
其他的
return mid;//找到密钥
}
return-(低+1);//找不到键。
}
该算法已被证明是合适的,我喜欢这样的事实,即您可以立即从结果中知道它是精确匹配还是插入点上的提示

以下是我将其转换为ruby的方式:

#使用二进制文件将指定值插入指定数组
#搜索算法。在进行此调用之前,必须对数组进行排序。
#如果未排序,则结果未定义
#具有指定值的多个元素,不保证
#哪一个会被找到。
#
#@param[Array]数组应插入值的有序数组
#@param[Object]value要插入的值
#_索引有序子数组中的@param[Fixnum | Bignum]开始于
#@param[Fixnum | Bignum]to_index ordered子数组在
#@return[Array]生成的数组
def self.insert(数组,值,from_index=0,to_index=array.length)
array.insert插入点(数组、值、从索引到索引)、值
结束
#在指定数组中搜索指定值的插入点
#使用二进制搜索算法。数组在生成之前必须进行排序
#此调用。如果未排序,则结果未定义。如果
#包含多个具有指定值的元素,不保证
#哪一个会被找到。
#
#@param[Array]数组应插入值的有序数组
#@param[Object]value要插入的值
#_索引有序子数组中的@param[Fixnum | Bignum]开始于
#@param[Fixnum | Bignum]to_index ordered子数组在
#@return[Fixnum | Bignum]应该插入值的位置
def self.insertion_point(数组,值,from_index=0,to_index=array.length)
如果从_index<0 | |从_index>array.length | |从_index>到| index | |到_index>array.length,则引发(ArgumentError,“无效范围”)
二进制搜索=\u二进制搜索(数组、值、从\u索引到\u索引)
如果二进制搜索<0
-(二进制搜索+1)
其他的
二进制搜索
结束
结束
#使用二进制文件在指定数组中搜索指定值
#搜索算法。在进行此调用之前,必须对数组进行排序。
#如果未排序,则结果未定义
#具有指定值的多个元素,不保证
#我们会找到一个。
#
#@param[Array]数组应在其中搜索值的有序数组
#@param[Object]value要搜索的值
#_索引有序子数组中的@param[Fixnum | Bignum]开始于
#@param[Fixnum | Bignum]to_index ordered子数组在
#@return[Fixnum | Bignum]如果值的位置大于0,则返回-(插入点+1)
def self.binary_search(数组,值,from_index=0,to_index=array.length)
如果从_index<0 | |从_index>array.length | |从_index>到| index | |到_index>array.length,则引发(ArgumentError,“无效范围”)
_二进制搜索(数组、值、从索引到索引)
结束
私有的
#类似于二进制搜索,但没有范围检查。
#
#@param[Array]
Searching for 6 in [1, 3, 5, 7, 9]
a = 6, arr[middle_index] = 5, begin_index = 0, end_index = 4, middle_index = 2
a = 6, arr[middle_index] = 7, begin_index = 3, end_index = 4, middle_index = 3
a = 6, arr[middle_index] = 5, begin_index = 3, end_index = 2, middle_index = 2
the result is 3, the index for value 7
[1, 3, 5, 6, 7, 9]

Searching for 6 in [1, 3, 5, 7, 9, 11]
a = 6, arr[middle_index] = 5, begin_index = 0, end_index = 5, middle_index = 2
a = 6, arr[middle_index] = 9, begin_index = 3, end_index = 5, middle_index = 4
a = 6, arr[middle_index] = 7, begin_index = 3, end_index = 3, middle_index = 3
the result is 3, the index for value 7
[1, 3, 5, 6, 7, 9, 11]

Searching for 60 in [1, 3, 5, 7, 9]
a = 60, arr[middle_index] = 5, begin_index = 0, end_index = 4, middle_index = 2
a = 60, arr[middle_index] = 7, begin_index = 3, end_index = 4, middle_index = 3
a = 60, arr[middle_index] = 9, begin_index = 4, end_index = 4, middle_index = 4
the result is 5, the index for value nil
[1, 3, 5, 7, 9, 60]

Searching for 60 in [1, 3, 5, 7, 9, 11]
a = 60, arr[middle_index] = 5, begin_index = 0, end_index = 5, middle_index = 2
a = 60, arr[middle_index] = 9, begin_index = 3, end_index = 5, middle_index = 4
a = 60, arr[middle_index] = 11, begin_index = 5, end_index = 5, middle_index = 5
the result is 6, the index for value nil
[1, 3, 5, 7, 9, 11, 60]

Searching for -60 in [1, 3, 5, 7, 9]
a = -60, arr[middle_index] = 5, begin_index = 0, end_index = 4, middle_index = 2
a = -60, arr[middle_index] = 1, begin_index = 0, end_index = 1, middle_index = 0
a = -60, arr[middle_index] = 9, begin_index = 0, end_index = -1, middle_index = -1
the result is 0, the index for value 1
[-60, 1, 3, 5, 7, 9]

Searching for -60 in [1, 3, 5, 7, 9, 11]
a = -60, arr[middle_index] = 5, begin_index = 0, end_index = 5, middle_index = 2
a = -60, arr[middle_index] = 1, begin_index = 0, end_index = 1, middle_index = 0
a = -60, arr[middle_index] = 11, begin_index = 0, end_index = -1, middle_index = -1
the result is 0, the index for value 1
[-60, 1, 3, 5, 7, 9, 11]

Searching for -60 in [1]
a = -60, arr[middle_index] = 1, begin_index = 0, end_index = 0, middle_index = 0
the result is 0, the index for value 1
[-60, 1]

Searching for 60 in [1]
a = 60, arr[middle_index] = 1, begin_index = 0, end_index = 0, middle_index = 0
the result is 1, the index for value nil
[1, 60]

Searching for 60 in []
[60]
  BinarySearch_Left(A[0..N-1], value) {
      low = 0
      high = N - 1
      while (low <= high) {
          // invariants: value > A[i] for all i < low
                         value <= A[i] for all i > high
          mid = (low + high) / 2
          if (A[mid] >= value)
              high = mid - 1
          else
              low = mid + 1
      }
      return low
  }
def binary_search_helper(arr, a, begin_index, end_index)    
  if begin_index > end_index
    return begin_index
  else
    middle_index = (begin_index + end_index) / 2
    if arr[middle_index] == a
      return middle_index
    elsif a > arr[middle_index]
      return binary_search_helper(arr, a, middle_index + 1, end_index)
    else
      return binary_search_helper(arr, a, begin_index, middle_index - 1)
    end
  end
end

# for [1,3,5,7,9], searching for 6 will return index for 7 for insertion
# if exact match is found, then return that index
def binary_search(arr, a)
  return binary_search_helper(arr, a, 0, arr.length - 1)
end