问题描述:
二叉搜索树迭代器
实现一个二叉搜索树迭代器。你将使用二叉搜索树的根节点初始化迭代器。
调用 next()
将返回二叉搜索树中的下一个最小的数。
示例:
BSTIterator iterator = new BSTIterator(root);
iterator.next(); // 返回 3
iterator.next(); // 返回 7
iterator.hasNext(); // 返回 true
iterator.next(); // 返回 9
iterator.hasNext(); // 返回 true
iterator.next(); // 返回 15
iterator.hasNext(); // 返回 true
iterator.next(); // 返回 20
iterator.hasNext(); // 返回 false
提示:
next()
和hasNext()
操作的时间复杂度是 O(1),并使用 O(h) 内存,其中 h 是树的高度。- 你可以假设
next()
调用总是有效的,也就是说,当调用next()
时,BST 中至少存在一个下一个最小的数。
基本思路:
next函数不就是一次inorder traversal中while的循环体吗?
has_next函数不就是while中的判断条件吗?
AC代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
// 这里你当然可以使用Morris遍历打造Threaded Binary Tree
// 但是你iterator总不能改变原来树的结构把,所以我还是使用了非递归形式的inorder traversal
class BSTIterator {
private:
TreeNode *p; // 指向当前BST的节点
stack<TreeNode *> s; // 非递归遍历所需要的栈
public:
BSTIterator(TreeNode* root) {
p = root;
}
/** @return the next smallest number */
int next() {
// 搜索最左边的节点
while (p) {
s.push(p);
p = p->left;
}
// 获得该节点的值
p = s.top();
s.pop();
int ret_val = p->val;
// 这里其实做了两件事
// 1. 如果是空的节点,阻止下一次的while(p)
// 2. 如果有右子树,就进入右子树
p = p->right;
// 返回结果
return ret_val;
}
/** @return whether we have a next smallest number */
bool hasNext() {
return p || !s.empty();
}
};
/**
* Your BSTIterator object will be instantiated and called as such:
* BSTIterator* obj = new BSTIterator(root);
* int param_1 = obj->next();
* bool param_2 = obj->hasNext();
*/
其他经验:
我算是有点懂了:
为了合并while,我们可能需要改变p的值。一个很显著的特点就是p到底进不进入右子树:
- 如果进右子树,只要简单地修改p的指向即可。
- 如果不进入右子树,那我们的栈就要一直pop。这时候我们可以通过把p赋为NULL,跳过最开头的while循环,直接进入后面的pop阶段。