Frage

So ive diese big-ass Sammlung richtig verstanden hat? Sein Baum-backed (RBTree), so look-ups sind schnell, und die Werte werden sortiert.

Say ive bekam Wert X. Ich kann X in meinem Baum in logn Zeit, cool nachzuschlagen. Aber ich möchte die Werte rechts von X in dem Baum als auch, bis einer von ihnen einen Test dosent erfüllen. Das heißt, alle Elemente erhalten, die> = X und

I könnte den Index X erhalten, i, erhalten dann den Wert bei i + 1, i + 2 .... bis val (i + z)> Y. Abgesehen davon, dass kostet logn z *. Wenn Sie über den Baum aufzuzählen, zu der Enumerator im Inneren des Baumes kostet nicht logn zum nächsten Element zu gehen - es folgt nur einen Zeiger in dem Baum.

So ist es eine Möglichkeit, von einem bestimmten Index zu starten aufzählt? So dass ich überspringen i Elemente nicht, bevor ich den Bereich Aufzählen von vorne beginnen kann ich will.

Sag mir, wenn Sie im verrückt denken.

War es hilfreich?

Lösung

Nun, wenn Sie die Elemente Ihrer Sammlung zu setzen, da sich selbst, und es Ihnen nichts ausmacht, sie vor dem Einsetzen Sortierung, können Sie sie mit einer verknüpften Liste Typ wickeln könnte. So stellen Sie sicher der Schlüssel für die verknüpfte Listenelement-Wrapper für jedes Element der Schlüssel des Elements verwendet als Schlüssel für den Baum sortieren. Dann wird eine Lookup würden Sie einen Ort in der verknüpften Liste, und man konnte es nur zu Fuß von dort aus.

Wenn Sie jedoch, dass es so nicht tun können, ist Ihre einzige Möglichkeit ist RBTree zu ändern, was eine wenig Arbeit in C erfordern würde, da es sich um eine native Erweiterung in Ruby. Die meisten der Stücke, die Sie brauchen, sind dort dict_lookup() bereits Sie den Knoten im Baum, die Sie benötigen, und rbtree_for_each() Ihnen zu zeigen, wie einen Iterator zu schreiben, ein Startknoten gegeben.

Sie müßten den folgenden Code hinzuzufügen, in dem RBTree Juwel rbtree.c:

*** rbtree.c.orig 2009-03-27 14:14:55.000000000 -0400
--- rbtree.c  2009-03-27 14:20:21.000000000 -0400
***************
*** 528,533 ****
--- 528,574 ----
      return EACH_NEXT;
  }

+ static VALUE
+ rbtree_each_starting_with_body(rbtree_each_arg_t* arg)
+ {
+     VALUE self = arg->self;
+     dict_t* dict = DICT(self);
+     dnode_t* node;
+     
+     ITER_LEV(self)++;
+     for (node = (dnode_t*) arg->arg;
+          node != NULL;
+          node = dict_next(dict, node)) {
+         
+         if (arg->func(node, NULL) == EACH_STOP)
+             break;
+     }
+     return self;
+ }
+ 
+ /*
+  * call-seq:
+  *   rbtree.each_starting_with(key) {|key, value| block} => rbtree
+  *
+  * Calls block once for each key in order, starting with the given key,
+  * passing the key and value as a two-element array parameters.
+  */
+ VALUE
+ rbtree_each_starting_with(VALUE self, VALUE key)
+ {
+     dnode_t* node = dict_lookup(DICT(self), TO_KEY(key));
+     rbtree_each_arg_t each_arg;
+     if (node == NULL) { return self; };
+     
+     RETURN_ENUMERATOR(self, 0, NULL);
+ 
+     each_arg.self = self;
+     each_arg.func = each_i;
+     each_arg.arg = node;
+     return rb_ensure(rbtree_each_starting_with_body, (VALUE)&each_arg,
+                      rbtree_each_ensure, self);
+ }
+ 
  /*
   * call-seq:
   *   rbtree.each {|key, value| block} => rbtree
***************
*** 1616,1621 ****
--- 1657,1663 ----
      rb_define_method(MultiRBTree, "length", rbtree_size, 0);

      rb_define_method(MultiRBTree, "each", rbtree_each, 0);
+     rb_define_method(MultiRBTree, "each_starting_with", rbtree_each_starting_with, 1);
      rb_define_method(MultiRBTree, "each_value", rbtree_each_value, 0);
      rb_define_method(MultiRBTree, "each_key", rbtree_each_key, 0);
      rb_define_method(MultiRBTree, "each_pair", rbtree_each_pair, 0);

Wenn Sie dann make im Quellverzeichnis des installierten rbtree gem ausführen, sollte es die Erweiterung Remake, und Sie können es als normal verwenden:

% irb
irb> require 'rubygems'
=> true
irb> require 'rbtree'
=> true
irb> x = RBTree[ 'a', 1, 'b', 2, 'c', 3, 'd', 4 ]
=> #<RBTree: {"a"=>1, "b"=>2, "c"=>3, "d"=>4}, default=nil, cmp_proc=nil>
irb> x.each { |k,v| p [k, v] }
["a", 1]
["b", 2]
["c", 3]
["d", 4]
=> #<RBTree: {"a"=>1, "b"=>2, "c"=>3, "d"=>4}, default=nil, cmp_proc=nil>
irb> x.each_starting_with('b') { |k,v| p [k, v] }
["b", 2]
["c", 3]
["d", 4]
=> #<RBTree: {"a"=>1, "b"=>2, "c"=>3, "d"=>4}, default=nil, cmp_proc=nil>

Denken Sie daran, dass Sie diese Änderung vorgenommen haben, und verteilen Sie die geänderte Juwel mit Ihren Änderungen. Oder, hey, legt sie href="http://rubyforge.org/projects/rbtree/" rel="nofollow noreferrer"> der gem Schöpfer auf Rubyforge , um

scroll top