Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 04.07.2014, 02:49   #1
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,430
По умолчанию Обход дерева неизвестной глубины

Всем привет!

Есть некое бездонное нечто:
Код:
 Type
   TTreeItem = class;
   TTree = class(TTreeItem);
   TTreeItem = class(TObjectList<TTreeItem>)
   Container:Boolean;
   function FindByID(aWhat:string; out aObj:TTreeItem):Boolean;
    end;
Каждый TTreeItem явл. списком объектов TTreeItem которые явл. списками других объектов TTreeItem .... в общем что-то не имеющее конца и вложенности.

У объекта есть переключатель, переменная Container которая являт собой признак способности этого объекта содержать в себе другие объекты. Если True, TTreeItem имеет право хранить другие TTreItem.

Задача:
Мне нужно рекурсивно обойти это дерево и найти что-то, когда что-то найдено, вернуть это в переменную и прекратить поиск.

Для этого написал функцию FindByID:
Код:
function TTreeItem.FindByID(aWhat: string; var aObj: TTreeItem): Boolean;
var
  i: Integer;
begin
  Result := False;
  if (Id = aWhat) then //Проверяем себя..
  begin
    aOut := self;
    Result := True;
    Exit;
  end;
  If Container then
  begin
    for i := 0 to Count - 1 do 
    begin
      if Assigned(aOut) then //Если уже нашли, то прерываем эту рекурсию.
        Exit;
      if (Items[i].Id = aWhat) then
      begin
        aOut := Items[i];
        Result := True;
        Break;
      end
      else
      begin
        if Items[i].Container then
        begin
          if Items[i].FindByID(aWhat, aOut) then
            Break;
        end;
      end;
    end;
  end;
end;
Код тривиален в коментариях не сильно нуждается:
Проверяем себя,
Если контеинер, то цикл по внутренним элементам.
Если нашли элемент, то возврат его в переменную, и выход из функции.

Проблема в том, что код работает.
И под отладчиком я точно прихожу к моменту когда функция дает результат(возврат совпадения в переменную и выход), однако затем, на следующие X нажатий F8, отладчик скачет по предпоследнему end; и затем передает управление программе. В итоге алгоритм отработал вроде бы верно, но функция вернула False, и нужный код не отработал.

В чем ошибка?
Может есть более эффективный метод поиска в таких деревьях?

Последний раз редактировалось Человек_Борща; 04.07.2014 в 02:51.
Человек_Борща вне форума Ответить с цитированием
Старый 04.07.2014, 03:03   #2
BDA
МегаМодератор
СуперМодератор
 
Аватар для BDA
 
Регистрация: 09.11.2010
Сообщений: 7,322
По умолчанию

А так?
Код:
function TTreeItem.FindByID(aWhat: string; var aObj: TTreeItem): Boolean;
var
  i: Integer;
begin
  Result := False;
  if (Id = aWhat) then
  begin
    aOut := self;
    Result := True;
    Exit;
  end;
  If Container then
    for i := 0 to Count - 1 do 
    begin
      Result := Items[i].FindByID(aWhat, aOut);
      if Result then
        Exit;
    end;
end;
Кстати, если сработает if Items[i].FindByID(aWhat, aOut) then Break;, то значение Result так и останется false (если не ошибаюсь).
Пишите язык программирования - это форум программистов, а не экстрасенсов. (<= это подпись )

Последний раз редактировалось BDA; 04.07.2014 в 03:06.
BDA вне форума Ответить с цитированием
Старый 04.07.2014, 03:32   #3
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,430
По умолчанию

Работает. Чудно однако... из-за одного Break'а
Человек_Борща вне форума Ответить с цитированием
Старый 04.07.2014, 06:16   #4
Utkin
Старожил
 
Аватар для Utkin
 
Регистрация: 04.02.2009
Сообщений: 17,351
По умолчанию

Мне тоже Break не понравился....
Маньяк-самоучка
Utkin появился в результате деления на нуль.
Осторожно! Альтернативная логика
Utkin вне форума Ответить с цитированием
Старый 04.07.2014, 16:07   #5
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,799
По умолчанию

Угу, низ я бы записал так:
Код:
begin
  Result := Items[i].FindByID(aWhat, aOut);
  if Result then
    Break;
end;
Vapaamies вне форума Ответить с цитированием
Старый 04.07.2014, 16:10   #6
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,430
По умолчанию

Так оно с Break'ом не работает с Exit - все отлично.
Человек_Борща вне форума Ответить с цитированием
Старый 04.07.2014, 16:21   #7
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

А здесь без разницы. В исходном коде не работало потому, что Result забыли присвоить
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Чтение дерева неизвесной глубины из БД Человек_Борща БД в Delphi 4 03.06.2014 07:16
обход прошитого дерева fergus2010 Общие вопросы Delphi 6 23.01.2014 23:00
Обход дерева mohita C# (си шарп) 1 11.12.2011 19:48
Обход двоичного дерева F1nk Помощь студентам 0 03.06.2010 17:51
обход дерева ribka Помощь студентам 2 11.12.2007 20:38