Два двоичных дерева поиска (BST) не могут быть объединены непосредственно во время рекурсивного обхода.Предположим, мы должны объединить дерево 1 и дерево 2, показанные на рисунке.
Рекурсия должна уменьшить объединение до более простой ситуации.Мы не можем уменьшить объединение только до соответствующих левых поддеревьев L1 и L2, потому что L2 может содержать числа больше 10, поэтому нам нужно будет включить в процесс правое поддерево R1.Но затем мы включаем числа больше 10 и, возможно, больше 20, поэтому нам нужно будет также включить правильное поддерево R2.Подобные рассуждения показывают, что мы не можем упростить объединение, включив поддеревья из дерева 1 и дерева 2 одновременно.
Единственная возможность сокращения - это упрощение только внутри соответствующих деревьев.Таким образом, мы можем преобразовать деревья в их правильные колючки с отсортированными узлами:
Теперь мы можем легко объединить два колючки в один.Этот позвоночник на самом деле BST, поэтому мы могли бы остановиться здесь.Однако этот BST полностью несбалансирован, поэтому мы преобразуем его в сбалансированный BST.
Сложность:
Spine 1: time = O(n1), space = O(1)
Spine 2: time = O(n2), space = O(1)
Merge: time = O(n1+n2), space = O(1)
Balance: time = O(n1+n2), space = O(1)
Total: time = O(n1+n2), space = O(1)
Полный рабочий код находится на http://ideone.com/RGBFQ. Вотосновные части.Код верхнего уровня:
Node* merge(Node* n1, Node* n2) {
Node *prev, *head1, *head2;
prev = head1 = 0; spine(n1, prev, head1);
prev = head2 = 0; spine(n2, prev, head2);
return balance(mergeSpines(head1, head2));
}
Вспомогательные функции для преобразования в шипы:
void spine(Node *p, Node *& prev, Node *& head) {
if (!p) return;
spine(p->left, prev, head);
if (prev) prev->right = p;
else head = p;
prev = p;
p->left = 0;
spine(p->right, prev, head);
}
Слияние шипов:
void advance(Node*& last, Node*& n) {
last->right = n;
last = n;
n = n->right;
}
Node* mergeSpines(Node* n1, Node* n2) {
Node head;
Node* last = &head;
while (n1 || n2) {
if (!n1) advance(last, n2);
else if (!n2) advance(last, n1);
else if (n1->info < n2->info) advance(last, n1);
else if (n1->info > n2->info) advance(last, n2);
else {
advance(last, n1);
printf("Duplicate key skipped %d \n", n2->info);
n2 = n2->right;
}
}
return head.right;
}
Балансировка:
Node* balance(Node *& list, int start, int end) {
if (start > end) return NULL;
int mid = start + (end - start) / 2;
Node *leftChild = balance(list, start, mid-1);
Node *parent = list;
parent->left = leftChild;
list = list->right;
parent->right = balance(list, mid+1, end);
return parent;
}
Node* balance(Node *head) {
int size = 0;
for (Node* n = head; n; n = n->right) ++size;
return balance(head, 0, size-1);
}