Werkzeug für die binäre Suche („Halbierung“)

8

Implementieren Sie den binären Suchalgorithmus so, wie er verwendet wird, um die Quellcode-Revision zu identifizieren, die ein Computersoftwareprogramm beschädigt. Ihr Tool sollte zwei Argumente verwenden, die die früheste und letzte nummerierte Revision für die Suche angeben (beide positive Ganzzahlen), und Sie haben zwei Möglichkeiten, Vergleiche anzustellen:

  1. Führen Sie den Shell-Befehl aus ./test N, wobei N die Revisionsnummer ist. Wenn der Test erfolgreich ist ( dh die Revision ist gut), wird der Exit-Code 0 zurückgegeben.

  2. Rufen Sie die Funktion auf test(N), die andernfalls zurückgegeben wird, truewenn der Test erfolgreich ist false.

Die Standardausgabe muss die Nummer der ersten fehlerhaften Revision sein. Versuchen Sie, den Quellcode Ihres Tools so kurz wie möglich zu halten. Genießen!

PleaseStand
quelle
Nur eine Klarstellung, möchten Sie ein Skript oder nur eine Funktion?
Nemo157
@ Nemo157: Ein vollständiges Skript. Ich füge die test(N)Funktionsoption hauptsächlich hinzu, um den Programmiersprachen gerecht zu werden, ohne dass eine Standardmethode zum Ausführen von Shell-Befehlen wie JavaScript vorhanden ist.
PleaseStand

Antworten:

4

Ruby - 92 82 62 60 Zeichen

Iterativ ist viel kürzer, aber bei weitem nicht so cool wie Schwanz rekursiv.

l,h=$*.map &:to_i
test(m=(l+h)/2)?l=m+1:h=m-1 while l<=h
p l

Die alte rekursive Schwanzmethode als Referenz

b=proc{|l,h|h<l ?l:(m=(l+h)/2;test(m)?l=m+1:h=m-1;redo)}
puts b[*$*.map(&:to_i)]

Skript testen

Verwendet ein wenig Magie, um die testFunktion einzufügen , und führt eine Datei aus, die nur aus dem obigen Code besteht.

low = Random.rand(100)
mid = low + Random.rand(1e25)
high = mid + Random.rand(1e50)

File.open('./bisect-test-method.rb','w') do |file|
  file << "def test(value)
             value < #{mid}
           end
          "
end

puts "Using input:"
puts "  low=#{low}"
puts "  high=#{high}"
puts "  first_bad=#{mid}"
puts "Output: #{`ruby -r ./bisect-test-method golf-bisect.rb #{low} #{high}`}"

Ausgabe:

Using input:
  low=4
  high=75343785543465286986587973836706907796015092187720
  first_bad=5013102893257647460384884
Output: 5013102893257647460384884
Nemo157
quelle
5

Python, 64 Zeichen

Dieser ist rekursiv, so dass der Stapel für wirklich große Eingaben überläuft

01234567890123456789012345678901234567890123456789012345678901234567890
|         |         |         |         |         |         |         |
 B=lambda L,H:H>L+1 and B(*[L,L/2+H/2,H][test(L/2+H/2):][:2])or H

Testlauf

def test(n):
    print "testing ", n
    return n<66

L,H=10,1000


B=lambda L,H:H>L+1 and B(*[L,L/2+H/2,H][test(L/2+H/2):][:2])or H

print B(L,H)

Ausgänge

testing  505
testing  257
testing  133
testing  71
testing  40
testing  55
testing  62
testing  66
testing  64
testing  65
66
Gnibbler
quelle
Sollte 66 drucken, nicht 65 (Rückgabe H, nicht L).
Keith Randall
@ Keith, ok hat das geändert
Gnibbler
2

Python - 77 Zeichen

Missbrauch des Python-Halbierungsmoduls. L ist der niedrige Wert, H ist der hohe Wert

class B:__getitem__=lambda s,n:test(n)
import bisect as b
b.bisect(B(),0,L,H)

Hier ist ein Testlauf

def test(n):
    print "testing ", n
    return n>66
L,H=10,1000

class B:__getitem__=lambda s,n:test(n)
import bisect as b
b.bisect(B(),0,L,H)

Ausgänge

testing  505
testing  257
testing  133
testing  71
testing  40
testing  56
testing  64
testing  68
testing  66
testing  67

Erläuterung:

So wird Halbierung definiert. Grundsätzlich erwartet es eine Liste und entscheidet basierend auf dem Wert, den es durch Betrachten findet, ob es nach oben oder unten halbiert werden soll a[mid]. Diese Anrufe __getitem__auf a, die stattdessen eine Liste der zu sein, eine Klasse ist , dass ich mich definiert haben.

def bisect_right(a, x, lo=0, hi=None):
    """Return the index where to insert item x in list a, assuming a is sorted.

    The return value i is such that all e in a[:i] have e <= x, and all e in
    a[i:] have e > x.  So if x already appears in the list, a.insert(x) will
    insert just after the rightmost x already there.

    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """

    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        if x < a[mid]: hi = mid
        else: lo = mid+1
    return lo

bisect=bisect_right
Gnibbler
quelle
2

Python - 70 Zeichen

def B(L,H):
 while L+1<H:M=L+H;L,H=[L,M/2,H][test(M/2):][:2]
 return L

Testlauf

def test(n):
    print "testing ", n
    return n<66
L,H=10,1000

def B(L,H):
 while L+1<H:M=L+H;L,H=[L,M/2,H][test(M/2):][:2]
 return L

print B(L,H)

Ausgänge

testing  505
testing  257
testing  133
testing  71
testing  40
testing  55
testing  63
testing  67
testing  65
testing  66
65
Gnibbler
quelle