Подумайте о том, чтобы построить дерево по-другому, построив его из листьев. Если у вас есть очередь узлов, вы можете взять два узла спереди, соединить их вместе с новым узлом и добавить этот новый узел в конец очереди. Повторяйте до тех пор, пока у вас не закончатся узлы, и у вас будет турнирная сетка с тем же числом раундов, которое вы получите при попытке построить дерево из корня.
Вот код, который строит дерево и заполняет листья именами из памятки.
var
Nodes: TQueue;
Node: PNode;
s: string;
begin
Nodes := TQueue.Create;
try
// Build initial queue of leaf nodes
for s in Memo1.Lines do begin
New(Node);
Node.Data := s;
Node.Left := nil;
Node.Right := nil;
Nodes.Push(Node);
end;
// Link all the nodes
while Nodes.Count > 1 do begin
New(Node);
Node.Left := Nodes.Pop;
Node.Right := Nodes.Pop;
Nodes.Push(Node);
end;
Assert((Nodes.Count = 1) or (Memo1.Lines.Count = 0));
if Nodes.Empty then
Tree := TTree.Create
else
Tree := TTree.Create(Nodes.Pop);
finally
Nodes.Free;
end;
end;
Что хорошо в этом коде, так это то, что мы ни в коем случае не знаем и не заботимся о том, на каком уровне должен находиться какой-либо конкретный узел.
Если число участников не является степенью двойки, то некоторые из участников в конце списка могут получить раунд "до свидания", и им будет назначено сыграть победителей в верхней части списка. , Код выше имеет минимальное количество узлов. В вашем коде может быть несколько «спамовых» узлов, которые не представляют никакого фактического совпадения в турнире.
Объект дерева должен владеть узлами, которые он содержит, поэтому у него должен быть деструктор, такой как:
destructor TTree.Destroy;
procedure FreeSubnodes(Node: PNode);
begin
if Assigned(Node.Left) then
FreeSubnodes(Node.Left);
if Assigned(Node.Right) then
FreeSubnodes(Node.Right);
Dispose(Node);
end;
begin
FreeSubnodes(Root);
inherited;
end;
Вы заметите, я тоже изменил, как называется конструктор дерева. Если дерево пустое, ему не нужно иметь никаких узлов. Если дерево не пустое, то мы создадим его узлами при его создании.
constructor TTree.Create(ARoot: PNode = nil);
begin
inherited;
Root := ARoot;
end;
Если у вас есть возможность скопировать дерево, то вам также необходимо скопировать все его узлы. Если этого не сделать, то при освобождении одного дерева указатель корневого узла копии внезапно станет недействительным.
constructor TTree.Copy(Other: TTree);
function CopyNode(Node: PNode): PNode;
begin
if Assigned(Node) then begin
New(Result);
Result.Data := Node.Data;
Result.Left := CopyNode(Node.Left);
Result.Right := CopyNode(Node.Right);
end else
Result := nil;
end;
begin
inherited;
Root := CopyNode(Other.Root);
end;