多くの人がこれを間違えるのは驚くべきことです。
これは、単純なソリューションが拒否できないツリーの例です。
5
/ \
/ \
4 6
/ \ / \
1 7 1 7
すべての親がその子の間にあるため、ナイーブチェックのすべての呼び出しは成功します。しかし、それは明らかに整形式の二分探索木ではありません。
簡単な解決策は次のとおりです。
bool test(Tree* n,
int min=std::numeric_limits<int>::min(),
int max=std::numeric_limits<int>::max()) {
return !n || (
min < n->data && n->data < max
&& test(n->left, min, n->data)
&& test(n->right, n->data, max));
}
INT_MINもINT_MAXもツリーに存在しない必要があるため、これは完全ではありません。多くの場合、BSTノードは<ではなく<=で順序付けられ、その変更を行うと、2つではなく1つの値のみが予約されます。すべてを修正することは、演習として残されています。
これは、ナイーブテストがどのように間違っているかを示すデモンストレーションです。
#include <iostream>
#include <limits>
#define T new_tree
struct Tree{
Tree* left;
int data;
Tree* right;
};
Tree* T(int v) { return new Tree{0, v, 0}; }
Tree* T(Tree* l, int v, Tree* r) { return new Tree{l, v, r}; }
bool naive_test(Tree* n) {
return n == 0 || ((n->left == 0 || n->data > n->left->data)
&& (n->right == 0 || n->data < n->right->data)
&& naive_test(n->left) && naive_test(n->right));
}
bool test(Tree* n,
int min=std::numeric_limits<int>::min(),
int max=std::numeric_limits<int>::max()) {
return !n || (
min < n->data && n->data < max
&& test(n->left, min, n->data)
&& test(n->right, n->data, max));
}
const char* goodbad(bool b) { return b ? "good" : "bad"; }
int main(int argc, char**argv) {
auto t = T( T( T(1),4,T(7)), 5, T(T(1),6,T(7)));
std::cerr << "Naive test says " << goodbad(naive_test(t))
<< "; Test says " << goodbad(test(t)) << std::endl;
return 0;
}