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.
@@ -1,3 +1,11 @@
1
+ === March 28, 2009
2
+
3
+ * Implemented SplayTree in C
4
+ * Made recursively_free_nodes methods static to fix a SEGFAULT
5
+ * Improved CBst
6
+ * Moved to Markdown for README
7
+ * 0.2.0 release
8
+
1
9
  === January 19, 2009
2
10
 
3
11
  * kd-tree for points in multi-dimensional space
data/Manifest CHANGED
@@ -1,18 +1,13 @@
1
1
  algorithms.gemspec
2
- benchmark.rb
3
- benchmarks/rbench/column.rb
4
- benchmarks/rbench/group.rb
5
- benchmarks/rbench/report.rb
6
- benchmarks/rbench/runner.rb
7
- benchmarks/rbench/summary.rb
8
- benchmarks/rbench.rb
2
+ benchmarks/deque.rb
9
3
  benchmarks/sorts.rb
10
- ext/containers/bst/bst.c
11
- ext/containers/bst/extconf.rb
4
+ benchmarks/treemaps.rb
12
5
  ext/containers/deque/deque.c
13
6
  ext/containers/deque/extconf.rb
14
- ext/containers/tree_map/extconf.rb
15
- ext/containers/tree_map/rbtree.c
7
+ ext/containers/rbtree_map/extconf.rb
8
+ ext/containers/rbtree_map/rbtree.c
9
+ ext/containers/splaytree_map/extconf.rb
10
+ ext/containers/splaytree_map/splaytree.c
16
11
  History.txt
17
12
  lib/algorithms/search.rb
18
13
  lib/algorithms/sort.rb
@@ -27,16 +22,16 @@ lib/containers/splay_tree_map.rb
27
22
  lib/containers/stack.rb
28
23
  lib/containers/suffix_array.rb
29
24
  lib/containers/trie.rb
30
- lib/graphs/graph.rb
31
25
  Manifest
32
26
  Rakefile
33
- README
34
- spec/bst_spec.rb
27
+ README.markdown
28
+ spec/deque_gc_mark_spec.rb
35
29
  spec/deque_spec.rb
36
30
  spec/heap_spec.rb
37
31
  spec/kd_tree_spec.rb
38
32
  spec/priority_queue_spec.rb
39
33
  spec/queue_spec.rb
34
+ spec/rb_tree_map_gc_mark_spec.rb
40
35
  spec/rb_tree_map_spec.rb
41
36
  spec/search_spec.rb
42
37
  spec/sort_spec.rb
