我一直在研究一些搜索算法,而我的最后一个问题归结为二进制搜索。我观看了一些youtube视频以了解该概念,然后尝试解决该问题,但不断出现无休止的循环错误。我已经检查了堆栈溢出和reddit,以及Google会带我到哪里去,但我找不到适合我的编码方法的解决方案。另外,请原谅“猴子修补”一词,引起我注意的是,该技术术语被称为“扩展”,所以我的指导老师将其作为“猴子修补”来教给我们的是错。
这是我的代码:
class Array
def my_bsearch(target)
return nil if self.empty?
middle_idx = self.length/2
left = self.take(middle_idx)
right = self.drop(middle_idx + 1)
return middle_idx if self[middle_idx] == target
until self[middle_idx] == target || self.nil? == nil
if self[middle_idx] < target
right.my_bsearch(target)
elsif self[middle_idx] > target
left.my_bsearch(target)
end
end
end
end
我有一个解决方案,但是我不想只记住它-我在理解它时遇到了麻烦;当我尝试翻译它,学习它并将我所缺少的东西实现到自己的代码中时。
class Array
def my_bsearch(target)
return nil if size == 0
mid = size/2
case self[mid] <=> target
when 0
return mid
when 1
return self.take(mid).my_bsearch(target)
else
search_res = self.drop(mid+1).my_bsearch(target)
search_res.nil? ? nil : mid + 1 + search_res
end
end
end
我猜我了解情况,尽管不习惯使用它。我尝试使用调试器来跟踪它,但是我认为我对ELSE部分中发生的事情挂了电话。虽然语法糖显然比我的逻辑更简洁,但对我的红宝石知识水平的人来说并不简单明了。所以,是的,我的无知是我猜到的大部分问题。
有没有一个识字能力和耐心的人,能够帮助我将其分解为我可以更好地理解的东西,以便我可以从中学习?
答案 0 :(得分:1)
首先,take
和drop
具有足够相似的界面,您实际上并不想放下+ 1
。如果这样做,它将忽略数组中的一个元素。
接下来,对于此类的实例,self.nil?
将始终为false
(并且永远不会为nil
)。实际上,.nil?
是一种完全避免必须与nil
与==
进行比较的方法。
您想要self.empty?
。此外,除设置器外,默认情况下,在Ruby中,消息会发送到self
。换句话说,self.
是有用的前缀的唯一时间是消息以=
结尾并且像self.instance_var = 'a constant'
那样作为左值运行,因为没有self.
,标记instance_var =
将被解释为局部变量,而不是实例变量设置。这里不是这种情况,因此empty?
就足够了self.empty?
答案 1 :(得分:0)
所以我想出了办法,所以我决定回答我自己的帖子,以希望在遇到此问题时能帮助其他人。
因此,如果我有一个Array,并且目标是middle_element,则它将报告middle_element_idx。没关系。如果目标小于middle_element怎么办?它递归搜索原始数组的左侧。找到后,将报告left_side_idx。这样做没有问题,因为数组中的元素从左到右依次计数。因此,它从0开始并上升。
但是如果目标位于中间元素的右侧怎么办?
好吧,搜索右侧很容易。逻辑与向左搜索相对。递归完成。如果在右侧找到了target_idx,它将返回一个target_idx-但是,这是在右侧数组中找到的目标的IDx!因此,您需要获取返回的target_idx并将其添加1并添加原始的middle_element_idx。见下文:
def my_bsearch(target)
return nil if self.empty?
middle_idx = self.length/2
left = self.take(middle_idx)
right = self.drop(middle_idx + 1)
if self[middle_idx] == target
return middle_idx
elsif self[middle_idx] > target
return left.my_bsearch(target)
else
searched_right_side = 1 + right.my_bsearch(target)
return nil if searched_right_side.nil? == true
return searched_right_side + middle_idx
end
end
end
请注意此解决方案还有多少行?与case / when和三元方法结合使用的飞船运算符将大大减少行数。
根据蒂姆的建议/反馈,我将其更新为:
def my_bsearch(target)
return nil if empty?
middle_idx = self.length/2
left = self.take(middle_idx)
right = self.drop(middle_idx)
if self[middle_idx] == target
return middle_idx
elsif self[middle_idx] > target
return left.my_bsearch(target)
else
searched_right_side = right.my_bsearch(target)
return nil if searched_right_side.nil?
return searched_right_side + middle_idx
end
end
end