二叉搜索树(BST树)
来源:互联网 发布:unity3d中文版下载 编辑:程序博客网 时间:2024/05/29 03:12
一、简介
(1)二叉搜索树,又叫做二叉排序树,二叉查找树,有序二叉树
是指一棵空树或者具有下列性质的二叉树:
- 每个节点都有一个作为搜索依据的关键码(key),所有节点的关键码互不相同。
- 左子树上所有节点的关键码(key)都小于根节点的关键码(key)。
- 右子树上所有节点的关键码(key)都大于根节点的关键码(key)。
- 左右子树都是二叉搜索树。
(2)二叉搜索树中序遍历的结果就是一个升序序列;
(3)空树也是一个二叉搜索树;
既然有以上性质,那么二叉树的查找是相当方便的;当然插入和删除,复杂度也会明显降低。
二、代码实现
(1)二叉搜索树的查找
从根结点开始搜索
如果根结点的健值大于要寻找的key,则向根结左点子树寻找;
如果根结点的健值小于要寻找的健值,则向根结点的右子树寻找;
如果相等,则代表找到;
如果一直找到NULL也没有找到,则说明该健值没有在此二叉搜索树里面;
bool _Find(Node* root,const T& x)//查找---非递归 { //1.如果二叉搜索树为空,则返回错 if (root==NULL) { return false; } //2.二叉搜索树不为空 Node* cur=root; while (cur) { //2.1如果根结点的健值大于要寻找的key,则向根结点左子树寻找; if (cur->data>x) { cur=cur->left; } //2.2如果根结点的健值小于要寻找的健值,则向根结点的右子树寻找; else if (cur->data<x) { cur=cur->right; } //2.3如果相等,则代表找到; else { return true; } } //2.4如果一直找到NULL也没有找到,则说明该健值没有在此二叉搜索树里面; return false; }
(2)二叉搜索树的插入
首先说明,在二叉搜索树中,不能出现相同key值的两个结点;
二叉搜索树的插入是,先找到合适的空位置,然后进行插入;如果在寻找的过程中,发现了和要插入的值相同的结点;
那么就不用插入了,直接返回;
bool _InsertNoR(Node* root,const T& x)//给搜索二叉树插入某个元素--非递归 { //1.如果二叉搜索树为空,则直接插入节点 if (root==NULL) { root=new Node(x); _root=root; return true; } //2.二叉搜索树不为空 Node* cur=root;//遍历二叉搜索树 Node* father=NULL;//记录正确插入位置的父节点; //2.1寻找插入的正确位置,在此期间,如果遇到和插入节点相同的结点,则直接返回错误; while (cur) { if (cur->data==x) { return false; } else if (cur->data > x) { father=cur; cur=cur->left; } else { father=cur; cur=cur->right; } } //2.2寻找到正确的插入位置,然后进行插入操作; cur=new Node(x);//要插入的结点 //2.2.1如果父节点的值小于插入的值,则插入到父节点的右边 if ( x> father->data) { father->right=cur; } //2.2.2如果父节点的值大于插入的值,则插入到父节点的左边 else { father->left=cur; } return true; }
(3)二叉搜索树的删除
二插搜索树的删除比较麻烦,下面一一分析;
1>如果二叉搜索树为空,返回错;
2>如果要删除的结点没有在二叉搜索树中,则直接返回错误;
3>如果通过查找,发现要删除的结点是叶子节点,没有左右孩子,则直接将该节点删除;
4>如果通过查找发现要删除的结点只有一个孩子;
则
如果该要删除的结点是父节点的左孩子,就将该孩子连接到父节点的左边;
如果该要删除的结点是父节点的右孩子,就将该孩子连接到父节点的右边;
5>如果通过寻找发现该要删除的结点左右孩子都有;
那么首先:找到该节点的右子树的最小结点(或者也可以找到该节点的左子树的最大节点),该最小结点就是右子树的最左结点;
然后判断:该最小结点是否还有右子树,如果还有右子树,则还要判断改最小结点是其父节点的左孩子还是右孩子,如果是左孩子,则将该最小结点的右子树连接到其父节点的左边;如果是右孩子,则将该最小结点的右子树连接到其父节点的右边;
最后:将游离出来的最小节点和要删除的结点交换值,然后将最小节点释放;
注: 出现该最小结点是其父节点的右孩子的情况只有一种,那就是这个最小结点就是要删除的结点的右子树的根结点;
ool _RmoveNoR(Node* root,const T& x) //二叉搜索树的删除---非递归 { //1.二叉搜索树为空 if (root==NULL) { return false; } //2.二叉搜索树不为空 Node* cur=root; Node* father=NULL; //2.2寻找要删除的结点 while (cur) { //2.2.1x小于cur,往左子树寻找 if (cur->data>x) { father=cur; cur=cur->left; } //2.2.2 x大于cur,往右子树寻找 else if (cur->data<x) { father=cur; cur=cur->right; } //2.2.3找到结点,准备删除 else { //2.2.3.1删除的结点为叶子节点 if (cur->left==NULL&&cur->right==NULL) { //1)要删除的结点是父节点的左孩子 if (father->left==cur) { delete cur; cur=NULL; father->left=NULL; return true; } //1)要删除的结点时父节点的右孩子 if (father->right==cur) { delete cur; cur=NULL; father->right=NULL; return true; } } //2.2.3.2删除的结点只右右子树! if (cur->left==NULL&&cur->right) { //1)要删除的结点是父节点的左孩子 if (father->left==cur) { father->left=cur->right; delete cur; cur=NULL; return true; } //1)要删除的结点是父节点的右孩子 if(father->right==cur) { father->right=cur->right; delete cur; cur=NULL; return true; } } //2.2.3.3删除的结点只有左子树! if (cur->left&&cur->right==NULL) { //1)要删除的结点时父节点的左孩子 if (father->left==cur) { father->left=cur->left; delete cur; cur=NULL; return true; } //1)要删除的结点时父节点的右孩子 if (father->right==cur) { father->right=cur->left; delete cur; cur=NULL; return true; } } //2.2.3.4删除的结点左右子树都有 if (cur->left&&cur->right) { //首先先找到以该节点为根的右子树的最小结点,就是右子树中序遍历的第一个结点,就是右子树的最左结点 //然后将此节点替换要删除的结点; Node* min=cur->right; Node* father1=cur; while (min->left) { father1=min; min=min->left; } if (min->right&&father1->left==min) { father1->left=min->right; } if (min->right&&father1->right==min) { father1->right=min->right; } std::swap(cur->data,min->data); delete min; min=NULL; return true; } } } //2.3该节点没在二叉搜索树里面 return false; }
三、二叉搜索树的退化及缺陷
二插搜索树的查找,插入和删除在一般情况下的时间复杂度都是O(H)【H为二叉树的高度】;
但是在插入有序数列或者接近有序的数列之后,查找和删除的时间复杂度是O(N);这和链表的顺序表的查找效率一样;删除效率和链表一样;体现不出二叉树每次排除一般的优势;
所以就出现了高度平衡的二叉搜索树AVL; 【明天写】
四、完整代码
#include<iostream>using namespace std;template<class T>struct TreeNode{ T data; TreeNode<T>* left; TreeNode<T>* right; TreeNode(const T& x) :data(x) ,left(NULL) ,right(NULL) {}};template<class T>class SearchBinaryTree{ typedef TreeNode<T> Node;public: SearchBinaryTree()//构造 :_root(NULL) {} ~SearchBinaryTree()//析构 { _Destroy(_root); } bool Find(const T& x)//寻找 { return _Find(_root,x); } bool InsertNoR(const T& x)//插入---非递归 { return _InsertNoR(_root,x); } bool RmoveNoR(const T& x)//删除---非递归 { return _RmoveNoR(_root,x); } void Printf()//前序打印搜索二叉树 { _Printf(_root); }protected: void _Destroy(Node* root)//销毁搜索二叉树 { if (root==NULL) { return ; } _Destroy(root->left); _Destroy(root->right); delete root; } void _Printf(Node* root) { if (root==NULL) { return ; } cout<<root->data<<" "; _Printf(root->left); _Printf(root->right); } bool _Find(Node* root,const T& x)//查找---非递归 { //1.如果二叉搜索树为空,则返回错 if (root==NULL) { return false; } //2.二叉搜索树不为空 Node* cur=root; while (cur) { //2.1如果根结点的健值大于要寻找的key,则向根结点左子树寻找; if (cur->data>x) { cur=cur->left; } //2.2如果根结点的健值小于要寻找的健值,则向根结点的右子树寻找; else if (cur->data<x) { cur=cur->right; } //2.3如果相等,则代表找到; else { return true; } } //2.4如果一直找到NULL也没有找到,则说明该健值没有在此二叉搜索树里面; return false; } bool _InsertNoR(Node* root,const T& x)//给搜索二叉树插入某个元素--非递归 { //1.如果二叉搜索树为空,则直接插入节点 if (root==NULL) { root=new Node(x); _root=root; return true; } //2.二叉搜索树不为空 Node* cur=root;//遍历二叉搜索树 Node* father=NULL;//记录正确插入位置的父节点; //2.1寻找插入的正确位置,在此期间,如果遇到和插入节点相同的结点,则直接返回错误; while (cur) { if (cur->data==x) { return false; } else if (cur->data > x) { father=cur; cur=cur->left; } else { father=cur; cur=cur->right; } } //2.2寻找到正确的插入位置,然后进行插入操作; cur=new Node(x);//要插入的结点 //2.2.1如果父节点的值小于插入的值,则插入到父节点的右边 if ( x> father->data) { father->right=cur; } //2.2.2如果父节点的值大于插入的值,则插入到父节点的左边 else { father->left=cur; } return true; } bool _RmoveNoR(Node* root,const T& x) //二叉搜索树的删除---非递归 { //1.二叉搜索树为空 if (root==NULL) { return false; } //2.二叉搜索树不为空 Node* cur=root; Node* father=NULL; //2.2寻找要删除的结点 while (cur) { //2.2.1x小于cur,往左子树寻找 if (cur->data>x) { father=cur; cur=cur->left; } //2.2.2 x大于cur,往右子树寻找 else if (cur->data<x) { father=cur; cur=cur->right; } //2.2.3找到结点,准备删除 else { //2.2.3.1删除的结点为叶子节点 if (cur->left==NULL&&cur->right==NULL) { //1)要删除的结点是父节点的左孩子 if (father->left==cur) { delete cur; cur=NULL; father->left=NULL; return true; } //1)要删除的结点时父节点的右孩子 if (father->right==cur) { delete cur; cur=NULL; father->right=NULL; return true; } } //2.2.3.2删除的结点只右右子树! if (cur->left==NULL&&cur->right) { //1)要删除的结点是父节点的左孩子 if (father->left==cur) { father->left=cur->right; delete cur; cur=NULL; return true; } //1)要删除的结点是父节点的右孩子 if(father->right==cur) { father->right=cur->right; delete cur; cur=NULL; return true; } } //2.2.3.3删除的结点只有左子树! if (cur->left&&cur->right==NULL) { //1)要删除的结点时父节点的左孩子 if (father->left==cur) { father->left=cur->left; delete cur; cur=NULL; return true; } //1)要删除的结点时父节点的右孩子 if (father->right==cur) { father->right=cur->left; delete cur; cur=NULL; return true; } } //2.2.3.4删除的结点左右子树都有 if (cur->left&&cur->right) { //首先先找到以该节点为根的右子树的最小结点,就是右子树中序遍历的第一个结点,就是右子树的最左结点 //然后将此节点替换要删除的结点; Node* min=cur->right; Node* father1=cur; while (min->left) { father1=min; min=min->left; } if (min->right&&father1->left==min) { father1->left=min->right; } if (min->right&&father1->right==min) { father1->right=min->right; } std::swap(cur->data,min->data); delete min; min=NULL; return true; } } } //2.3该节点没在二叉搜索树里面 return false; }protected: Node* _root;};int main(){ SearchBinaryTree<int> st; //插入 st.InsertR(7); st.InsertR(5); st.InsertR(4); st.InsertR(3); st.InsertR(6); st.InsertR(9); st.InsertR(15); st.InsertR(1); st.InsertR(8); st.InsertR(10); st.InsertR(12); st.Printf(); cout<<endl; //寻找 cout<<"寻找"<<endl; cout<<st.Find(7)<<endl; cout<<st.Find(5)<<endl; cout<<st.Find(4)<<endl; cout<<st.Find(3)<<endl; cout<<st.Find(6)<<endl; cout<<st.Find(9)<<endl; cout<<st.Find(15)<<endl; cout<<st.Find(1)<<endl; cout<<st.Find(8)<<endl; cout<<st.Find(10)<<endl; cout<<st.Find(12)<<endl; cout<<st.Find(13)<<endl; cout<<st.Find(14)<<endl; /*cout<<"删除"<<endl;*/ //删除 st.RmoveNoR(3); st.RmoveNoR(6); st.RmoveNoR(9); st.Printf(); return 0;}
END!!!
- BST 二叉搜索树
- 二叉搜索树BST
- 二叉搜索树BST
- 二叉搜索树(BST)
- BST-搜索二叉树
- BST二叉搜索树
- BST(二叉树搜索树)
- 二叉搜索树(BST树)
- *BST(二叉搜索树)
- 二叉搜索树(BST)
- BST二叉搜索树的实现
- 二叉搜索树(BST)的基本操作
- 二叉搜索树(BST)demo
- BST(二叉搜索树)按层遍历
- 二叉 搜索/查找 树、二叉排序树、BST
- BST 二叉搜索树 非指针版
- C++ BST(二叉搜索树)
- POJ 2309 BST(二叉搜索树)
- Redis单机多节点集群实验
- HDU 1724 Ellipse (自适应辛普森积分)
- MySQL的下载、安装、配置
- centos7 firewall 防火墙 命令
- 一起学android之如何获取手机程序列表以及程序相关信息并启动指定程序 (26)
- 二叉搜索树(BST树)
- 最小生成树手动模拟
- 萌新的linux之旅15
- ThinkPHP5 路由绑定
- mysql型锁机制总结
- 在多声卡的情况下使用修改注册表的方法设置默认声卡
- 如何关闭eclipse对js xml的验证?
- 【Leetcode】【python】Unique Binary Search Trees II
- 枚举声卡