algorithms 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/History.txt +139 -2
  2. data/Manifest +31 -8
  3. data/README +90 -0
  4. data/Rakefile +22 -9
  5. data/algorithms.gemspec +28 -101
  6. data/benchmark.rb +29 -27
  7. data/benchmarks/rbench.rb +16 -0
  8. data/benchmarks/rbench/column.rb +26 -0
  9. data/benchmarks/rbench/group.rb +43 -0
  10. data/benchmarks/rbench/report.rb +53 -0
  11. data/benchmarks/rbench/runner.rb +109 -0
  12. data/benchmarks/rbench/summary.rb +51 -0
  13. data/benchmarks/sorts.rb +33 -0
  14. data/ext/containers/bst/bst.c +205 -0
  15. data/ext/containers/{priority_queue → bst}/extconf.rb +1 -1
  16. data/ext/containers/deque/deque.c +233 -0
  17. data/ext/containers/deque/extconf.rb +4 -0
  18. data/ext/containers/tree_map/extconf.rb +1 -1
  19. data/ext/containers/tree_map/rbtree.c +73 -25
  20. data/lib/algorithms.rb +65 -6
  21. data/lib/algorithms/search.rb +84 -0
  22. data/lib/algorithms/sort.rb +238 -0
  23. data/lib/containers/deque.rb +176 -0
  24. data/lib/containers/heap.rb +451 -111
  25. data/lib/containers/kd_tree.rb +87 -0
  26. data/lib/containers/priority_queue.rb +107 -508
  27. data/lib/containers/queue.rb +62 -23
  28. data/lib/containers/rb_tree_map.rb +398 -0
  29. data/lib/containers/splay_tree_map.rb +274 -0
  30. data/lib/containers/stack.rb +59 -21
  31. data/lib/containers/suffix_array.rb +68 -0
  32. data/lib/containers/trie.rb +182 -0
  33. data/lib/graphs/graph.rb +25 -0
  34. data/spec/bst_spec.rb +31 -0
  35. data/spec/deque_spec.rb +108 -0
  36. data/spec/heap_spec.rb +111 -66
  37. data/spec/kd_tree_spec.rb +89 -0
  38. data/spec/priority_queue_spec.rb +71 -27
  39. data/spec/queue_spec.rb +53 -45
  40. data/spec/rb_tree_map_spec.rb +123 -0
  41. data/spec/search_spec.rb +28 -0
  42. data/spec/sort_spec.rb +28 -0
  43. data/spec/splay_tree_map_spec.rb +102 -0
  44. data/spec/stack_spec.rb +56 -49
  45. data/spec/suffix_array_spec.rb +40 -0
  46. data/spec/trie_spec.rb +59 -0
  47. metadata +54 -32
  48. data/README.txt +0 -58
  49. data/ext/containers/priority_queue/priority_queue.c +0 -948
  50. data/ext/containers/tree_map/Rakefile +0 -4
  51. data/lib/containers/hash.rb +0 -0
  52. data/lib/containers/tree_map.rb +0 -265
  53. data/spec/priority_queue_test.rb +0 -371
  54. data/spec/tree_map_spec.rb +0 -99
@@ -1,4 +1,7 @@
1
- require 'lib/algorithms'
1
+ # :nodoc: all
2
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), 'lib')
3
+ require 'algorithms'
4
+
2
5
  require 'benchmark'
3
6
  include Benchmark
4
7
 
@@ -6,44 +9,43 @@ include Benchmark
6
9
  @random_array = []
7
10
  @num_items = 10000
8
11
  @num_items.times { |x| @random_array << rand(@num_items) }
9
- # @heap = DS::MaxHeap.new(@random_array)
10
-
12
+ # @heap = Containers::MaxHeap.new(@random_array)
13
+ #
11
14
  # benchmark do |bench|
12
15
  # bench.report("Array#max:\t ") do
13
16
  # @num_items.times { @random_array.delete_at(@random_array.index(@random_array.max)) }
14
17
  # end
15
18
  # bench.report("MaxHeap:\t ") do
16
- # @num_items.times { @heap.get_max! }
19
+ # @num_items.times { @heap.max! }
17
20
  # end
18
21
  # end
19
22
 
23
+ # Benchmark Deque
24
+ deque = Containers::RubyDeque.new
25
+ array = []
26
+ benchmark do |bench|
27
+ bench.report("Array:\t ") { 1000000.times { |x| array << x } }
28
+ bench.report("Deque:\t ") { 1000000.times { |x| deque.push_back(x) } }
29
+ end
30
+
20
31
  # Benchmark Search trees
