我将为这个问题编写完整的实现,以便于证明我对所花费时间的论点。
.
假设BST的每个节点都具有如下结构:
typedef struct node{
int vale;
struct node* left;
struct node* right;
}node;
该算法将有 2 个步骤:
a. 从树的根节点开始,找到起始节点和该节点的所有祖先。将所有这些存储在传递的堆栈中:
//root -> root node of the tree.
//val -> value of the node to find.
// s -> stack to store all ancestor.
node* find_node(node* root, int val,std::stack<node*> &s)
{
if(root != NULL) s.push(root);
if(root == NULL || root->value == val) return root;
if(root->value > val) return find_node(root->left);
else return find_node(root->right);
}
并且对该方法的调用如下所示:
//Assuming that the root is the root node of the tree.
std::stack<node*> s;
node* ptr = find_node(root,s); // we have all ancestors of ptr along with ptr in stack s now.
b. 现在我们必须打印树的下一个直接大于(大于 ptr)的元素。我们将从节点(即ptr)开始:
// s -> stack of all ancestor of the node.
// k -> k-successor to find.
void print_k_bigger(stack<node*> s, int k)
{
//since the top element of stack is the starting node. So we won't print it.
// We will just pop the first node and perform inorder traversal on its right child.
prev = s.top();
s.pop();
inorder(prev->right,k);
// Now all the nodes present in the stack are ancestor of the node.
while(!s.empty() && k>0)
{
//pop the node at the top of stack.
ptr = s.top();
s.pop();
//if the node popped previously (prev) was the right child of the current
//node, i.e. prev was bigger than the current node. So we will have to go
//one more level up to search for successors.
if(prev == ptr->right) continue;
//else the current node is immidiate bigger than prev node. Print it.
printf("%d",ptr->value);
//reduce the count.
k--;
//inorder the right subtree of the current node.
inorder(ptr->right);
//Note this.
prev = ptr;
}
}
这是我们的 inorder 的样子:
void inorder(node* ptr, int& k)
{
if(ptr != NULL)
{
inorder(ptr->left,k);
printf("%d",ptr->value);
k--;
inorder(ptr->right,k);
}
}
时间分析:
-
find_node 方法是 O(h),因为它可以达到最大根到叶路径的长度。
-
print_k_bigger 方法是 O(h+k),因为在循环的每次迭代中,堆栈的大小都在减小,或者 k 的值是减少。请注意,当从 while 循环内部调用 inorder() 时,它不会增加额外的开销,因为对 inorder() 的所有调用一起将占用最大值 O(k)。