簡體   English   中英

smalltalk 中的二分查找

[英]Binary Search in smalltalk

Array extend [
   Array class >> bin: val left: l right: r [
      ^ super binSearch: val left: l right: r
   ]

   binSearch: val left: l right: r [
      |arr iter|
      arr := self.
      [l == r]
         ifTrue: [^ (-1)].
      iter := (r + l)/2.
      [arr at: iter == val]
         ifTrue: [^iter].
      [arr at: iter < val]
         ifTrue:[^ super binSearch val left: l right: iter]
         ifFalse: [^ super binSearch val left: iter right: r]
   ]
]
arr := #(3 6 9 10).
arr bin: 6 left: 1 right: 4.

這是我當前的代碼,但我收到編譯錯誤:“對象:新數組:4“<0x7fe20936e940>”錯誤:不理解 #bin:left:right:”。 我想知道我做錯了什么。

謝謝

第一部分對我來說毫無意義。 你的算法是遞歸的,所以它應該調用自己而不是委托給 class,這是一個不同的 object。

為此,請將super替換為self ,然后將使用新參數再次調用相同的方法。

Array extend [
   binSearch: val left: l right: r [
      |arr iter|
      arr := self.
      l = r
         ifTrue: [^ -1].
      iter := (r + l) // 2.
      (arr at: iter) = val
         ifTrue: [^iter].
      (arr at: iter) < val
         ifTrue:[^ self binSearch: val left: l right: iter]
         ifFalse: [^ self binSearch: val left: iter right: r]
   ]
]

補充說明

  1. [布爾] ifTrue: &friends 的接收者必須是Boolean (即truefalse )。 通過將條件括在方括號之間,您正在創建一個BlockClosure 我已經在適當的情況下將[...]替換為(...) ,然后在不需要時將其刪除(請參閱下面的 [Precedence])。

  2. [比較] 這是有爭議的,但是雖然條件l==r並不完全錯誤,但是l=r通常更好。 原因: ==的語義對應於完全相同的 object(低級), =的語義等於(或等價)。 您的算法不關心lr是否由完全相同的 object 表示,它只需要知道兩個變量是否具有相同的 integer。 盡管這種區別在這種情況下無關緊要,但您可能會養成使用==的習慣,這將在您處理其他類型的對象(vg LargeIntegers等)的那一天失敗

  3. [括號] ^ -1不需要加括號。

  4. [除法] 因為+/是消息,所以在r + 1 / 2中也不需要加括號。 但是,除法可能會產生一個Fraction ,您的代碼需要Integer 改為使用//來獲取商。

  5. [冒號] 您忘記了binSearch之后的冒號。 這會產生 DNU 錯誤。

  6. [優先級] arr at: iter周圍需要括號,以便將此消息的結果與val進行比較(請記住,優先級順序是:一元、二元、關鍵字)。

  7. [ DNU ] 關於您收到的錯誤:您創建的選擇器是binSearch:left:right: ,但是您發送的消息bin:left:right:未定義。

  8. [ self ] 不需要將self分配給其他東西:接收者不會隨着遞歸而改變。

  9. [返回] 許多 Smalltalker 應該將返回符號^移到最后一個表達式的開頭。

  10. 在 Smalltalk 中, arrays 是基於 1 的,廣泛接受的約定是在沒有找到索引時返回0 (而不是-1 )。

Array extend [
   binSearch: val left: l right: r [
      | iter |
      l = r ifTrue: [^ 0].
      iter := (r + l) // 2.
      (self at: iter) = val ifTrue: [^iter].
      ^ (self at: iter) < val
         ifTrue:[self binSearch: val left: l right: iter]
         ifFalse: [self binSearch: val left: iter right: r]
   ]
]

建議

  • 通過添加足夠的單元測試來練習和改進您的方法來完成您的工作。 我將我的答案限制在編碼風格上,而不是它的正確性。

  • 添加以下方法,以便您的服務的客戶端在使用它時不需要冗長。

binSearch: value
  ^self binSearch: value left: 1 right: self size
  • 考慮將選擇器更改為更具可讀性的內容。 您的選擇器不是一個句子,而是一種命名參數的方式。 關於什么?
binarySearch: value from: left to: right

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM