Вопрос

Итак, у меня есть эта огромная коллекция, верно?Он основан на дереве (RBTree), поэтому поиск выполняется быстро, а значения сортируются.

Скажем, у меня есть значение X.Я могу найти X в своем дереве во время входа в систему, круто.Но мне также нужны значения справа от X в дереве, пока одно из них не перестанет соответствовать тесту.Т.е. получить все элементы >= X и <Y

я мог получить индекс X, i, затем получить значение в i+1, i+2....пока val(i+z) не станет > Y.Кроме того, что стоит з*логин.Если вы выполняете перечисление по дереву, перечислителю внутри дерева не требуется logn для перехода к следующему элементу — он просто следует за указателем в дереве.

Итак, есть ли способ начать перечисление с определенного индекса?Так что мне не нужно пропускать i элементов, прежде чем я смогу начать перечислять нужный диапазон.

Скажи мне, если считаешь меня сумасшедшим.

Это было полезно?

Решение

Что ж, если вы сами помещаете туда элементы своей коллекции и не против отсортировать их перед вставкой, вы можете обернуть их типом связанного списка.Просто убедитесь, что ключ для обертки подключенного элемента списка для каждого элемента использует ключ элемента в качестве ключа для сортировки деревьев.Тогда поиск даст вам местоположение в связанном списке, и вы сможете просто пройти по нему оттуда.

Однако, если вы не можете сделать это таким образом, ваш единственный выход — изменить RBTree, что потребует небольшой работы на C, поскольку это собственное расширение Ruby.Большинство необходимых вам деталей уже есть. dict_lookup() чтобы дать вам нужный узел в дереве, и rbtree_for_each() чтобы показать вам, как написать итератор по начальному узлу.

Вам нужно будет добавить следующий код в rbtree.c в геме 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);

Тогда, если вы запустите make в исходном каталоге установленного гема rbtree следует переделать расширение, и вы сможете использовать его как обычно:

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

Просто помните, что вы внесли это изменение, и распространяйте модифицированный драгоценный камень со своими изменениями.Или, эй, отправь их в создатель драгоценных камней в Rubyforge, чтобы каждый мог их воспользоваться.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top