tyler-binary_search 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.textile +88 -0
- data/VERSION.yml +4 -0
- data/ext/binary_search.c +28 -0
- data/ext/extconf.rb +2 -0
- data/lib/binary_search/native.rb +1 -0
- data/lib/binary_search/pure.rb +15 -0
- data/lib/binary_search.rb +1 -0
- metadata +61 -0
data/README.textile
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
h1. Binary Search for Ruby's Arrays
|
2
|
+
|
3
|
+
One incredibly handy algorithm that is missing from Ruby's Array class is the binary search. If we *know* for *absolute certain* that the array we're working with is sorted you can use a binary search to search through the array much much more quickly than a linear search, which would be performed with index or detect/find.
|
4
|
+
|
5
|
+
Need proof? Howsabout some benchmarks:
|
6
|
+
|
7
|
+
<pre>
|
8
|
+
== Benchmark Ruby's builtin :index method vs. a pure Ruby binary search method
|
9
|
+
|
10
|
+
Benchmark for 2000000 iterations searching through an array of 5 elements.
|
11
|
+
user system total real
|
12
|
+
Index: 1.320000 0.010000 1.330000 ( 1.320691)
|
13
|
+
Ruby BI: 8.700000 0.010000 8.710000 ( 8.774825)
|
14
|
+
|
15
|
+
Benchmark for 1000000 iterations searching through an array of 10 elements.
|
16
|
+
user system total real
|
17
|
+
Index: 0.990000 0.000000 0.990000 ( 0.996690)
|
18
|
+
Ruby BI: 6.000000 0.010000 6.010000 ( 6.043375)
|
19
|
+
|
20
|
+
Benchmark for 1000000 iterations searching through an array of 100 elements.
|
21
|
+
user system total real
|
22
|
+
Index: 6.050000 0.020000 6.070000 ( 6.091887)
|
23
|
+
Ruby BI: 10.250000 0.010000 10.260000 ( 10.318961)
|
24
|
+
|
25
|
+
Benchmark for 100000 iterations searching through an array of 1000 elements.
|
26
|
+
user system total real
|
27
|
+
Index: 6.120000 0.010000 6.130000 ( 6.155703)
|
28
|
+
Ruby BI: 1.480000 0.010000 1.490000 ( 1.493227)
|
29
|
+
|
30
|
+
Benchmark for 10000 iterations searching through an array of 10000 elements.
|
31
|
+
user system total real
|
32
|
+
Index: 5.880000 0.010000 5.890000 ( 5.916098)
|
33
|
+
Ruby BI: 0.200000 0.000000 0.200000 ( 0.206104)
|
34
|
+
|
35
|
+
Benchmark for 1000 iterations searching through an array of 100000 elements.
|
36
|
+
user system total real
|
37
|
+
Index: 5.950000 0.010000 5.960000 ( 6.005916)
|
38
|
+
Ruby BI: 0.030000 0.000000 0.030000 ( 0.027823)
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
== Benchmark Ruby's builtin :index method vs. a native binary search method
|
43
|
+
|
44
|
+
Benchmark for 2000000 iterations searching through an array of 5 elements.
|
45
|
+
user system total real
|
46
|
+
Index: 1.360000 0.000000 1.360000 ( 1.369248)
|
47
|
+
Native BI: 1.140000 0.010000 1.150000 ( 1.144739)
|
48
|
+
|
49
|
+
Benchmark for 1000000 iterations searching through an array of 10 elements.
|
50
|
+
user system total real
|
51
|
+
Index: 0.960000 0.000000 0.960000 ( 0.971568)
|
52
|
+
Native BI: 0.630000 0.000000 0.630000 ( 0.637069)
|
53
|
+
|
54
|
+
Benchmark for 1000000 iterations searching through an array of 100 elements.
|
55
|
+
user system total real
|
56
|
+
Index: 6.150000 0.010000 6.160000 ( 6.192804)
|
57
|
+
Native BI: 0.810000 0.000000 0.810000 ( 0.816337)
|
58
|
+
|
59
|
+
Benchmark for 100000 iterations searching through an array of 1000 elements.
|
60
|
+
user system total real
|
61
|
+
Index: 6.170000 0.020000 6.190000 ( 6.216637)
|
62
|
+
Native BI: 0.110000 0.000000 0.110000 ( 0.111025)
|
63
|
+
|
64
|
+
Benchmark for 10000 iterations searching through an array of 10000 elements.
|
65
|
+
user system total real
|
66
|
+
Index: 5.980000 0.010000 5.990000 ( 6.033161)
|
67
|
+
Native BI: 0.010000 0.000000 0.010000 ( 0.013183)
|
68
|
+
|
69
|
+
Benchmark for 1000 iterations searching through an array of 100000 elements.
|
70
|
+
user system total real
|
71
|
+
Index: 5.920000 0.020000 5.940000 ( 5.972206)
|
72
|
+
Native BI: 0.000000 0.000000 0.000000 ( 0.001602)
|
73
|
+
</pre>
|
74
|
+
|
75
|
+
So, your array must be fairly large (between 100 and 1000 elements) for the Ruby version of binary_index to be faster than Ruby's builtin index method. However, even for arrays as small as 5 elements, the native version of the binary_index method is faster than Ruby's index. However, for very large sized Arrays, both the the pure and the native version are much much much faster than the builtin method.
|
76
|
+
|
77
|
+
<pre>
|
78
|
+
<code>
|
79
|
+
require 'binary_search/native'
|
80
|
+
|
81
|
+
x = [5,1,6,7,2,6,4,2,6,1,6,1,1,8,3,5,2].sort
|
82
|
+
puts x.binary_index(5)
|
83
|
+
</code>
|
84
|
+
</pre>
|
85
|
+
|
86
|
+
So the actual method is 'binary_index' as it does the same thing that 'index' does: returns the index of a matching element. It should be noted that 'index' returns the *first* instance of a matching element. 'binary_index' is not guaranteed to return the first. It should also be noted, again, that this will only work if the array is sorted correctly. If it's not weird crap will happen.
|
87
|
+
|
88
|
+
Oh yeah, and don't bother trying to require 'binary_search', it'll just throw an error telling you to either require 'binary_search/pure' or 'binary_search/native'. I'd always use native... but some people are weird.
|
data/VERSION.yml
ADDED
data/ext/binary_search.c
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
|
3
|
+
static ID id_cmp;
|
4
|
+
|
5
|
+
static VALUE rb_array_binary_index(VALUE self, VALUE value) {
|
6
|
+
int lower = 0;
|
7
|
+
int upper = RARRAY(self)->len - 1;
|
8
|
+
int i, comp;
|
9
|
+
|
10
|
+
while(lower <= upper) {
|
11
|
+
i = lower + (upper - lower) / 2;
|
12
|
+
comp = FIX2INT(rb_funcall(value, id_cmp, 1, RARRAY(self)->ptr[i]));
|
13
|
+
|
14
|
+
if(comp == 0) {
|
15
|
+
return LONG2NUM(i);
|
16
|
+
} else if(comp == 1) {
|
17
|
+
lower = i + 1;
|
18
|
+
} else {
|
19
|
+
upper = i - 1;
|
20
|
+
};
|
21
|
+
}
|
22
|
+
return Qnil;
|
23
|
+
}
|
24
|
+
|
25
|
+
void Init_binary_search() {
|
26
|
+
id_cmp = rb_intern("<=>");
|
27
|
+
rb_define_method(rb_cArray, "binary_index", rb_array_binary_index, 1);
|
28
|
+
}
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../ext/binary_search'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Array
|
2
|
+
def binary_index(target,lower=0,upper=self.size-1)
|
3
|
+
return if lower > upper
|
4
|
+
idx = lower + (upper - lower) / 2
|
5
|
+
value = self[idx]
|
6
|
+
if value == target
|
7
|
+
return idx
|
8
|
+
elsif value > target
|
9
|
+
self.binary_index(target, lower, idx - 1)
|
10
|
+
elsif value < target
|
11
|
+
self.binary_index(target, idx + 1, upper)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
raise "require 'binary_search/pure' for the pure Ruby implementation or 'binary_search/native' for the C version."
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tyler-binary_search
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tyler McMullen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-12-29 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Binary search and index methods for Ruby Arrays.
|
17
|
+
email: tbmcmullen@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions:
|
21
|
+
- ext/extconf.rb
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- README.textile
|
26
|
+
- VERSION.yml
|
27
|
+
- ext/binary_search.c
|
28
|
+
- ext/extconf.rb
|
29
|
+
- lib/binary_search
|
30
|
+
- lib/binary_search/native.rb
|
31
|
+
- lib/binary_search/pure.rb
|
32
|
+
- lib/binary_search.rb
|
33
|
+
has_rdoc: false
|
34
|
+
homepage: http://github.com/tyler/binary_search
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
- ext
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.2.0
|
57
|
+
signing_key:
|
58
|
+
specification_version: 2
|
59
|
+
summary: Binary search and index methods for Ruby Arrays.
|
60
|
+
test_files: []
|
61
|
+
|