【二叉搜索树】二叉搜索树的基本操作

来源:互联网 发布:听书软件安卓 编辑:程序博客网 时间:2024/05/17 11:06


什么是二叉搜索树

二叉查找树(BinarySearch Tree,也叫二叉搜索树,或称二叉排序树Binary Sort Tree)或者是一棵空树,或者是具有下列性质的二叉树:

(1)若它的左子树不为空,则左子树上所有结点的值均小于它的根结点的值;

(2)若它的右子树不为空,则右子树上所有结点的值均大于它的根结点的值;

(3)它的左、右子树也分别为二叉查找树。


二叉树的节点

template<typename K, typename V>struct BianrySearchNode{BianrySearchNode(const K& key, const V& value): _key(key), _value(value), _pLeft(NULL), _pRight(NULL){}K _key;V _value;BianrySearchNode<K, V>* _pLeft;BianrySearchNode<K, V>* _pRight;};


二叉搜索树主要的操作:查找,插入,删除。

【插入】

(1)插入操作需要遍历二叉搜索树,

(2)a 待插入元素的值小于当前结点的key值,则访问当前结点的 左子树

     b 待插入元素的值大于当前结点的key值,则访问当前结点的右子树

     c 待插入元素的值等于当前结点的key值,则返回false,表示该元素已存在

代码实现

typedef BianrySearchNode<K, V>  Node;bool Insert(const K& key, const V& value) //这里实现用键值对{if (NULL == _pRoot){_pRoot = new Node(key, value);return true;}//找插入的点Node *pCur = _pRoot;Node *pParent = NULL;while (pCur){pParent = pCur;if (key < pCur->_key)pCur = pCur->_pLeft;else if (key > pCur->_key)pCur = pCur->_pRight;elsereturn false;}// 插入pCur = new Node(key, value);if (key < pParent->_key)pParent->_pLeft = pCur;elsepParent->_pRight = pCur;return true;}


【删除】

首先要查找该元素是否存在,如果不存在就返回false;存在要分为以下几种情况:

1、要删除的结点无孩子结点;(可以划分到2 或者3)
2、要删除的结点只有左孩子结点;
3、要删除的结点只有右孩子结点;
4、要删除的结点有左、右孩子结点;

其实上面还可以分为根节点和非根节点

对于上述情况,相应的删除方法如下:
a、直接删除该结点
b、删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点;
c、删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点;
d、在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除

画几个图来表示更清楚



在第三种情况中:黑色实体为删除的点,红色原点为查找的右子树中最小的节点。

删除元素为根节点和非根节点可以合并成一种情况


代码实现:

s 

bool Remove(const K& key){//找出要删除的节点Node* pCur = _pRoot;Node* pParent = NULL;while (pCur){if (key < pCur->_key){pParent = pCur;pCur = pCur->_pLeft;}else if (key > pCur->_key){pParent = pCur;pCur = pCur->_pRight;}elsebreak;}//跳出循环,pCur为空,不为空 :可能为根节点,//1该结点只有左子树 :包含左右子树都为空//2该节点只有右子树//3该节点有左右子树if (pCur){//只有左子树if (pCur->_pRight == NULL){if (pCur == _pRoot) //删除的节点为根节点,且只有左子树{_pRoot = pCur->_pLeft;}else{   //不为根if (pParent->_pLeft == pCur) //判断在左还是右pParent->_pLeft = pCur->_pLeft;elsepParent->_pRight = pCur->_pLeft;}delete pCur;}else if (pCur->_pLeft == NULL) //只有右子树{if (pCur == _pRoot)_pRoot = pCur->_pRight;else{if (pParent->_pLeft == pCur)pParent->_pLeft = pCur->_pRight;elsepParent->_pRight = pCur->_pRight;}delete pCur;}else //左右子树都存在:找右子树中最小的,再把两个的值互换,删除最小的的那个结点{//找右子树中最小的Node* pRightMin = pCur->_pRight;Node* pRightMinParent = pCur;while (pRightMin->_pLeft){pRightMinParent = pRightMin;pRightMin = pRightMin->_pLeft;}//不分根节点和非根节点pCur->_key = pRightMin->_key;pCur->_value = pRightMin->_value;if (pRightMin == pCur->_pRight)pRightMinParent->_pRight = pRightMin->_pRight;elsepRightMinParent->_pLeft = pRightMin->_pRight;delete pRightMin;}return true;}return false;}

这几种情况的测试用例

void TestRemove1() //左子树{//int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };BinarySearchTree<int, int> bs;BinarySearchTree<int, int> bs1;bs.Insert(5, 5);bs.Insert(3, 3);bs.Insert(1, 1);bs.Insert(7, 7);bs.Insert(2, 2);bs.Insert(0, 0);bs.Remove(3); // 测试普通节点//2种情况:根节点bs1.Insert(5, 5);bs1.Insert(3, 3);bs1.Insert(1, 1);bs1.Insert(2, 2);bs1.Insert(0, 0);bs1.Insert(4, 4);bs1.Remove(5);//删除根节点}void TestRemove2() //右子树{//int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };BinarySearchTree<int, int> bs;bs.Insert(5, 5);bs.Insert(6, 6);bs.Insert(8, 8);bs.Insert(7, 7);bs.Insert(9, 9);bs.Remove(6);//测试根节点bs.Remove(5);}void TestRemove3() //左右子树{//int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };BinarySearchTree<int, int> bs;BinarySearchTree<int, int> bs1;bs.Insert(4, 4);bs.Insert(3, 3);bs.Insert(7, 7);bs.Insert(8, 8);bs.Insert(5, 5);bs.Insert(6, 6);bs.Remove(4); //1//不为根节点bs1.Insert(4, 4);bs1.Insert(3, 3);bs1.Insert(6, 6);bs1.Insert(5, 5);bs1.Insert(9, 9);//bs1.Insert(7, 7);//bs1.Insert(8, 8);bs1.Insert(10, 10);bs1.Remove(6);}



1 0