バイナリ検索(「二分」)ツール


8

コンピューターソフトウェアプログラムを破壊するソースコードのリビジョンを識別するために使用されるバイナリ検索アルゴリズムを実装します。ツールは、検索する最も古いおよび最新の番号付きリビジョン(両方とも正の整数)を指定する2つの引数を取る必要があり、比較を行うための2つのオプションがあります。

  1. シェルコマンドを実行し./test N、Nはリビジョン番号です。テストに合格した場合(つまり、リビジョンが良好である場合)、終了コード0が返されます。

  2. テストに合格した場合test(N)に戻る関数を呼び出します。そうでないtrue場合は戻りfalseます。

標準出力は最初の不正なリビジョンの番号でなければならず、ツールのソースコードをできるだけ短くするようにしてください。楽しい!


いくつかの明確化、あなたはスクリプトが欲しいですか、それとも関数が欲しいですか?
— Nemo157

@ Nemo157:完全なスクリプト。test(N)JavaScriptなどのシェルコマンドを実行する標準的な方法がないプログラミング言語に公平に対応するために、主に関数オプションを含めています。
— PleaseStand

回答:


4

Ruby- 92 82 62 60文字

反復ははるかに短いですが、再帰的な末尾ほどクールではありません。

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

参考のために古い末尾再帰法

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)]

テストスクリプト

少し魔法を使ってtest関数を挿入し、上記のコードだけで構成されるファイルを実行します。

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}`}"

出力:

Using input:
  low=4
  high=75343785543465286986587973836706907796015092187720
  first_bad=5013102893257647460384884
Output: 5013102893257647460384884

5

Python、64文字

これは再帰的であるため、入力が非常に大きい場合はスタックがオーバーフローします

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

試運転

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)

出力

testing  505
testing  257
testing  133
testing  71
testing  40
testing  55
testing  62
testing  66
testing  64
testing  65
66

65ではなく66を印刷する必要があります(LではなくHを返します)。
— キースランドール

@キース、それは変更されました
— ニブラー

2

Python-77文字

Python bisectモジュールの悪用。Lは低い値、Hは高い値

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

これが試運転です

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)

出力

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

説明:

二分法の定義は次のとおりです。基本的にそれはリストを期待し、を見て見つけた値に基づいて上または下に二分するかどうかを決定しa[mid]ます。この呼び出し__getitem__のa代わりにリストされて、私は自分自身が定義されていることをクラスです。

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

2

Python-70文字

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

試運転

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)

出力

testing  505
testing  257
testing  133
testing  71
testing  40
testing  55
testing  63
testing  67
testing  65
testing  66
65
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.