二叉树中使用最广泛的就是搜索二叉树;
搜索二叉树还有其它名称:二叉排序树、二叉查找树等;
1.搜索二叉树的优点
1】有很好的查询性能
2】有很好的新增和删除的性能
3】若左子树不空,则左子树上所有结点的值均小于它的根结点的值
4】若右子树不空,则右子树上所有结点的值均大于它的根结点的值
5】左、右子树也分别为二叉排序树
如图:典型的搜索二叉树
对搜索二叉树进行中序遍历的结果就是元素从小到大排序后的结果;
如果二叉树中的元素是基本类型int、short等,可以直接操作;
如果元素是对象,那么该对象的类必须重载运算符><==,因为搜索二叉树就是通过这些运算符来排序的;
搜索二叉树里面不允许有重复元素;
2.搜索二叉树的操作
1)新增元素
例如:在上图的搜索二叉树中新增节点8
比较8和15,因为8<15,所以应该放左子树,如果左子树的节点没值就直接写到这里,有值就要继续比较;
比较8和5,8>5,放右子树;
8<12,放左边;
8<10,放左边;
8>6,放右边;
8>7,放右边,7的右子树是空的,因此8放这里;
因此8应该放在以7为父节点的右子树中;
例如:新增18
经过一系列查找,树中原本有一个18;
因为搜索二叉树中不允许重复元素,因此直接返回;
2)查找元素
例如:从上面图的二叉树中找6
6<15,从左找;
6>5,往右找;
6<12,往左找;
6<10,往左找,然后找到了;
例如:找21
21>15,从右找;
21>20,往右找;
21<23,往左找,然后左边没有了,因此找不到返回空;
3)删除元素
情况一:叶子节点
1】删除该节点
2】将父节点(左或者右)指针置NULL
例如:删除3,直接删除3,然后5的左指针指向NULL;
情况2:只有一个子树
1】删除该节点
2】将父节点(左或者右)指针指向子树
例如:删除6,直接删除6,然后将10的左指针指向7;
情况3:左右子树都有
方法1)
1】用右子树最小的节点取代源节点
2】再递归删除最小节点
例如:删除5
先从5的右边找到最小的6;
不删除5而是将节点处的值从5换为6;
再删除原来的6;
原理:
右边最小的数一定比根节点大,也比左边任何一个数大;
右边最小的数只可能是叶子节点,或只有右子树,删除操作简单;
方法2)
1】用左子树最大的节点取代源节点
2】删除最大节点
3.搜索二叉树的实现
头文件:
#ifndef SEARCHTREE_H #define SEARCHTREE_H #include "stdio.h" #include "stdlib.h" #include "windows.h" #define SUCCESS 1 // 执行成功 #define FAIL -1 // 执行失败 template<class T> class TreeNode{ public: T element; //当前节点存储的数据 TreeNode<T>* pLeft; //指向左子节点的指针 TreeNode<T>* pRight; //指向右子节点的指针 TreeNode<T>* pParent; //指向父结点的指针 TreeNode(T& ele){ //初始化Node节点 memset(&element,0,sizeof(TreeNode)); //为元素赋值 memcpy(&element,&ele,sizeof(T)); pLeft = pRight = pParent = NULL; } //重载== 比较两结点是否相等 bool operator==(TreeNode<T>* node){ return node->element == element?true:false; } }; template<class T> class BSortTree{ public: BSortTree(); //构造函数 ~BSortTree(); //析构函数 public: //判断树是否为空 bool IsEmpty(); //新增节点 DWORD Insert(T element); //删除节点 void Delete(T element); TreeNode<T>* Search(T element); //查找节点 void InOrderTraverse(TreeNode<T>* pNode); //中序遍历 void PreOrderTraverse(TreeNode<T>* pNode); //前序遍历 void PostOrderTraverse(TreeNode<T>* pNode); //后序遍历 private: TreeNode<T>* GetMaxNode(TreeNode<T>* pNode); //获取以pNode为根的最大节点 TreeNode<T>* GetMinNode(TreeNode<T>* pNode); //获取以pNode为根的最小节点 TreeNode<T>* SearchNode(TreeNode<T>* pNode,T element); //获取以pNode为根的最小节点 DWORD InsertNode(T element, TreeNode<T>* pNode); //新增节点 TreeNode<T>* DeleteNode(T element, TreeNode<T>* pNode); //删除节点 void Clear(TreeNode<T>* pNode); //清空所有节点 private: TreeNode<T>* m_pRoot; //根结点指针 int size; //树中元素总个数 }; template<class T> BSortTree<T>::BSortTree() { m_pRoot = NULL; size = 0; } template<class T> BSortTree<T>::~BSortTree(){ Clear(m_pRoot); } template<class T> DWORD BSortTree<T>::Insert(T element) { //如果根节点为空 if ( !m_pRoot ) { m_pRoot = new TreeNode<T>(element); size++; return SUCCESS; } //如果根节点不为空 return InsertNode(element, m_pRoot); } template<class T> DWORD BSortTree<T>::InsertNode(T element, TreeNode<T>* pNode) { //将元素封装到节点中 TreeNode<T>* pNewNode = new TreeNode<T>(element); //如果element == 当前节点 直接返回 if(element == pNode->element) { return SUCCESS; } //如果pNode的左子节点为NULL 并且element < 当前节点 if(pNode->pLeft == NULL && element < pNode->element) { pNode->pLeft = pNewNode; pNewNode->pParent = pNode; size++; return SUCCESS; } //如果pNode的右子节点为NULL 并且element > 当前节点 if(pNode->pRight == NULL && element > pNode->element){ pNode->pRight = pNewNode; pNewNode->pParent = pNode; size++; return SUCCESS; } //如果element<当前节点 且当前节点的左子树不为空 if(element < pNode->element) { InsertNode(element,pNode->pLeft); } else { InsertNode(element,pNode->pRight); } return SUCCESS; } template<class T> void BSortTree<T>::Clear(TreeNode<T>* pNode) { if(pNode!=NULL) { Clear(pNode->pLeft); Clear(pNode->pRight); delete pNode; pNode=NULL; } } template<class T> bool BSortTree<T>::IsEmpty() { return size==0?true:false; } template<class T> TreeNode<T>* BSortTree<T>::Search(T element) { return SearchNode(m_pRoot, element); } template<class T> TreeNode<T>* BSortTree<T>::SearchNode(TreeNode<T>* pNode,T element) { if(pNode == NULL) //如果节点为NULL { return NULL; } else if(element == pNode->element) //如果相等 { return pNode; } //如果比节点的元素小 向左找 else if(element < pNode->element) { return SearchNode(pNode->pLeft,element); } else //如果比节点的元素大 向右找 { return SearchNode(pNode->pRight,element); } } template<class T> void BSortTree<T>::Delete(T element) { //先找到元素所在节点 TreeNode<T>* node = Search(element); if(node == NULL){ //如果没有该元素则直接返回 return; } TreeNode<T>* parent = node->pParent; if(!node->pLeft && !node->pRight){ //如果是叶子节点直接删除 if(parent->pLeft == node){ //判断是父节点的左子树还是右子树 parent->pLeft = NULL; }else{ parent->pRight = NULL; } delete node; }else if(!node->pLeft){ //如果只有一个子树,删除该节点并用子树代替该节点 if(parent->pLeft == node){ //判断是父节点的左子树还是右子树 parent->pLeft = node->pRight; }else{ parent->pRight = node->pRight; } node->pRight->pParent = parent; delete node; }else if(!node->pRight){ if(parent->pLeft == node){ //判断是父节点的左子树还是右子树 parent->pLeft = node->pLeft; }else{ parent->pRight = node->pLeft; } node->pLeft->pParent = parent; delete node; }else{ //如果目标节点左右子树都不为空 TreeNode<T>* min = node->pRight; while(min->pLeft){ min = min->pLeft; //找到目标节点右子树中最小的元素 } memcpy(node, min, sizeof(T)); //用右子树最小元素的值替换目标节点的值 TreeNode<T>* minParent = min->pParent; //删除最小元素 if(minParent->pLeft == min){ minParent->pLeft = min->pRight; }else{ minParent->pRight = min->pRight; } if(min->pRight){ min->pRight->pParent = minParent; } delete min; } size--; return; } //中序遍历 template<class T> void BSortTree<T>::InOrderTraverse(TreeNode<T>* pNode){ if(pNode){ InOrderTraverse(pNode->pLeft); printf("%d\t",pNode->element); InOrderTraverse(pNode->pRight); } } #endif
测试:
#include "SearchTree.h" void fun() { //12 8 5 9 17 15 13 /* 12 8 17 5 9 15 13 */ BSortTree<int> tree; //插入 tree.Insert(12); tree.Insert(8); tree.Insert(5); tree.Insert(9); tree.Insert(17); tree.Insert(15); tree.Insert(13); //查找特定元素 TreeNode<int>* p = tree.Search(9); printf("%x %d\n",p,p->element); //中序遍历 tree.InOrderTraverse(tree.Search(12)); printf("\n"); //删除元素8 tree.Delete(8); tree.InOrderTraverse(tree.Search(12)); printf("\n"); } void main(){ fun(); getchar(); }
结果: