二叉搜索树
特性
一颗二叉树,可以为空,若不为空则满足:1.非空左子树的所有值小于其根节点的值。2.非空右子树的所有值大于其根节点的值。3.左右子树都是二叉搜索树
二叉搜索树的查找效率最好是O(log_2 N),但最差情况下回退化为O(N)
二叉搜索的相关实现
准备工作
template<class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
//节点的构造函数
BSTreeNode(const K& key)
:_left(nullptr)
, _right(nullptr)
, _key(key)
{};
};
非递归:二叉搜索树的插入
从根开始比较,比根大则往右找。比根小则往左找。
最多找高度次,走到空代表该值不存在。
template<class K>
class BSTree
{
typedef BSTreeNode<K> Node;
public:
//二叉搜索树的插入
bool Insert(const K& val)
{
if (_root == nullptr)
{
_root= new Node(val);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (val > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else if (val < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else
{
//该搜索二叉树已经有这个值了 插入失败
return false;
}
}
//cur目前指向空 parent已到位需要链接一下
cur = new Node(val);
if (parent->_key < val) parent->_right = cur;
else parent->_left = cur;
return true;
}
//以下函数为了显示结果看写的代码对不对
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
std::cout << root->_key << " ";
_InOrder(root->_right);
}
private:
_root=nullptr;
};
注意:这里_InOder打印调用会出现问题。
BSTree<int> tree1;
//tree._InOder(tree._root);在函数外拿不到this指针。而且递归需要显示的传参数
这里需要封装一层
再创建一个成员函数InOrder()
class BSTree
{
public:
void InOrde()
{
_InOrder(_root);
}
};
测试代码
void Insert_test1()
{
BSTree<int> tree1;
int a[] = { 8,3,1,10,6,4,7,14,13 };
for (auto e : a)
{
tree1.Insert(e);
}
//tree1.InOrder(tree1._root); 因为InOrder()是成员函数
//但我在类外拿不到this指针需要在改进一下
tree1.InOrder();
}
非递归:二叉搜索树的删除
bool Erase(const K& key)
{
//这部分代码同上 不再重复写了
else
{//找到了 开始删除
//分情况 1、要删除的节点有左子树 2、有右子树 3、都有
if (cur->left == nullptr)
{
if (cur != _root)
{
if (parent->_left == cur) parent->_left = cur->_right;
else parent->_right = cur->_right;
}
else
{
_root = cur->_right;
}
delete cur;
}
else if (cur->right == nullptr)
{
if (cur != _root)
{
if (parent->_left == cur) parent->_left = cur->_left;
else parent->_right = cur->_left;
}
else
{
_root = cur->_left;
}
delete cur;
}
else
{
//采用替换法
//可以找左子树的最右值,也可以找右子树的最左值,这里采用后者
Node* parent_minNode = cur;
Node* minNode = cur->_right;
while (minNode->_left)
{
parent_minNode = minNode;
minNode = minNode->_left;
}
swap(cur->_key, minNode->_key);
//不确定这个最左值是不是还有右子树
parent_minNode->left=cur->right;//不准确
delete minNode;
}
//...
}
这样会有一种极端情况无法处理 删除根节点key=8
这里10就是最小的左子树,此时
parent_minNode->right=minNode->right
swap(cur->_key, minNode->_key);
if (minNode == parent_minNode->left)
{
parent_minNode->_left = minNode->_right;
}
else
{
parent_minNode->_right = minNode->_right;
}
delete minNode;
递归法插入:
class BSTree
{
//...
public:
bool InsertR(const K&key)
{
return _InsertR(_root,key);
}
private:
bool _InsertR(Node*&root,const K&key)
{
if (root == nullptr)
{
//开始插入
Node* cur = new Node(key);
root = cur;
return true;
}
if (key > root->_key)
{
return _InsertR(root->_right, key);
}
else if (key < root->_key)
{
return _InsertR(root->_left, key);
}
else
{
return false;
}
}
//...
}
递归法删除:
class BSTree
{
//...
pubilc:
bool EraseR(const K& key)
{
return _EraseR(_root,key);
}
private:
bool _EraseR(Node*&root,const K& key)
{
if (root == nullptr)
{
return false;
}
if (key > root->_key)
{
return _EraseR(root->_right, key);
}
else if (key < root->_key)
{
return _EraseR(root->_left, key);
}
else
{
//找到了
Node* cur = root;
if (root->_left == nullptr)
root = root->_right;
else if (root->_right == nullptr)
root = root->_left;
else
{
Node* minNode = cur->_right;
while (minNode->_left)
{
minNode = minNode->_left;
}
std::swap(minNode->_key, cur->_key);
return _EraseR(cur->_right, key);
}
delete cur;
return true;
}
}
//...
};
测试代码
void Insert_test1()
{
BSTree<int> tree1;
int a[] = { 8,3,1,10,6,4,7,14,13 };
for (auto e : a)
{
tree1.InsertR(e);
}
tree1.InOrder();
std::cout << std::endl;
tree1.EraseR(13);
tree1.InsertR(2);
tree1.InOrder();
}
二叉树的非递归遍历
二叉树的非递归前序遍历
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root)
{
vector<int>v;
stack<TreeNode*>st;
TreeNode*cur=root;
while(cur || !st.empty())
{
while(cur)
{
v.push_back(cur->val);
st.push(cur);
cur=cur->left;
}
//出来了表示左树全部遍历完毕,只剩右树
cur=st.top()->right;
st.pop();
}
return v;
}
};
二叉树的非递归中序遍历
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root)
{
vector<int>v;
stack<TreeNode*>st;
TreeNode*cur=root;
while(!st.empty()||cur)
{
while(cur)
{
st.push(cur);
cur=cur->left;
}
v.push_back(st.top()->val);
cur=st.top()->right;
st.pop();
}
return v;
}
};
题目
1. 根据前序遍历和中序遍历,是可以确定一棵树的结构,使用两个遍历结果确定树的结构, 其中有一个遍历结果必须要是中序遍历结果。