二叉搜索树

来源:互联网 发布:淘宝上的海外专营店 编辑:程序博客网 时间:2024/06/12 01:16

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

     

          1. 每个节点都有一个作为搜索依据的关键码(key),所有节点的关键码互不同。

          2. 左子树上所有节点的关键码(key)都小于根节点的关键码(key)。

          3. 右子树上所有节点的关键码(key)都大于根节点的关键码(key)。

          4. 左右子树都是二叉搜索树。

            对于二叉搜索树,在实现它的结点的插入、删除、查找时,插入结点不是很复杂,但是对于其删除有一定的难度。在实现删除时,要考虑的情况较多。

      一、对二叉树的定义:

template<class K,class V>struct BSTNode{K _key;V _value;BSTNode<K, V>* _Left;BSTNode<K, V>* _Right;BSTNode(K key,V value):_key(key),_value(value),_Left(NULL),_Right(NULL){}};template<class K, class V>class BSTree{typedef BSTNode<K, V>  Node;public:BSTree():_root(NULL){}}
对于定义,应该没什么问题。那就来说说它的插入、删除、查找的实现。


二、插入的实现

   对于插入,在此我用两种方法来实现(递归和非递归)

  首先,非递归的方法:(在插入时,都要按照二叉树的性质来实现即要在合适位置)

  思想:1、先考虑根结点为空。

             2、保存上一个节点,插入时要找上一个结点。

             3、找到合适的位置(要插入的key小于当前key就往左子树找反之往右子树找)

             4、找到合适位置后,插入结点

bool Insert(const K& key, const V& value){if (_root == NULL){                    _root = new Node(key, value);    return true;}Node* cur = _root;Node* parent = NULL;while (cur){if (cur->_key > key){parent = cur;cur = cur->_Left;}else if (cur->_key < key){parent = cur;cur = cur->_Right;}else{return false;}}if (parent->_key > key){parent->_Left = new Node(key, value);}else{parent->_Right = new Node(key, value);}return true;}
      非递归完成后,我们来看一下Insert的递归的形式

bool  _Insert_R(Node* &root, const K& key, const V& value){if (root == NULL){root = new Node(key, value);return true;}if (root->_key > key){return _Insert_R(root->_Left,key,value);}else if (root->_key < key){return _Insert_R(root->_Right,key,value);}return false;}
接下来就是的查找和删除,先看一下查找:

 三、查找的实现(非递归形式)

Node* _Find(Node* root, const K& key){if (root == NULL)return NULL;Node* cur = root;while (cur){if (cur->_key > key){cur = cur->_Left;}else if (cur->_key < key){cur = cur->_Right;}else {return cur;}}return NULL;}
查找的递归形式

Node* _Find_R(Node* &root, const K& key){if (root == NULL) //没有结点return root;if (root->_key == key)return root;if (root->_key < key){return _Find_R(root->_Right, key);}else{return _Find_R(root->_Left, key);}}
四、删除的实现:(非递归)对于删除,在此需要考虑的情况非常多。

下面是删除的思想:

(在删除时,也要和查找一样,先查找到要删除的结点,然后删除)



   1、考虑根结点为空情况和一个结点情况

   2、当有多个结点时,根据上图中的情形考虑到不同情况

     (1)要删除的左结点的左子树或右子数为空。

     (2)要删除的结点是根结点。

     (3)要删除的结点的左右结点都不为空。

bool _Remove(Node* root, const K& key){if (root == NULL)    //没有结点return false;if (root->_Left == NULL&&root->_Right == NULL)   //一个结点{if (root->_key == key){delete root;root = NULL;return true;}else{return false;}}Node* cur = root;        //多个节点Node* prev = NULL;while (cur){if (cur->_key > key){prev = cur;cur = cur->_Left;}else if (cur->_key < key){prev = cur;cur = cur->_Right;}else   //找到了要删除的结点,判断左子树是否为空,若为空,把删除点的左子树设为删除点右子树的左子树{Node *del = cur;if (cur->_Left == NULL){if (prev== NULL){_root = cur->_Right;}else{if (prev->_Left == cur){prev->_Left = cur->_Right;}else{prev->_Right = cur->_Right;}}}else if (cur->_Right == NULL){if (prev == NULL){_root= cur->_Left;}else{if (prev->_Left == cur){prev->_Left = cur->_Left;}else{prev->_Right = cur->_Left;}}}else  //左右都不为空{prev = cur;Node* fistleft = cur->_Right;while (fistleft->_Left){prev = fistleft;fistleft = fistleft->_Left;}swap(cur->_key, fistleft->_key);swap(cur->_value, fistleft->_value);del = fistleft;if (prev->_Left == fistleft){prev->_Left = fistleft->_Right;}else{prev->_Right = fistleft->_Right;}}delete del;return true;}}return false;}
删除的递归形式:
bool _Remove_R(Node* &root, const K& key)  //引用{if (root == NULL){return false;}if (root->_key < key){return _Remove_R(root->_Right,key);}else if (root->_key > key){return _Remove_R(root->_Left,key);}else{if (root->_Left == NULL){root = root->_Right;}else if (root->_Right==NULL){root = root->_Left;}else{Node* firstleft = root->_Right;while (firstleft->_Left){firstleft = firstleft->_Left;}swap(firstleft->_key, root->_key);swap(firstleft->_value, root->_value);_Remove_R(firstleft,key);}return true;}}
五、二叉查找树的时间复杂度


它和二分查找一样,插入和查找的时间复杂度均为lgN,但是在最坏的情况下仍然会有N的时间复杂度。原因在于插入和删除元素的时候,树没有保持平衡。




0 0
原创粉丝点击