21
- @tree = Containers::TreeMap.new
22
- @ctree = Containers::TreeMap.new
32
+ @rb_tree = Containers::RubyRBTreeMap.new
33
+ @splay_tree = Containers::SplayTreeMap.new
23
34
  @hash = Hash.new
24
35
 
25
36
  benchmark do |bench|
26
- bench.report("Tree: \t") do
27
- @random_array.each { |x| @tree[x] = x }
28
- end
29
-
30
- bench.report("CTree: \t") do
31
- @random_array.each { |x| @ctree[x] = x }
32
- end
33
-
34
- bench.report("Hash: \t") do
35
- @hash.each { |x| @hash[x] = x }
36
- end
37
-
38
- bench.report("Hash: \t") do
39
- @num_items.times { |n| @hash.has_key?(n) }
40
- end
37
+ puts "\nInsertion"
38
+ bench.report("RBTree: \t") { @random_array.each { |x| @rb_tree[x] = x } }
39
+ bench.report("SplayTree: \t") { @random_array.each { |x| @splay_tree[x] = x } }
40
+ bench.report("Hash: \t\t") { @hash.each { |x| @hash[x] = x } }
41
41
 
42
- bench.report("Tree: \t") do
43
- @num_items.times { |n| @tree.contains?(n) }
44
- end
42
+ puts "\nTest has_key?"
43
+ bench.report("RBTree: \t") { @num_items.times { |n| @rb_tree.has_key?(n) } }
44
+ bench.report("SplayTree: \t") { @num_items.times { |n| @splay_tree.has_key?(n) } }
45
+ bench.report("Hash: \t\t") { @num_items.times { |n| @hash.has_key?(n) } }
45
46
 
46
- bench.report("CTree: \t") do
47
- @num_items.times { |n| @ctree.contains?(n) }
48
- end
47
+ puts "\nSorted order"
48
+ bench.report("RBTree: \t") { @rb_tree.each { |k, v| k } }
49
+ bench.report("SplayTree: \t") { @splay_tree.each { |k, v| k } }
50
+ bench.report("Hash: \t\t") { @hash.sort.each { |k, v| k } }
49
51
  end