@@ -0,0 +1,92 @@
1
+ # algorithms
2
+
3
+ * Official homes are here on github, and at [rubyforge](http://rubyforge.org/projects/algorithms/)
4
+ * Documentation: [http://algorithms.rubyforge.org/](http://algorithms.rubyforge.org/)
5
+
6
+ ## DESCRIPTION:
7
+
8
+ Started as a [Google Summer of Code 2008](http://code.google.com/soc/2008/ruby/about.html) project
9
+
10
+ Written by [Kanwei Li](http://kanwei.com/), mentored by Austin Ziegler
11
+
12
+ Original Proposal: Using the right data structure or algorithm for the situation is an important
13
+ aspect of programming. In computer science literature, many data structures
14
+ and algorithms have been researched and extensively documented. However, there
15
+ is still no standard library in Ruby implementing useful structures and
16
+ algorithms like Red/Black Trees, tries, different sorting algorithms, etc.
17
+ This project will create such a library with documentation on when to use a
18
+ particular structure/algorithm. It will also come with a benchmark suite to
19
+ compare performance in different situations.
20
+
21
+ ## FEATURES:
22
+
23
+ Done so far:
24
+
25
+ * Heaps Containers::Heap, Containers::MaxHeap, Containers::MinHeap
26
+ * Priority Queue Containers::PriorityQueue
27
+ * Deque Containers::Deque, Containers::CDeque (C extension), Containers::RubyDeque
28
+ * Stack Containers::Stack (uses Deque)
29
+ * Queue Containers::Queue (uses Deque)
30
+ * Red-Black Trees Containers::RBTreeMap, Containers::CRBTreeMap (C extension), Containers::RubyRBTreeMap
31
+ * Splay Trees Containers::SplayTreeMap, Containers::CSplayTreeMap (C extension), Containers::RubySplayTreeMap
32
+ * Tries Containers::Trie
33
+ * Suffix Array Containers::SuffixArray
34
+
35
+ * Search algorithms
36
+ - Binary Search Algorithms::Search.binary_search
37
+ - Knuth-Morris-Pratt Algorithms::Search.kmp_search
38
+ * Sort algorithms
39
+ - Bubble sort Algorithms::Sort.bubble_sort
40
+ - Comb sort Algorithms::Sort.comb_sort
41
+ - Selection sort Algorithms::Sort.selection_sort
42
+ - Heapsort Algorithms::Sort.heapsort
43
+ - Insertion sort Algorithms::Sort.insertion_sort
44
+ - Shell sort Algorithms::Sort.shell_sort
45
+ - Quicksort Algorithms::Sort.quicksort
46
+ - Mergesort Algorithms::Sort.mergesort
47
+
48
+ ## SYNOPSIS:
49
+
50
+ require 'rubygems'
51
+ require 'algorithms'
52
+
53
+ max_heap = Containers::MaxHeap.new
54
+
55
+ # To not have to type "Containers::" before each class, use:
56
+ include Containers
57
+ max_heap = MaxHeap.new
58
+
59
+
60
+ ## REQUIREMENTS:
61
+
62
+ * Ruby 1.8 compatible Ruby, or Ruby 1.9
63
+ * C compiler for C extensions (optional, but very much recommended for vast performance benefits)
64
+
65
+ ## INSTALL:
66
+
67
+ * sudo gem install algorithms
68
+
69
+ ## LICENSE:
70
+
71
+ (The MIT License)
72
+
73
+ Algorithms and Containers project is Copyright (c) 2009 Kanwei Li
74
+
75
+ Permission is hereby granted, free of charge, to any person obtaining
76
+ a copy of this software and associated documentation files (the
77
+ 'Software'), to deal in the Software without restriction, including
78
+ without limitation the rights to use, copy, modify, merge, publish,
79
+ distribute, sublicense, and/or sell copies of the Software, and to
80
+ permit persons to whom the Software is furnished to do so, subject to
81
+ the following conditions:
82
+
83
+ The above copyright notice and this permission notice shall be
84
+ included in all copies or substantial portions of the Software.
85
+
86
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
87
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
88
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
89
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
90
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
91
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
92
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ Echoe.new('algorithms') do |p|
6
6
  p.email = 'kanwei@gmail.com'
7
7
  p.summary = 'A library of algorithms and containers.'
8
8
  p.url = 'http://rubyforge.org/projects/algorithms/'
9
- p.version = "0.1.0"
9
+ p.version = "0.2.0"
10
10
  p.runtime_dependencies = []
11
11
  end
12
12
 
@@ -18,8 +18,9 @@ end
18
18
 
19
19
  task :push do
20
20
  sh "git push" # Rubyforge
21
- sh "git push gt" # Gitorious
21
+ sh "git push --tags" # Rubyforge
22
22
  sh "git push gh" # Github
23
+ sh "git push gh --tags" # Github
23
24
  end
24
25
 
25
26
  task :hanna do
@@ -2,19 +2,19 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{algorithms}
5
- s.version = "0.1.0"
5
+ s.version = "0.2.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Kanwei Li"]
9
- s.date = %q{2009-02-21}
9
+ s.date = %q{2009-03-29}
10
10
  s.description = %q{A library of algorithms and containers.}
11
11
  s.email = %q{kanwei@gmail.com}
12
- s.extensions = ["ext/containers/bst/extconf.rb", "ext/containers/deque/extconf.rb", "ext/containers/tree_map/extconf.rb"]
13
- s.extra_rdoc_files = ["ext/containers/bst/bst.c", "ext/containers/bst/extconf.rb", "ext/containers/deque/deque.c", "ext/containers/deque/extconf.rb", "ext/containers/tree_map/extconf.rb", "ext/containers/tree_map/rbtree.c", "lib/algorithms/search.rb", "lib/algorithms/sort.rb", "lib/algorithms.rb", "lib/containers/deque.rb", "lib/containers/heap.rb", "lib/containers/kd_tree.rb", "lib/containers/priority_queue.rb", "lib/containers/queue.rb", "lib/containers/rb_tree_map.rb", "lib/containers/splay_tree_map.rb", "lib/containers/stack.rb", "lib/containers/suffix_array.rb", "lib/containers/trie.rb", "lib/graphs/graph.rb", "README"]
14
- s.files = ["algorithms.gemspec", "benchmark.rb", "benchmarks/rbench/column.rb", "benchmarks/rbench/group.rb", "benchmarks/rbench/report.rb", "benchmarks/rbench/runner.rb", "benchmarks/rbench/summary.rb", "benchmarks/rbench.rb", "benchmarks/sorts.rb", "ext/containers/bst/bst.c", "ext/containers/bst/extconf.rb", "ext/containers/deque/deque.c", "ext/containers/deque/extconf.rb", "ext/containers/tree_map/extconf.rb", "ext/containers/tree_map/rbtree.c", "History.txt", "lib/algorithms/search.rb", "lib/algorithms/sort.rb", "lib/algorithms.rb", "lib/containers/deque.rb", "lib/containers/heap.rb", "lib/containers/kd_tree.rb", "lib/containers/priority_queue.rb", "lib/containers/queue.rb", "lib/containers/rb_tree_map.rb", "lib/containers/splay_tree_map.rb", "lib/containers/stack.rb", "lib/containers/suffix_array.rb", "lib/containers/trie.rb", "lib/graphs/graph.rb", "Manifest", "Rakefile", "README", "spec/bst_spec.rb", "spec/deque_spec.rb", "spec/heap_spec.rb", "spec/kd_tree_spec.rb", "spec/priority_queue_spec.rb", "spec/queue_spec.rb", "spec/rb_tree_map_spec.rb", "spec/search_spec.rb", "spec/sort_spec.rb", "spec/splay_tree_map_spec.rb", "spec/stack_spec.rb", "spec/suffix_array_spec.rb", "spec/trie_spec.rb"]
12
+ s.extensions = ["ext/containers/deque/extconf.rb", "ext/containers/rbtree_map/extconf.rb", "ext/containers/splaytree_map/extconf.rb"]
13
+ s.extra_rdoc_files = ["ext/containers/deque/deque.c", "ext/containers/deque/extconf.rb", "ext/containers/rbtree_map/extconf.rb", "ext/containers/rbtree_map/rbtree.c", "ext/containers/splaytree_map/extconf.rb", "ext/containers/splaytree_map/splaytree.c", "lib/algorithms/search.rb", "lib/algorithms/sort.rb", "lib/algorithms.rb", "lib/containers/deque.rb", "lib/containers/heap.rb", "lib/containers/kd_tree.rb", "lib/containers/priority_queue.rb", "lib/containers/queue.rb", "lib/containers/rb_tree_map.rb", "lib/containers/splay_tree_map.rb", "lib/containers/stack.rb", "lib/containers/suffix_array.rb", "lib/containers/trie.rb", "README.markdown"]
14
+ s.files = ["algorithms.gemspec", "benchmarks/deque.rb", "benchmarks/sorts.rb", "benchmarks/treemaps.rb", "ext/containers/deque/deque.c", "ext/containers/deque/extconf.rb", "ext/containers/rbtree_map/extconf.rb", "ext/containers/rbtree_map/rbtree.c", "ext/containers/splaytree_map/extconf.rb", "ext/containers/splaytree_map/splaytree.c", "History.txt", "lib/algorithms/search.rb", "lib/algorithms/sort.rb", "lib/algorithms.rb", "lib/containers/deque.rb", "lib/containers/heap.rb", "lib/containers/kd_tree.rb", "lib/containers/priority_queue.rb", "lib/containers/queue.rb", "lib/containers/rb_tree_map.rb", "lib/containers/splay_tree_map.rb", "lib/containers/stack.rb", "lib/containers/suffix_array.rb", "lib/containers/trie.rb", "Manifest", "Rakefile", "README.markdown", "spec/deque_gc_mark_spec.rb", "spec/deque_spec.rb", "spec/heap_spec.rb", "spec/kd_tree_spec.rb", "spec/priority_queue_spec.rb", "spec/queue_spec.rb", "spec/rb_tree_map_gc_mark_spec.rb", "spec/rb_tree_map_spec.rb", "spec/search_spec.rb", "spec/sort_spec.rb", "spec/splay_tree_map_spec.rb", "spec/stack_spec.rb", "spec/suffix_array_spec.rb", "spec/trie_spec.rb"]
15
15
  s.has_rdoc = true
16
16
  s.homepage = %q{http://rubyforge.org/projects/algorithms/}
17
- s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Algorithms", "--main", "README"]
17
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Algorithms", "--main", "README.markdown"]
18
18
  s.require_paths = ["lib", "ext"]
19
19
  s.rubyforge_project = %q{algorithms}
20
20
  s.rubygems_version = %q{1.3.1}
@@ -0,0 +1,17 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '../lib')
2
+ require 'algorithms'
3
+ include Algorithms
4
+
5
+ require 'rubygems'
6
+ require 'rbench'
7
+
8
+ RBench.run(2) do
9
+ %w(array deque).each { |s| self.send(:column, s.intern) }
10
+ deque = Containers::Deque.new
11
+ array = []
12
+
13
+ report "Insertion at end" do
14
+ array { 1000000.times { |x| array << x } }
15
+ deque { 1000000.times { |x| deque.push_back(x) } }
16
+ end
17
+ end
@@ -2,17 +2,18 @@ $: << File.join(File.expand_path(File.dirname(__FILE__)), '../lib')
2
2
  require 'algorithms'
3
3
  include Algorithms
4
4
 
5
+ require 'rubygems'
5
6
  require 'rbench'
6
7
 
7
8
  RBench.run(5) do
8
9
 
9
- sorts = %w(built_in comb_sort heapsort insertion_sort shell_sort quicksort mergesort)
10
+ sorts = %w(ruby comb_sort heapsort insertion_sort shell_sort quicksort mergesort)
10
11
  sorts.each { |sort| self.send(:column, sort.intern) }
11
12
 
12
13
  n = 1000
13
14
 
14
15
  proc = lambda { |scope, ary|
15
- scope.built_in { ary.dup.sort }
16
+ scope.ruby { ary.dup.sort }
16
17
  scope.comb_sort { Sort.comb_sort(ary.dup) }
17
18
  scope.heapsort { Sort.heapsort(ary.dup) }
18
19
  scope.insertion_sort { Sort.insertion_sort(ary.dup) }
@@ -0,0 +1,36 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '../lib')
2
+ require 'algorithms'
3
+ include Algorithms
4
+
5
+ require 'rubygems'
6
+ require 'rbench'
7
+
8
+ RBench.run(10) do
9
+ trees = %w(hash rbtree splaytree)
10
+ trees.each { |tree| self.send(:column, tree.intern) }
11
+
12
+ rbtree = Containers::RBTreeMap.new
13
+ splaytree = Containers::SplayTreeMap.new
14
+ hash = Hash.new
15
+
16
+ random_array = Array.new(10000) { |i| rand(i) }
17
+ num = 1000
18
+
19
+ report "Insertion" do
20
+ rbtree { random_array.each_with_index { |x,index| rbtree[index] = x } }
21
+ splaytree { random_array.each_with_index { |x,index| splaytree[index] = x } }
22
+ hash { random_array.each_with_index { |x,index| hash[index] = x } }
23
+ end
24
+
25
+ report "has_key?" do
26
+ rbtree { num.times { |n| rbtree.has_key?(n) } }
27
+ splaytree { num.times { |n| splaytree.has_key?(n) } }
28
+ hash { num.times { |n| hash.has_key?(n) } }
29
+ end
30
+
31
+ report "Lookup in sorted order" do
32
+ rbtree { rbtree.each { |k, v| k } }
33
+ splaytree { splaytree.each { |k, v| k } }
34
+ hash { hash.sort.each { |k, v| k } }
35
+ end
36
+ end
@@ -56,14 +56,28 @@ static deque_node* create_node(VALUE obj) {
56
56
  return node;
57
57
  }
58
58
 
59
- static void deque_free(deque *deque) {
60
- free_nodes(deque->front);
61
- free(deque);
59
+ static void deque_mark(void *ptr) {
60
+ if (ptr) {
61
+ deque *deque = ptr;
62
+ deque_node *node = deque->front;
63
+ while(node) {
64
+ rb_gc_mark(node->obj);
65
+ node = node->right;
66
+ }
67
+ }
68
+ }
69
+
70
+ static void deque_free(void *ptr) {
71
+ if (ptr) {
72
+ deque *deque = ptr;
73
+ free_nodes(deque->front);
74
+ free(deque);
75
+ }
62
76
  }
63
77
 
64
78
  static VALUE deque_alloc(VALUE klass) {
65
79
  deque *deque = create_deque();
66
- return Data_Wrap_Struct(klass, NULL, deque_free, deque);
80
+ return Data_Wrap_Struct(klass, deque_mark, deque_free, deque);
67
81
  }
68
82
 
69
83
  static VALUE deque_push_front(VALUE self, VALUE obj) {
@@ -22,7 +22,7 @@ typedef struct {
22
22
  rbtree_node *root;
23
23
  } rbtree;
24
24
 
25
- void recursively_free_nodes(rbtree_node *node) {
25
+ static void recursively_free_nodes(rbtree_node *node) {
26
26
  if(node) {
27
27
  recursively_free_nodes(node->left);
28
28
  recursively_free_nodes(node->right);
@@ -37,7 +37,7 @@ static rbtree* get_tree_from_self(VALUE self) {
37
37
  return tree;
38
38
  }
39
39
 
40
- int isred(rbtree_node *node) {
40
+ static int isred(rbtree_node *node) {
41
41
  if(!node) { return FALSE; }
42
42
 
43
43
  if(node->color == RED) { return TRUE; }
@@ -176,17 +176,17 @@ static VALUE get(rbtree *tree, rbtree_node *node, VALUE key) {
176
176
  }
177
177
 
178
178
  static VALUE min_key(rbtree_node *node) {
179
- if (!node->left)
180
- return node->key;
179
+ while (node->left)
180
+ node = node->left;
181
181
 
182
- return min_key(node->left);
182
+ return node->key;
183
183
  }
184
184
 
185
185
  static VALUE max_key(rbtree_node *node) {
186
- if (!node->right)
187
- return node->key;
186
+ while (node->right)
187
+ node = node->right;
188
188
 
189
- return max_key(node->right);
189
+ return node->key;
190
190
  }
191
191
 
192
192
  static rbtree_node* delete_min(rbtree_node *h, VALUE *deleted_value) {
@@ -285,6 +285,17 @@ static rbtree* rbt_each(rbtree *tree, void (*each)(rbtree *tree, rbtree_node *no
285
285
  static int id_compare_operator;
286
286
 
287
287
  static int rbtree_compare_function(VALUE a, VALUE b) {
288
+ if (a == b) return 0;
289
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
290
+ long x = FIX2LONG(a), y = FIX2LONG(b);
291
+ if (x == y) return 0;
292
+ if (x > y) return 1;
293
+ return -1;
294
+ }
295
+ if (TYPE(a) == T_STRING && RBASIC(a)->klass == rb_cString &&
296
+ TYPE(b) == T_STRING && RBASIC(b)->klass == rb_cString) {
297
+ return rb_str_cmp(a, b);
298
+ }
288
299
  return FIX2INT(rb_funcall((VALUE) a, id_compare_operator, 1, (VALUE) b));
289
300
  }
290
301
 
@@ -293,14 +304,33 @@ static VALUE rbtree_init(VALUE self)
293
304
  return self;
294
305
  }
295
306
 
296
- static void rbtree_free(rbtree *tree) {
297
- recursively_free_nodes(tree->root);
298
- free(tree);
307
+ static void recursively_mark_nodes(rbtree_node *node) {
308
+ if(node) {
309
+ rb_gc_mark(node->key);
310
+ rb_gc_mark(node->value);
311
+ recursively_mark_nodes(node->left);
312
+ recursively_mark_nodes(node->right);
313
+ }
314
+ }
315
+
316
+ static void rbtree_mark(void *ptr) {
317
+ if (ptr) {
318
+ rbtree *tree = ptr;
319
+ recursively_mark_nodes(tree->root);
320
+ }
321
+ }
322
+
323
+ static void rbtree_free(void *ptr) {
324
+ if (ptr) {
325
+ rbtree *tree = ptr;
326
+ recursively_free_nodes(tree->root);
327
+ free(tree);
328
+ }
299
329
  }
300
330
 
301
331
  static VALUE rbtree_alloc(VALUE klass) {
302
332
  rbtree *tree = create_rbtree(&rbtree_compare_function);
303
- return Data_Wrap_Struct(klass, NULL, rbtree_free, tree);
333
+ return Data_Wrap_Struct(klass, rbtree_mark, rbtree_free, tree);
304
334
  }
305
335
 
306
336
  static VALUE rbtree_push(VALUE self, VALUE key, VALUE value) {
@@ -1,4 +1,4 @@
1
1
  require 'mkmf'
2
- extension_name = "CBst"
2
+ extension_name = "CSplayTreeMap"
3
3
  dir_config(extension_name)
4
4
  create_makefile(extension_name)
@@ -0,0 +1,370 @@
1
+ #include "ruby.h"
2
+
3
+ typedef struct struct_splaytree_node {
4
+ VALUE key;
5
+ VALUE value;
6
+ struct struct_splaytree_node *left;
7
+ struct struct_splaytree_node *right;
8
+ } splaytree_node;
9
+
10
+ typedef struct {
11
+ int (*compare_function)(VALUE key1, VALUE key2);
12
+ int size;
13
+ splaytree_node *root;
14
+ splaytree_node *header;
15
+ } splaytree;
16
+
17
+ static void recursively_free_nodes(splaytree_node *node) {
18
+ if(node) {
19
+ recursively_free_nodes(node->left);
20
+ recursively_free_nodes(node->right);
21
+ free(node);
22
+ }
23
+ return;
24
+ }
25
+
26
+ static splaytree* get_tree_from_self(VALUE self) {
27
+ splaytree *tree;
28
+ Data_Get_Struct(self, splaytree, tree);
29
+ return tree;
30
+ }
31
+
32
+ static void splay(splaytree *tree, VALUE key) {
33
+ int cmp, cmp2;
34
+ splaytree_node *l, *r, *t, *y;
35
+
36
+ l = tree->header;
37
+ r = tree->header;
38
+ t = tree->root;
39
+
40
+ tree->header->left = NULL;
41
+ tree->header->right = NULL;
42
+
43
+ while(1) {
44
+ cmp = tree->compare_function(key, t->key);
45
+ if (cmp == -1) {
46
+ if (!(t->left)) break;
47
+ cmp2 = tree->compare_function(key, t->left->key);
48
+ if (cmp2 == -1) {
49
+ y = t->left;
50
+ t->left = y->right;
51
+ y->right = t;
52
+ t = y;
53
+ if (!(t->left)) break;
54
+ }
55
+ r->left = t;
56
+ r = t;
57
+ t = t->left;
58
+ }
59
+ else if (cmp == 1) {
60
+ if (!(t->right)) break;
61
+ cmp2 = tree->compare_function(key, t->right->key);
62
+ if (cmp2 == 1) {
63
+ y = t->right;
64
+ t->right = y->left;
65
+ y->left = t;
66
+ t = y;
67
+ if (!(t->right)) break;
68
+ }
69
+ l->right = t;
70
+ l = t;
71
+ t = t->right;
72
+ } else {
73
+ break;
74
+ }
75
+ }
76
+ l->right = t->left;
77
+ r->left = t->right;
78
+ t->left = tree->header->right;
79
+ t->right = tree->header->left;
80
+ tree->root = t;
81
+ }
82
+
83
+ static int height(splaytree_node *h) {
84
+ int left_height, right_height;
85
+
86
+ if(!h) { return 0; }
87
+
88
+ left_height = 1 + height(h->left);
89
+ right_height = 1 + height(h->right);
90
+
91
+ return left_height > right_height ? left_height : right_height;
92
+ }
93
+
94
+ static splaytree* create_splaytree(int (*compare_function)(VALUE, VALUE)) {
95
+ splaytree *tree = ALLOC(splaytree);
96
+ tree->compare_function = compare_function;
97
+ tree->root = NULL;
98
+ tree->size = 0;
99
+ tree->header = ALLOC(splaytree_node);
100
+ return tree;
101
+ }
102
+
103
+ static splaytree_node* create_node(VALUE key, VALUE value) {
104
+ splaytree_node *new_node = ALLOC(splaytree_node);
105
+ new_node->key = key;
106
+ new_node->value = value;
107
+ new_node->left = NULL;
108
+ new_node->right = NULL;
109
+ return new_node;
110
+ }
111
+
112
+ static void insert(splaytree *tree, VALUE key, VALUE value) {
113
+ int cmp;
114
+ splaytree_node *new_node;
115
+
116
+ if (!(tree->root)) {
117
+ new_node = create_node(key, value);
118
+ tree->root = new_node;
119
+ tree->size += 1;
120
+ return;
121
+ }
122
+
123
+ splay(tree, key);
124
+ cmp = tree->compare_function(key, tree->root->key);
125
+ if (cmp == 0) {
126
+ tree->root->value = value;
127
+ return;
128
+ } else {
129
+ new_node = create_node(key, value);
130
+ if (cmp == -1) {
131
+ new_node->left = tree->root->left;
132
+ new_node->right = tree->root;
133
+ tree->root->left = NULL;
134
+ } else { /* cmp == 1 */
135
+ new_node->right = tree->root->right;
136
+ new_node->left = tree->root;
137
+ tree->root->right = NULL;
138
+ }
139
+ tree->root = new_node;
140
+ tree->size += 1;
141
+ }
142
+ }
143
+
144
+ static VALUE get(splaytree *tree, VALUE key) {
145
+ int cmp;
146
+ if (!tree->root)
147
+ return Qnil;
148
+
149
+ splay(tree, key);
150
+ cmp = tree->compare_function(key, tree->root->key);
151
+ if (cmp == 0) {
152
+ return tree->root->value;
153
+ }
154
+ return Qnil;
155
+ }
156
+
157
+ static VALUE delete(splaytree *tree, VALUE key) {
158
+ int cmp;
159
+ splaytree_node *x, *deleted_root;
160
+ VALUE deleted;
161
+
162
+ splay(tree, key);
163
+ cmp = tree->compare_function(key, tree->root->key);
164
+ if (cmp == 0) {
165
+ deleted = tree->root->value;
166
+ deleted_root = tree->root;
167
+ if (!(tree->root->left)) {
168
+ tree->root = tree->root->right;
169
+ } else {
170
+ x = tree->root->right;
171
+ tree->root = tree->root->left;
172
+ splay(tree, key);
173
+ tree->root->right = x;
174
+ }
175
+ free(deleted_root);
176
+ tree->size -= 1;
177
+ return deleted;
178
+ }
179
+ return Qnil;
180
+ }
181
+
182
+ static splaytree* splaytree_each_node(splaytree *tree, splaytree_node *node, void (*each)(splaytree *tree_, splaytree_node *node_, void* args), void* arguments) {
183
+ if (!node)
184
+ return NULL;
185
+
186
+ if (node->left)
187
+ splaytree_each_node(tree, node->left, each, arguments);
188
+
189
+ (*each)(tree, node, arguments);
190
+
191
+ if (node->right)
192
+ splaytree_each_node(tree, node->right, each, arguments);
193
+ return tree;
194
+ }
195
+
196
+ static splaytree* splay_each(splaytree *tree, void (*each)(splaytree *tree, splaytree_node *node, void *args), void* arguments) {
197
+ if (tree->root)
198
+ splaytree_each_node(tree, tree->root, each, arguments);
199
+ return tree;
200
+ }
201
+
202
+ // Methods to be called in Ruby
203
+
204
+ static int id_compare_operator;
205
+
206
+ static int splaytree_compare_function(VALUE a, VALUE b) {
207
+ if (a == b) return 0;
208
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
209
+ long x = FIX2LONG(a), y = FIX2LONG(b);
210
+ if (x == y) return 0;
211
+ if (x > y) return 1;
212
+ return -1;
213
+ }
214
+ if (TYPE(a) == T_STRING && RBASIC(a)->klass == rb_cString &&
215
+ TYPE(b) == T_STRING && RBASIC(b)->klass == rb_cString) {
216
+ return rb_str_cmp(a, b);
217
+ }
218
+ return FIX2INT(rb_funcall((VALUE) a, id_compare_operator, 1, (VALUE) b));
219
+ }
220
+
221
+ static VALUE splaytree_init(VALUE self)
222
+ {
223
+ return self;
224
+ }
225
+
226
+ static void recursively_mark_nodes(splaytree_node *node) {
227
+ if(node) {
228
+ rb_gc_mark(node->key);
229
+ rb_gc_mark(node->value);
230
+ recursively_mark_nodes(node->left);
231
+ recursively_mark_nodes(node->right);
232
+ }
233
+ }
234
+
235
+ static void splaytree_mark(void *ptr) {
236
+ if (ptr) {
237
+ splaytree *tree = ptr;
238
+ recursively_mark_nodes(tree->root);
239
+ }
240
+ }
241
+
242
+ static void splaytree_free(void *ptr) {
243
+ if (ptr) {
244
+ splaytree *tree = ptr;
245
+ recursively_free_nodes(tree->root);
246
+ free(tree->header);
247
+ free(tree);
248
+ }
249
+ }
250
+
251
+ static VALUE splaytree_alloc(VALUE klass) {
252
+ splaytree *tree = create_splaytree(&splaytree_compare_function);
253
+ return Data_Wrap_Struct(klass, splaytree_mark, splaytree_free, tree);
254
+ }
255
+
256
+ static VALUE splaytree_push(VALUE self, VALUE key, VALUE value) {
257
+ splaytree *tree = get_tree_from_self(self);
258
+ insert(tree, key, value);
259
+ return value;
260
+ }
261
+
262
+ static VALUE splaytree_get(VALUE self, VALUE key) {
263
+ splaytree *tree = get_tree_from_self(self);
264
+ return get(tree, key);
265
+ }
266
+
267
+ static VALUE splaytree_size(VALUE self) {
268
+ splaytree *tree = get_tree_from_self(self);
269
+ return INT2NUM(tree->size);
270
+ }
271
+
272
+ static VALUE splaytree_is_empty(VALUE self) {
273
+ splaytree *tree = get_tree_from_self(self);
274
+ return (tree->root ? Qfalse : Qtrue);
275
+ }
276
+
277
+ static VALUE splaytree_height(VALUE self) {
278
+ splaytree *tree = get_tree_from_self(self);
279
+ return INT2NUM(height(tree->root));
280
+ }
281
+
282
+ static VALUE splaytree_has_key(VALUE self, VALUE key) {
283
+ splaytree *tree = get_tree_from_self(self);
284
+ if(!tree->root) { return Qfalse; }
285
+ if(get(tree, key) == Qnil)
286
+ return Qfalse;
287
+
288
+ return Qtrue;
289
+ }
290
+
291
+ static VALUE splaytree_min_key(VALUE self) {
292
+ splaytree *tree = get_tree_from_self(self);
293
+ splaytree_node *node;
294
+
295
+ if(!tree->root)
296
+ return Qnil;
297
+
298
+ node = tree->root;
299
+ while (node->left)
300
+ node = node->left;
301
+
302
+ return node->key;
303
+ }
304
+
305
+ static VALUE splaytree_max_key(VALUE self) {
306
+ splaytree *tree = get_tree_from_self(self);
307
+ splaytree_node *node;
308
+
309
+ if(!tree->root)
310
+ return Qnil;
311
+
312
+ node = tree->root;
313
+ while (node->right)
314
+ node = node->right;
315
+
316
+ return node->key;
317
+ }
318
+
319
+ static VALUE splaytree_delete(VALUE self, VALUE key) {
320
+ splaytree *tree = get_tree_from_self(self);
321
+ if(!tree->root)
322
+ return Qnil;
323
+
324
+ return delete(tree, key);
325
+ }
326
+
327
+ static VALUE splaytree_clear(VALUE self) {
328
+ splaytree *tree = get_tree_from_self(self);
329
+ recursively_free_nodes(tree->root);
330
+ tree->root = NULL;
331
+ tree->size = 0;
332
+
333
+ return Qnil;
334
+ }
335
+
336
+ static void splaytree_each_helper(splaytree *tree, splaytree_node *node, void *args) {
337
+ rb_yield(rb_ary_new3(2, node->key, node->value));
338
+ };
339
+
340
+ static VALUE splaytree_each(VALUE self) {
341
+ splaytree *tree = get_tree_from_self(self);
342
+ splay_each(tree, &splaytree_each_helper, NULL);
343
+ return self;
344
+ }
345
+
346
+ static VALUE CSplayTree;
347
+ static VALUE mContainers;
348
+
349
+ void Init_CSplayTreeMap() {
350
+ id_compare_operator = rb_intern("<=>");
351
+
352
+ mContainers = rb_define_module("Containers");
353
+ CSplayTree = rb_define_class_under(mContainers, "CSplayTreeMap", rb_cObject);
354
+ rb_define_alloc_func(CSplayTree, splaytree_alloc);
355
+ rb_define_method(CSplayTree, "initialize", splaytree_init, 0);
356
+ rb_define_method(CSplayTree, "push", splaytree_push, 2);
357
+ rb_define_method(CSplayTree, "clear", splaytree_clear, 0);
358
+ rb_define_alias(CSplayTree, "[]=", "push");
359
+ rb_define_method(CSplayTree, "size", splaytree_size, 0);
360
+ rb_define_method(CSplayTree, "empty?", splaytree_is_empty, 0);
361
+ rb_define_method(CSplayTree, "height", splaytree_height, 0);
362
+ rb_define_method(CSplayTree, "min_key", splaytree_min_key, 0);
363
+ rb_define_method(CSplayTree, "max_key", splaytree_max_key, 0);
364
+ rb_define_method(CSplayTree, "each", splaytree_each, 0);
365
+ rb_define_method(CSplayTree, "get", splaytree_get, 1);
366
+ rb_define_alias(CSplayTree, "[]", "get");
367
+ rb_define_method(CSplayTree, "has_key?", splaytree_has_key, 1);
368
+ rb_define_method(CSplayTree, "delete", splaytree_delete, 1);
369
+ rb_include_module(CSplayTree, rb_eval_string("Enumerable"));
370
+ }