W takich przypadkach często łatwiej jest myśleć wstecz, więc najpierw zastanów się, czego potrzebujesz. Z opisu opiszmy je:
- Rekurencja
- Ważność
- Liczba kompletnych węzłów
OK, to dość krótka lista, powinna być zarządzalna. Zacznijmy od pustej metody i dodam opis tego, co powinno się dziać.
valid_bst () {
}
Teraz ważność. Jak sprawdzasz ważność? Na czacie powiedziałeś, że drzewo jest ważne „jeśli ... wszystkie lewe dzieci są mniejsze niż rodzic, a prawe dzieci są większe niż rodzic”. Jestem pewien, że chciałeś również pozwolić na równość. To by było t.left.value <= t.value <= t.right.value
.
valid_bst () {
This node is valid if t.left.value <= t.value <= t.right.value
}
Ale co jeśli jedno z dzieci zaginie? Z tego, co powiedziałeś, uważam, że wiesz, że węzeł jest nadal ważny, jeśli brakuje jednego (lub obu). Dodajmy to, nieco restrukturyzując:
valid_bst () {
This node is valid to the left if
there is no left child or
it is no greater than the current node.
This node is valid to the right if
there is no right child or
it is no less than the current node.
This node is valid overall if it is valid to the left and right.
}
OK, teraz wiemy, czy ten węzeł jest prawidłowy. Jak sprawdzamy, czy całe drzewo jest prawidłowe? Nie ma go w tablicy, więc prawdopodobnie nie możemy / nie chcemy zapętlać go liniowo. Twoje zadanie daje odpowiedź: rekurencja. Ale w jaki sposób gromadzimy odpowiedź za pomocą rekurencji? Mamy dostęp do trzech informacji, czy ten węzeł jest prawidłowy, oraz wyników połączeń z pytaniem, czy lewy i prawy węzeł są prawidłowe. Oczywiście drzewo jest ważne tylko wtedy, gdy wszystkie trzy są prawdziwe.
valid_bst () {
This node is valid to the left if
there is no left child or
it is no greater than the current node.
This node is valid to the right if
there is no right child or
it is no less than the current node.
This node is valid overall if it is valid to the left and right.
Is the left child valid?
Is the right child valid?
This tree is only valid if this node and both its children are.
}
Jeśli zwracasz uwagę, to nawet mówi nam, co nasza funkcja musi zwrócić.
Jak teraz zintegrować liczenie? Mówisz, co się liczy („węzeł nadrzędny z lewym i prawym węzłem podrzędnym”) i nie powinno to być trudne do przetłumaczenia na rzeczywisty kod. Sprawdź, czy ten warunek jest spełniony, i odpowiednio zwiększ licznik. Pamiętaj tylko, że musi to być gdzieś, gdzie będzie to możliwe, za każdym razem, gdy będzie to prawdą.
I oczywiście pominąłem niektóre szczegóły, takie jak warunek zatrzymania rekurencji i sprawdzanie wartości zerowej.
<
definiowany jest operator porównania w węzłach?