Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Virtual Treeview указатель на узел по индексу


Автор: Napalmx 16.9.2009, 09:34
Собственно вопрос. Имеется VirtualStringTree заполненный узлами, как от него получить указатель на узел (PVIrtualNode)  зная индекс узла. Индекс узла вычисляется в теле программы. Заранее спасибо.

Автор: kami 16.9.2009, 12:12
имхо, только перебором.
Что-то типа

Код

function TForm1.GetNodebyIndex(index:integer):pVirtualNode;
var
  tmpNode:pVirtualNode;
begin
  Result:=nil;
  tmpNode:=vt.GetFirst;
  
  While Assigned(tmpNode) do
    begin
      if vt.AbsoluteIndex(tmpNode)=index then
        begin
          Result:=tmpNode;
          break;
        end;
      tmpNode:=vt.GetNext(tmpNode);
    end;
end;

Автор: Napalmx 16.9.2009, 15:59
Цитата(kami @ 16.9.2009,  12:12)
имхо, только перебором.

Этого как раз пытаюсь избежать... Узлов может быть достаточно большое количество. Список сортированный по определенному параметру, поэтому хочу организовать поиск делением пополам по этому же параметру. Для этого мне и нужно каждый раз получать узел-середину выбранного диапазона. Если искать узел перебором все плюсы данного алгоритма сходят на нет.

Автор: kami 17.9.2009, 00:58
Цитата(Napalmx @  16.9.2009,  15:59 Найти цитируемый пост)
Узлов может быть достаточно большое количество. 

Насколько большое?
на моей машине (AMD turion 64x2 1.9 ГГц) поиск по дереву из 11 100 элементов (4 уровня вложения) происходит максимум за 1 миллисекунду, чем ближе к началу - тем быстрее (не тики же считать smile  ).

Вот другой код, состряпанный сегодня на основе исходников VT (возможно, неоптимальный и некрасивый, но зато выполняется за 0 миллисекунд на том же дереве, разницу меньше 1мс считать просто лень).

Код

function TForm1.GetNodeByIndex(index: integer): pVirtualNode;
var
  tmpNode: pVirtualNode;
  tmpIndex: integer;
begin
  Result := nil;
  // проверяем, есть ли вообще такой элемент
  if (index > vt.AbsoluteIndex(vt.GetLast)) or (index < 0) then
    exit;

  // начинаем искать
  tmpIndex := 0;
  tmpNode := vt.GetFirst;

  while Assigned(tmpNode) and (tmpIndex <> index) do
    begin
      // пролистываем по элементам одного уровня, пока не перескочим за искомый индекс
      while Assigned(tmpNode) and (tmpIndex < index) do
        begin
          inc(tmpIndex, tmpNode.TotalCount);
          if tmpIndex <= index then
            tmpNode := tmpNode.NextSibling
        end;
      if (tmpIndex > index) then
        begin
          if Assigned(tmpNode) then
            tmpNode := tmpNode.LastChild; // чуть перескочили - берем последний дочерний узел
          while Assigned(tmpNode) do
            begin
          // отматываем назад
              dec(tmpIndex, tmpNode.TotalCount);
              if (tmpIndex > index) then
                tmpNode := tmpNode.PrevSibling
              else
                break;
            end;
        end;
    // и так до тех пор, пока не найдем узел с нужным индексом.
    end;
  Result := tmpNode;
end;

Автор: kami 17.9.2009, 07:05
Цитата(kami @  17.9.2009,  00:58 Найти цитируемый пост)
поиск по дереву из 11 100 элементов (4 уровня вложения) происходит максимум за 1 миллисекунду, чем ближе к началу - тем быстрее

мда... погорячился. С одним уровнем в 11 000 нодах поиск идет за 600-700 мс первым кодом и прежние 0 мс вторым...

Видимо, второй код оптимальнее для этой задачи.

Автор: Romikgy 17.9.2009, 09:15
имхо проще унаследовать данный виртуал , и при добавлении нового итема,
записывать индекс его и указатель на итем в отдельную структуру.....

Автор: Napalmx 18.9.2009, 07:42
Видимо так и придется перебирать... Просто я с компонентом работаю недавно, рассчитывал что есть какой-то метод или механизм для реализации этой задачи. Всем спасибо.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)