@@ -0,0 +1,16 @@
1
+ require 'pathname'
2
+ require 'benchmark'
3
+
4
+ dir = Pathname(__FILE__).dirname.expand_path + 'rbench/'
5
+
6
+ require dir + 'runner'
7
+ require dir + 'column'
8
+ require dir + 'group'
9
+ require dir + 'report'
10
+ require dir + 'summary'
11
+
12
+ module RBench
13
+ def self.run(times=1, &block)
14
+ Runner.new(times).run(&block)
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ module RBench
2
+ class Column
3
+ attr_accessor :name, :title, :width, :compare, :default
4
+
5
+ def initialize(runner, name, options = {})
6
+ @runner = runner
7
+ @name = name
8
+ @title = options[:title] || (@name == :times ? "" : @name.to_s.upcase)
9
+ @width = options[:width] || [@title.length,7].max
10
+ @compare = options[:compare]
11
+ @default = @compare ? @compare : options[:default]
12
+ end
13
+
14
+ def to_s(val=title)
15
+ str = case val
16
+ when Array then "%#{width-1}.2f" % (val[0] / val[1]) + "x"
17
+ when Float then "%#{width}.3f" % val
18
+ when Integer then "%#{width}.0f" % val
19
+ when TrueClass then " "*(width/2.0).floor + "X" + " "*(width/2.0).floor
20
+ when String then "%#{width}s" % (val)[0,width]
21
+ when Object then " " * width
22
+ end
23
+ return " #{(str.to_s+" "*width)[0,width]} |"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,43 @@
1
+ module RBench
2
+ class Group
3
+ self.instance_methods.each do |m|
4
+ send(:undef_method, m) unless m =~ /^(__|is_a?|kind_of?|respond_to?|hash|eql?|inspect|instance_eval)/
5
+ end
6
+
7
+ attr_reader :name, :items, :block, :times
8
+
9
+ def initialize(runner, name, times=nil, &block)
10
+ @runner = runner
11
+ @name = name
12
+ @items = []
13
+ @block = block
14
+ @times = times || @runner.times
15
+ end
16
+
17
+ def prepare
18
+ # This just loops through and spawns the reports, and the summary (if exists)
19
+ self.instance_eval(&@block) if @block
20
+ # Now we want to make sure that the summary is
21
+ @items << @items.shift if @items.first.is_a?(Summary)
22
+ end
23
+
24
+ def run
25
+ # Put a separator with the group-name at the top. puts?
26
+ puts @runner.separator(@name)
27
+ # Now loop through the items in this group, and run them
28
+ @items.each{|item| item.run}
29
+ end
30
+
31
+ def report(name,times=@times,&block)
32
+ @items << Report.new(@runner,self,name,times,&block)
33
+ end
34
+
35
+ def summary(name)
36
+ @items.unshift(Summary.new(@runner,self,name)) unless @items.detect{|i| i.is_a?(Summary)}
37
+ end
38
+
39
+ def to_s
40
+ @runner.separator(@name) << @items.map { |item| item.to_s }.join
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,53 @@
1
+ module RBench
2
+ class Report
3
+ self.instance_methods.each do |m|
4
+ send(:undef_method, m) unless m =~ /^(__|is_a?|kind_of?|respond_to?|hash|inspect|instance_eval|eql?)/
5
+ end
6
+
7
+ attr_reader :name, :cells
8
+
9
+ def initialize(runner, group, name, times=nil,&block)
10
+ @runner = runner
11
+ @group = group
12
+ @name = name
13
+ @times = (times || runner.times).ceil
14
+ @cells = {}
15
+ @block = block
16
+
17
+ # Setting the default for all cells
18
+ runner.columns.each {|c| @cells[c.name] = c.name == :times ? "x#{@times}" : c.default }
19
+
20
+ new_self = (class << self; self end)
21
+ @runner.columns.each do |column|
22
+ new_self.class_eval <<-CLASS
23
+ def #{column.name}(val=nil,&block)
24
+ @cells[#{column.name.inspect}] = block ? Benchmark.measure { @times.times(&block) }.real : val
25
+ end
26
+ CLASS
27
+ end
28
+ end
29
+
30
+ def run
31
+ # runs the actual benchmarks. If there is only one column, just evaluate the block itself.
32
+ if @runner.columns.length == 1
33
+ @cells[@runner.columns.first.name] = Benchmark.measure { @times.times(&@block) }.real
34
+ else
35
+ self.instance_eval(&@block)
36
+ end
37
+ # puts its row now that it is complete
38
+ puts to_s
39
+ end
40
+
41
+ def to_s
42
+ out = "%-#{@runner.desc_width}s" % name
43
+ @runner.columns.each do |column|
44
+ value = @cells[column.name]
45
+ value = @cells.values_at(*value) if value.is_a?(Array)
46
+ value = nil if value.is_a?(Array) && value.nitems != 2
47
+
48
+ out << column.to_s(value)
49
+ end
50
+ out << @runner.newline
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,109 @@
1
+ module RBench
2
+ class Runner
3
+ attr_accessor :columns, :items, :times, :width
4
+
5
+ def initialize(times)
6
+ @width = 0
7
+ @times = times
8
+ @columns = []
9
+ @items = []
10
+ end
11
+
12
+ def run(&block)
13
+
14
+ # initiate all the columns, groups, reports, and summaries on top level.
15
+ self.instance_eval(&block)
16
+
17
+ # the groups has not run just yet, but when they do, we really only want
18
+ # to make them initiate their reports, not run them (just yet)
19
+ # when we only have two levels, _every_ report should now be initialized.
20
+ @items.each{|item| item.prepare if item.is_a?(Group)}
21
+
22
+ # We are putting the summary to the back if its there.
23
+ @items << @items.shift if @items.first.is_a?(Summary)
24
+
25
+ # if on columns were set, create a default column
26
+ column(:results, :title => "Results") if @columns.empty?
27
+
28
+ # since we are about to start rendering, we put out the column-header
29
+ puts header
30
+
31
+ # now we are ready to loop through our items and run!
32
+ items.each { |item| item.run if item.respond_to?(:run) }
33
+
34
+ # returning self so people can output it in different formats.
35
+ self
36
+ end
37
+
38
+ def format(options={})
39
+ @width = options.delete(:width) || @width
40
+ end
41
+
42
+ def column(name,options={})
43
+ @columns << Column.new(self,name,options)
44
+ end
45
+
46
+ def group(name,times=nil,&block)
47
+ @items << Group.new(self,name,times,&block)
48
+ end
49
+
50
+ def report(name,times=nil,&block)
51
+ # create an anonymous group, or add it to the last open group.
52
+ group(nil) unless @items.last.is_a?(Group) && !@items.last.block
53
+ # now create the report on the last group
54
+ @items.last.report(name,times,&block)
55
+ end
56
+
57
+ def summary(name)
58
+ # adding the summary to the front, so it is easier to put it last later.
59
+ @items.unshift(Summary.new(self,nil,name)) unless @items.detect{|i| i.is_a?(Summary)}
60
+ end
61
+
62
+ ##
63
+ # convenience-methods
64
+ ##
65
+
66
+ def groups
67
+ @items.select{|item| item.is_a?(Group) }
68
+ end
69
+
70
+ def reports
71
+ # we now want _all_ reports, also those that are part of subgroups
72
+ groups.map{|g| g.items.select{|item| item.is_a?(Report) } }.flatten
73
+ end
74
+
75
+ ##
76
+ # for rendering text. pull out in separate module when to_xml and to_html is in place
77
+ ##
78
+
79
+ def newline
80
+ "\n"
81
+ end
82
+
83
+ def header
84
+ " " * desc_width + @columns.map {|c| c.to_s }.join + newline
85
+ end
86
+
87
+ def desc_width
88
+ @desc_width ||= [items.map{|i| (i.items.map{|r| r.name} << i.name) }.flatten.map{|i| i.to_s.length}.max+8,@width-columns_width].max
89
+ end
90
+
91
+ def columns_width
92
+ @columns.inject(0){ |tot,c| tot += (c.to_s.length) }
93
+ end
94
+
95
+ def width(value=nil)
96
+ header.length-1
97
+ end
98
+
99
+ def separator(title=nil,chr="-",length=width)
100
+ title ? chr*2 + title + chr * (width - title.length - 2) : chr * length
101
+ end
102
+
103
+ def to_s
104
+ out = " " * desc_width + @columns.map {|c| c.to_s }.join + newline
105
+ out << @items.map {|item| item.to_s}.join
106
+ end
107
+
108
+ end
109
+ end
@@ -0,0 +1,51 @@
1
+ module RBench
2
+ class Summary
3
+ attr_reader :name, :runner, :cells, :items
4
+ attr_accessor :lines
5
+
6
+ def initialize(runner, group, name)
7
+ @runner = runner
8
+ @group = group
9
+ @name = name
10
+ @cells = {} # A hash with keys as columns, and values being the result
11
+ @items = []
12
+ end
13
+
14
+ def run
15
+ # maybe add convenience-method to group to. group == runner really.
16
+ items = (@group ? @group.items & @runner.reports : @runner.reports)
17
+
18
+ rows = items.map{|item| item.cells.values_at(*@runner.columns.map{|c|c.name}) }
19
+ rows = rows.pop.zip(*rows)
20
+
21
+ @runner.columns.each_with_index do |c,i|
22
+ if c.compare
23
+ value,comparisons = 0,0
24
+ items.each do |item|
25
+ v1,v2 = *item.cells.values_at(*c.compare)
26
+ if v1.kind_of?(Numeric) && v2.kind_of?(Numeric) && v1 != 0 && v2 != 0
27
+ value += v1 / v2
28
+ comparisons += 1
29
+ end
30
+ end
31
+ @cells[c.name] = [value,comparisons] if comparisons > 0
32
+ elsif c.name != :times
33
+ @cells[c.name] = rows[i].compact.select{|r| r.kind_of?(Numeric)}.inject(0){|tot,v| tot += v.to_f }
34
+ end
35
+ end
36
+
37
+ puts to_s
38
+ end
39
+
40
+ def to_s
41
+ out = ""
42
+ out << @runner.separator(nil,"=") + @runner.newline unless @group
43
+ out << "%-#{@runner.desc_width}s" % name
44
+ @runner.columns.each do |column|
45
+ value = @cells[column.name]
46
+ out << column.to_s( value )
47
+ end
48
+ out << @runner.newline
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,33 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '../lib')
2
+ require 'algorithms'
3
+ include Algorithms
4
+
5
+ require 'rbench'
6
+
7
+ RBench.run(5) do
8
+
9
+ sorts = %w(built_in comb_sort heapsort insertion_sort shell_sort quicksort mergesort)
10
+ sorts.each { |sort| self.send(:column, sort.intern) }
11
+
12
+ n = 1000
13
+
14
+ proc = lambda { |scope, ary|
15
+ scope.built_in { ary.dup.sort }
16
+ scope.comb_sort { Sort.comb_sort(ary.dup) }
17
+ scope.heapsort { Sort.heapsort(ary.dup) }
18
+ scope.insertion_sort { Sort.insertion_sort(ary.dup) }
19
+ scope.shell_sort { Sort.shell_sort(ary.dup) }
20
+ scope.quicksort { Sort.quicksort(ary.dup) }
21
+ scope.mergesort { Sort.mergesort(ary.dup) }
22
+ }
23
+
24
+ report "Already sorted" do
25
+ sorted_array = Array.new(n) { rand(n) }.sort
26
+ proc.call(self, sorted_array)
27
+ end
28
+
29
+ report "Random" do
30
+ random_array = Array.new(n) { rand(n) }
31
+ proc.call(self, random_array)
32
+ end
33
+ end
@@ -0,0 +1,205 @@
1
+ #include "ruby.h"
2
+ #include <ctype.h>
3
+
4
+ #ifndef RSTRING_PTR
5
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
6
+ #endif
7
+
8
+ /* for compatibility with Ruby 1.8.5, which doesn't declare RSTRING_LEN */
9
+ #ifndef RSTRING_LEN
10
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
11
+ #endif
12
+
13
+ typedef struct struct_bst_node {
14
+ VALUE key;
15
+ VALUE data;
16
+ struct struct_bst_node *left;
17
+ struct struct_bst_node *right;
18
+ struct struct_bst_node *parent;
19
+ } bst_node;
20
+
21
+
22
+ typedef struct struct_bst_head {
23
+ bst_node *head;
24
+ unsigned int size;
25
+ } bst_head;
26
+
27
+ static VALUE bst_initialize(VALUE self) {
28
+ return self;
29
+ }
30
+
31
+ static void in_order_display (bst_node *root) {
32
+ if (root) {
33
+ in_order_display(root->left);
34
+ rb_yield(rb_assoc_new(root->key,root->data));
35
+ in_order_display(root->right);
36
+ }
37
+ }
38
+
39
+ static int id_compare_operator;
40
+
41
+ static int rb_key_compare(VALUE a, VALUE b) {
42
+ return FIX2INT(rb_funcall((VALUE) a, id_compare_operator, 1, (VALUE) b));
43
+ }
44
+
45
+ static void insert_element(bst_node **root,bst_node *newElement) {
46
+ bst_node *y = NULL;
47
+ bst_node *x = *root;
48
+ while (x != NULL) {
49
+ y = x;
50
+ //if (newElement->key < x->key) x = x->left;
51
+ if (rb_key_compare(newElement->key,x->key) < 0) x = x->left;
52
+ else x = x->right;
53
+ }
54
+ newElement->parent = y;
55
+ if (y == NULL) *root = newElement;
56
+ //else if (newElement->key < y->key) y->left = newElement;
57
+ else if (rb_key_compare(newElement->key,y->key) < 0) y->left = newElement;
58
+ else y->right = newElement;
59
+ }
60
+
61
+
62
+ static bst_node *create_element(VALUE key_data,VALUE data) {
63
+ bst_node *arbit = malloc(sizeof(bst_node));
64
+ arbit->data = data;
65
+ arbit->key = key_data;
66
+ arbit->left = NULL;
67
+ arbit->right = NULL;
68
+ arbit->parent = NULL;
69
+ return arbit;
70
+ }
71
+
72
+
73
+ static bst_node *tree_minimum (bst_node *root) {
74
+ bst_node *x = root;
75
+ while (x->left) x = x->left;
76
+ return x;
77
+ }
78
+
79
+
80
+ static bst_node *tree_maximum (bst_node *root) {
81
+ bst_node *x = root;
82
+ while (x->right) x = x->right;
83
+ return x;
84
+ }
85
+
86
+ static bst_node *node_successor (bst_node *root,bst_node *x) {
87
+ if (x->right) return tree_minimum(x->right);
88
+ bst_node *y = x->parent;
89
+ while (y && x == y->right) {
90
+ x = y;
91
+ y = x->parent;
92
+ }
93
+ return y;
94
+ }
95
+
96
+
97
+ bst_node *delete_node (bst_node **root,bst_node *tobeDeleted) {
98
+ bst_node *y,*x;
99
+
100
+ if ((tobeDeleted->left == NULL) || (tobeDeleted->right == NULL)) y = tobeDeleted;
101
+ else y = node_successor(*root,tobeDeleted);
102
+
103
+ if (y->left) x = y->left;
104
+ else x = y->right;
105
+
106
+ if (x) x->parent = y->parent;
107
+
108
+ if (y->parent == NULL) {
109
+ *root = x;
110
+ return y;
111
+ } else if (y == y->parent->left) {
112
+ y->parent->left = x;
113
+ } else {
114
+ y->parent->right = x;
115
+ }
116
+
117
+ if (tobeDeleted != y) tobeDeleted->key = y->key;
118
+ return y;
119
+ }
120
+
121
+ bst_node *search_node (bst_node *root,VALUE key) {
122
+ bst_node *x = root;
123
+ while (x) {
124
+ //if (x->key == key) return x;
125
+ if (rb_key_compare(x->key,key) == 0) return x;
126
+ //else if (key < x->key) x = x->left;
127
+ else if (rb_key_compare(key,x->key) < 0) x = x->left;
128
+ else x = x->right;
129
+ }
130
+ return NULL;
131
+ }
132
+
133
+ void delete_nodes_recur(bst_node *root) {
134
+ if(root) {
135
+ delete_nodes_recur(root->left);
136
+ if(root) free(root);
137
+ delete_nodes_recur(root->right);
138
+ }
139
+ }
140
+
141
+ static void bst_free_node(void *p) {
142
+ bst_head *headNode = (bst_head *)p;
143
+ delete_nodes_recur(headNode->head);
144
+ }
145
+
146
+ static VALUE bst_alloc(VALUE klass) {
147
+ bst_head *headNode = ALLOC(bst_head);
148
+ headNode->head = NULL;
149
+ headNode->size = 0;
150
+ VALUE obj;
151
+ obj = Data_Wrap_Struct(klass,NULL,bst_free_node,headNode);
152
+ return obj;
153
+ }
154
+
155
+ static VALUE rb_bst_insert_value(VALUE self,VALUE key,VALUE data) {
156
+ bst_head *headNode;
157
+ Data_Get_Struct(self,bst_head,headNode);
158
+ insert_element(&(headNode->head),create_element(key,data));
159
+ headNode->size++;
160
+ return self;
161
+ }
162
+
163
+ /* data structure builds up a stack for traversal, delete can be harmful */
164
+ static VALUE rb_bst_each(VALUE self)
165
+ {
166
+ bst_head *headNode;
167
+ Data_Get_Struct(self,bst_head,headNode);
168
+ in_order_display(headNode->head);
169
+ return Qnil;
170
+ }
171
+
172
+ static VALUE rb_bst_delete(VALUE self,VALUE keyVal) {
173
+ //int key = FIX2INT(keyVal);
174
+ bst_head *headNode;
175
+ Data_Get_Struct(self,bst_head,headNode);
176
+ bst_node *tobeDeleted = search_node(headNode->head,keyVal);
177
+ if(tobeDeleted) {
178
+ headNode->size = headNode->size - 1;
179
+ bst_node *deletedNode = delete_node(&(headNode->head),tobeDeleted);
180
+ return deletedNode->data;
181
+ } else {
182
+ rb_raise(rb_eArgError, "Key was not found");
183
+ return Qnil;
184
+ }
185
+ }
186
+
187
+ static VALUE rb_bst_size(VALUE self) {
188
+ bst_head *headNode;
189
+ Data_Get_Struct(self,bst_head,headNode);
190
+ return INT2FIX(headNode->size);
191
+ }
192
+
193
+ static VALUE mContainers;
194
+
195
+ void Init_CBst() {
196
+ id_compare_operator = rb_intern("<=>");
197
+ mContainers = rb_define_module("Containers");
198
+ VALUE cbst_class = rb_define_class_under(mContainers,"CBst",rb_cObject);
199
+ rb_define_alloc_func(cbst_class,bst_alloc);
200
+ rb_define_method(cbst_class,"initialize",bst_initialize,0);
201
+ rb_define_method(cbst_class,"insert",rb_bst_insert_value,2);
202
+ rb_define_method(cbst_class,"each", rb_bst_each,0);
203
+ rb_define_method(cbst_class,"delete",rb_bst_delete,1);
204
+ rb_define_method(cbst_class,"size",rb_bst_size,0);
205
+ }