概念:
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树),二叉搜索树是一种特殊的二叉树
二叉搜索树的性质:
1. 每个节点都有一个作为搜索依据的关键码(key),所有节点的关键码互不相同。
2. 左子树上所有节点的关键码(key)都小于根节点的关键码(key)。
3. 右子树上所有节点的关键码(key)都大于根节点的关键码(key)。
4. 左右子树都是二叉搜索树。
根据二叉搜索树的性质知:对二叉搜索树进行中序遍历得到的结点序列必然是一个有序序列。
代码:(代码中间包含了对基本功能(插入,删除,查找)的递归和非递归的实现)
- <span style="font-size:18px;">include <iostream>
- #include <string>
- using namespace std;
- template<class K,class V>
- struct BSTreeNode
- {
- K _data; //值
- V _freq; //出现的频率
- BSTreeNode<K, V>* _left; //指向左子树的指针
- BSTreeNode<K, V>* _right; //指向右子树的指针
- BSTreeNode(const K& data, const V& freq)//初始化
- :_data(data)
- , _freq(freq)
- , _left(NULL)
- , _right(NULL)
- {}
- };
- template<class K, class V>
- struct BSTree
- {
- typedef BSTreeNode<K, V> Node;
- public:
- BSTree()//初始化
- :_root(NULL)
- {}
- //插入
- bool Insert(const K& data, const V& freq)
- {
- if (_root == NULL)//如果节点为空,就在此节点处加入data数据
- {
- _root = new Node(data, freq);
- return true;
- }
- Node* parent = NULL;
- Node* cur = _root;
- while (cur)//搜索data应该插入的节点:parent节点后
- {
- if (data > cur->_data)//如果data大于节点的值,就继续在节点的右子树中插入data
- {
- parent = cur;
- cur = cur->_right;
- }
- else if (data < cur->_data)//如果data小于节点的值,就继续在节点的左子树中插入data
- {
- parent = cur;
- cur = cur->_left;
- }
- else
- {
- cur->_freq++;
- return true;
- }
- }
- //在parent节点后插入data
- if (data > parent->_data)
- {
- parent->_right = new Node(data, freq);
- }
- else
- {
- parent->_left = new Node(data, freq);
- }
- return true;
- }
- Node* Find(const K& data)//查找
- {
- Node* cur = _root;
- while (cur)
- {
- if (data >cur->_data)//若data大于当前节点,则在当前节点的右子树中查找
- {
- cur = cur->_right;
- }
- else if (data < cur->_data)//若data小于当前节点,则在当前节点的左子树中查找
- {
- cur = cur->_left;
- }
- else
- {
- return cur;
- }
- }
- return NULL;
- }
- bool Remove(const K& data)//删除
- {
- Node* parent = NULL;
- Node* cur = _root;
- while (cur)//寻找data节点cur
- {
- if (data > cur->_data)
- {
- parent = cur;
- cur = cur->_right;
- }
- else if (data < cur->_data)
- {
- parent = cur;
- cur = cur->_left;
- }
- else//要么cur==NULL退出了循环,要么data==cur->_databreak
- {
- break;
- }
- }
- if (cur == NULL)
- {
- return false;
- }
- //1.左为空,或者右为空
- //2.左右都不为空
- if (cur->_left == NULL)
- {//cur的左为空
- if (parent == NULL)//删除的是根节点
- {
- _root = cur->_right;
- }
- else
- {
- if (parent->_left == cur)
- {
- parent->_left = cur->_right;
- }
- else
- {
- parent->_right = cur->_right;
- }
- }
- delete cur;
- }
- else if (cur->_right == NULL)
- {//cur的右为空
- if (parent == NULL)
- {
- _root = cur->_right;
- }
- else
- {
- if (parent->_left == cur)
- {
- parent->_left = cur->_left;
- }
- else
- {
- parent->_right = cur->_left;
- }
- }
- delete cur;
- }
- else
- {//左不为空,右也不为空
- parent = cur;
- Node *subLeft = cur->_right;//subarea node 子区节点
- while (subLeft->_left)
- {//遍历删除节点的左子树??
- parent = subLeft;
- subLeft = subLeft->_left;
- }
- cur->_data = subLeft->_data;
- cur->_freq = subLeft->_freq;
- if (parent->_left == subLeft)
- {
- parent->_left = subLeft->_right;
- }
- else
- {
- parent->_right = subLeft->_right;
- }
- delete subLeft;
- }
- return true;
- }
- //以下是递归方式
- bool InsertR(const K& data, const V& freq)
- {
- return _InsertR(_root, data, freq);
- }
- bool _InsertR(Node*& root, const K& data, const V& freq)
- {
- if (root == NULL)
- {
- root = new Node(key, freq);
- return true;
- }
- if (data > root->_data)
- {
- return _InsertR(root->_right, key, freq);
- }
- else if (data < root->_data)
- {
- return _InsertR(root->_left, key, freq);
- }
- else
- {
- return false;
- }
- }
- Node* FindR(const K& data)
- {
- return _FindR(_root, data);
- }
- Node* _FindR(Node*& root, const K& data)
- {
- if (root == NULL)
- {
- return NULL;
- }
- if (data > root->_data)
- {
- return _FindR(root->_right, key);
- }
- else if (data < root->_data)
- {
- return _FindR(root->_left, key);
- }
- else
- {
- return root;
- }
- }
- bool RemoveR(const K& data)
- {
- return _RemoveR(_root, data);
- }
- bool _RemoveR(Node*& root, const K& data)
- {
- if (root == NULL)
- {
- return false;
- }
- if (data > root->_data)
- {
- return _RemoveR(root->_right, data);
- }
- else if (data < root->_data)
- {
- return _RemoveR(root->_left, data);
- }
- else
- {
- Node* del = root;
- if (root->_left == NULL)
- {
- root = root->_right;
- }
- else if (root->_right == NULL)
- {
- root = root->_left;
- }
- else
- {
- Node* parent = root;
- Node* subLeft = root->_right;
- while (subLeft->_left)
- {
- parent = subLeft;
- subLeft = subLeft->_left;
- }
- root->_data = subLeft->_data;
- root->_freq = subLeft->_freq;
- del = subLeft;
- if (parent->_left == subLeft)
- {
- parent->_left = subLeft->_right;
- }
- else
- {
- parent->_right = subLeft->_right;
- }
- }
- delete del;
- return true;
- }
- }
- void InOrder()
- {
- _InOrder(_root);
- cout << endl;
- }
- void _InOrder(Node* root)
- {
- if (root == NULL)
- return;
- _InOrder(root->_left);
- cout << root->_data << " ";
- _InOrder(root->_right);
- }
- protected:
- Node* _root;
- };</span>
在删除算法过程中要注意细节情况
1.删除根节点
2.删除叶子节点
3.删除带有子树的节点
算法分析:
它和二分查找一样,插入和查找的时间复杂度均为lgN,但是在最坏的情况下仍然会有N的时间复杂度。原因在于插入和删除元素的时候,树没有保持平衡。我们追求的是在最坏的情况下仍然有较好的时间复杂度,这就是后面要讲的平衡查找树的内容了。下文首先讲解平衡查找树的最简单的一种:2-3查找树。BST与二分查找一样,插入与查找的时间复杂度均为lgN,但是BST最坏情况是插入一个本身的有序的数列,这样在构建BST时会退化成类似于数组结构
即:
有一篇BST分析的很到位,链接是:
http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html
所以也就衍生出AVL树即平衡二叉查找树