Question

Ive a obtenu cette collection grand-cul droit? Son soutenu arbre (RBTree), alors regardez-ups sont rapides, et les valeurs sont triées.

Dis Ive a obtenu la valeur X. Je peux regarder X dans mon arbre dans le temps de logn, cool. Mais je veux que les valeurs à droite de X dans l'arbre et, jusqu'à ce que l'un d'eux dosent à une épreuve. À savoir, obtenir tous les éléments qui sont> = X et

peut obtenir l'indice de X, i, puis obtenir la valeur à i + 1, i + 2 .... jusqu'à ce que val (i + z) est> Y. Sauf que les coûts z * logn. Si vous énumérez sur l'arbre, le recenseur intérieur de l'arbre ne coûte pas logn pour passer à l'élément suivant - il suit juste un pointeur dans l'arbre.

Alors, est-il un moyen de commencer à partir d'un indice énumération spécifique? Telle que je ne dois sauter sur i éléments avant que je puisse commencer à énumérer sur la plage que je veux.

Dites-moi si vous pensez im fou.

Était-ce utile?

La solution

Eh bien, si vous mettez les éléments de votre collection là-bas vous-même, et ne vous dérange pas de les trier avant l'insertion, vous pouvez les envelopper avec un type de liste chaînée. Assurez-vous que la clé pour l'emballage de l'élément de liste chaînée pour chaque élément utilise la clé de l'élément comme clé pour le genre d'arbre. Ensuite, une recherche vous obtiendrait un emplacement dans la liste chaînée, et vous pourriez juste marcher à partir de là.

Cependant, si vous ne pouvez pas le faire de cette façon, votre seul recours est de modifier RBTree, ce qui nécessiterait un peu de travail en C, car il est une extension native de rubis. La plupart des morceaux que vous avez besoin sont là dict_lookup() déjà pour vous donner le nœud de l'arbre dont vous avez besoin, et rbtree_for_each() pour vous montrer comment écrire un itérateur, étant donné un noeud de départ.

Il faudrait ajouter le code suivant à rbtree.c dans la gemme RBTree:

*** 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);

Ensuite, si vous exécutez make dans le répertoire source de la gemme rbtree installé, il doit refaire l'extension, et vous pouvez l'utiliser comme normal:

% 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>

Rappelez-vous juste que vous avez fait ce changement, et diffusez la gemme modifiée avec vos modifications. Ou, hey, les soumettre à le créateur de bijou sur Rubyforge, afin que chacun puisse en tirer profit.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top