纸上得来终觉浅,觉知此事要躬行
二叉搜索树的定义。
若它的左子树不为空,则左子树上所有节点的值均小于它的根节点的值。
若它的右字树不为空,则右子树上所有节点的值均大于它的根节点的值。
它的左、右子树也分别为二叉搜索树。
二叉搜索树是有序数,这就决定了二叉搜索树的递归遍历、迭代遍历和普通二叉树都不一样。
15、在二叉搜索树中寻找节点
leetcode700:
确定一个节点是否存在二叉搜索树中,如果在,则返回这个节点,如果不在,则返回null。
(1)、递归法
因为二叉搜索树的节点是有序的,所以可以有方向地搜索。如果root->val大于val,则搜索左子树,如果root->val小于val,则搜索右子树,如果没有找到目标节点,则返回null。
#include<iostream>
using namespace std;
typedef struct _tag_BitNode {
int data;
_tag_BitNode* left;
_tag_BitNode* right;
_tag_BitNode(int val) {
data = val;
left = nullptr;
right = nullptr;
}
}BitNode,*BitNodePtr;
BitNode* SearchBST(BitNode* root, int val) {
if (root == nullptr || root->data == val) {
return root;
}
if (root->data > val) {
return SearchBST(root->left, val);
}
if (root->data < val) {
return SearchBST(root->right, val);
}
return nullptr;
}
void main() {
BitNode node0(4), node1(2), node2(7);
BitNode node3(1), node4(3), node5(6), node6(8);
node0.left = &node1;
node0.right = &node2;
node1.left = &node3;
node1.right = &node4;
node2.left = &node5;
node2.right = &node6;
BitNode* ret = SearchBST(&node0, 3);
cout << "hell world" << endl;
}
(2)、迭代法
一提到二叉树遍历的迭代法,读者可能立刻想到使用栈模拟深度遍历,使用队列模拟广度遍历。但对于二叉搜索树就不一样了,基于二叉搜索树的特殊性,也就是节点的有序性,不适用辅助栈或者队列就可以写成迭代法。
对于一般二叉树,递归过程中还有回溯的过程。例如,遍历一个左方向的分支到头了,就需要调头,再遍历右分支。而对于二叉搜索树,不需要回溯的过程,基于节点的有序性就可以确定搜索方向。
BitNode* SearchBSTIter(BitNode* root,int val) {
while (root != nullptr) {
if (root->data > val) {
root = root->left;
}
else if (root->data < val) {
root = root->right;
}
else {
return root;
}
}
return nullptr;
}
本节介绍了二叉搜索树的遍历方式,基于二叉搜索树的特性,遍历的时候要比普票的二叉树简单得多,一些读者很容易忽略二叉搜索树的特性而写出很复杂的代码。所以针对二叉搜索树的题目,一定要利用其特性。
16、验证二叉搜索树
leetcode98:验证二叉搜索树
判断二叉树是不是二叉搜索树的条件如下:
(1)、若它的左子树不为空,则左子树上所有节点的值均小于它的根节点的值。
(2)、若它的右子树不为空,则右子树上所有节点的值均大于它的根节点的值。
(3)、它的左、右字树也分别为二叉搜索树。
采用中序遍历时,输出的二叉树搜索树节点的数值是有序序列。基于这个特性,验证二叉搜索树就相当于判断一个序列是不是递增的。
递归法:
可以采用中序遍历将二叉搜索树转变成一个数组,只要比较这个数组是不是有序的即可,如果数组是有序的,则是二叉搜索树。
class Solution {
private:
vector<int> vec;
void Inorder(BitNode* root) {
if (root == nullptr) {
return ;
}
Inorder(root->left);
vec.push_back(root->data);
Inorder(root->right);
}
public:
bool IsValidBST(BitNode* root) {
vec.clear();
Inorder(root);
for (int i = 1; i < vec.size(); i++) {
if (vec[i] < vec[i - 1]) {
return false;
}
}
return true;
}
};
迭代法:
bool IsValidBSF(BitNode* root) {
stack<BitNode*> st;
BitNode* cur = root;
BitNode* pre = nullptr;
while (cur != nullptr || !st.empty()) {
if (cur != nullptr) {
st.push(cur);
cur = cur->left;
}
else {
cur = st.top();
st.pop();
if (pre != nullptr && cur->data <= pre->data) {
return false;
}
pre = cur;
cur = cur->right;
}
}
return true;
}
17、二叉搜索树的最小绝对值
leetcode530:二叉搜索树中的最小绝对值
给出一颗树所有节点为非负值的二叉搜索树,请计算树中任意两个节点的差的绝对值的最小值。
(1)、递归法
注意是二叉搜索树,二叉搜素树是有序的。遇到二叉搜索树上求最值,求差值问题,就把它想象成在一个有序数组上求最值、求差值,这样就简单多了。
class Solution {
private:
vector<int> vec;
void TraverSal(BitNode* root) {
if (root == nullptr) {
return;
}
TraverSal(root->left);
vec.push_back(root->data);
TraverSal(root->right);
}
public:
int GetMinimumDifference(BitNode* root) {
vec.clear();
TraverSal(root);
if (vec.size() < 2) {
return 0;
}
int result = INT_MAX;
for (int i = 1; i < vec.size(); i++) {
result = min(result, (vec[i] - vec[i - 1]));
}
return result;
}
};
其实对二叉树进行中序遍历的过程中,我们可以直接找到相邻两个节点的差值:用一个pre节点记录cur节点的前一个节点。
class Solution {
private:
int result = INT_MAX;
BitNode* pre = nullptr;
void TraverSal(BitNode* cur) {
if (cur == nullptr) {
return;
}
TraverSal(cur->left);
if (pre != nullptr) {
result = min(result, cur->data - pre->data);
}
pre = cur;
TraverSal(cur->right);
}
public:
int GetMinimumDifference(BitNode* root) {
TraverSal(root);
return result;
}
};
迭代法:
下面给出一种中序遍历的迭代法
class Solution {
public:
int GetMinimumDifference(BitNode* root) {
stack<BitNode*> st;
BitNode* cur = root;
BitNode* pre = nullptr;
int result = INT_MAX;
while (cur != nullptr || !st.empty()) {
if (cur != nullptr) {
st.push(cur);
cur = cur->left;
}
else {
BitNode* node = st.top();
st.pop();
if (pre != nullptr) {
result = min(result, cur->data - pre->data);
}
pre = cur;
cur = cur->right;
}
}
return result;
}
};