algorithms 0.1.0 → 0.2.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/History.txt +8 -0
- data/Manifest +9 -14
- data/README.markdown +92 -0
- data/Rakefile +3 -2
- data/algorithms.gemspec +6 -6
- data/benchmarks/deque.rb +17 -0
- data/benchmarks/sorts.rb +3 -2
- data/benchmarks/treemaps.rb +36 -0
- data/ext/containers/deque/deque.c +18 -4
- data/ext/containers/{tree_map → rbtree_map}/extconf.rb +0 -0
- data/ext/containers/{tree_map → rbtree_map}/rbtree.c +42 -12
- data/ext/containers/{bst → splaytree_map}/extconf.rb +1 -1
- data/ext/containers/splaytree_map/splaytree.c +370 -0
- data/lib/algorithms.rb +6 -5
- data/lib/containers/deque.rb +5 -10
- data/lib/containers/splay_tree_map.rb +14 -19
- data/spec/deque_gc_mark_spec.rb +18 -0
- data/spec/heap_spec.rb +110 -103
- data/spec/kd_tree_spec.rb +1 -86
- data/spec/priority_queue_spec.rb +62 -62
- data/spec/rb_tree_map_gc_mark_spec.rb +25 -0
- data/spec/splay_tree_map_spec.rb +26 -26
- metadata +19 -25
- data/README +0 -90
- data/benchmark.rb +0 -51
- data/benchmarks/rbench.rb +0 -16
- data/benchmarks/rbench/column.rb +0 -26
- data/benchmarks/rbench/group.rb +0 -43
- data/benchmarks/rbench/report.rb +0 -53
- data/benchmarks/rbench/runner.rb +0 -109
- data/benchmarks/rbench/summary.rb +0 -51
- data/ext/containers/bst/bst.c +0 -205
- data/lib/graphs/graph.rb +0 -25
- data/spec/bst_spec.rb +0 -31
    
        data/benchmarks/rbench.rb
    DELETED
    
    | @@ -1,16 +0,0 @@ | |
| 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
         | 
    
        data/benchmarks/rbench/column.rb
    DELETED
    
    | @@ -1,26 +0,0 @@ | |
| 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
         | 
    
        data/benchmarks/rbench/group.rb
    DELETED
    
    | @@ -1,43 +0,0 @@ | |
| 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
         | 
    
        data/benchmarks/rbench/report.rb
    DELETED
    
    | @@ -1,53 +0,0 @@ | |
| 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
         | 
    
        data/benchmarks/rbench/runner.rb
    DELETED
    
    | @@ -1,109 +0,0 @@ | |
| 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
         | 
| @@ -1,51 +0,0 @@ | |
| 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
         | 
    
        data/ext/containers/bst/bst.c
    DELETED
    
    | @@ -1,205 +0,0 @@ | |
| 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 | 
            -
            }
         |