algorithms 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }