数据结构之二叉搜索树
2016-06-23 10:16
477 查看
一。定义:二叉搜索树(Binary Search Tree),也称有序二叉树(ordered binary tree),排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树:1. 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;2. 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;3. 任意节点的左、右也分别为二叉查找树。4. 没有键值相等的节点(no duplicate nodes)。根据二叉搜索树的特点知:对二叉搜索树进行中序遍历得到的结点序列必然是一个有序序列。
一棵二叉搜索树:
根据树的结构,我们可以封装一个结点的结构BSNode:
二叉搜索树的结构我们更加关注的是它的增删查改功能。而且在这过程中我们要保证整棵树中没有重复的key值(结点的值)所以封装一棵二叉搜索树BSTree:
二。实现 (一)插入新结点
插入节点的思路就是递归的找要插入的位置,直到root为NULL,那么当前位置就是要插入的位置。
(二)查找结点,返回该结点
(三)删除结点,使剩下结点仍是一棵二叉搜索树
查找待删除的结点,每次判断:当前结点key值大于key。递归进入左子树,继续查找。
当前结点key值小于key。递归进入右子树,继续查找。
当前结点key值等于key。在这又分为4种情况:
当前结点的左子树为空。删除当前结点,把右子树给当前指针
当前结点的右子树为空。删除当前结点,把左子树给当前指针
当前结点的左右子树都为空。把根指针置空,删除当前结点。
当前结点的左右子树都不为空。找到右子树的最左结点,和待删除结点交换值,删除最左结点。
把这些因素都考虑周全就可以准确的删除二叉搜索树的任何一个结点。
一棵二叉搜索树:
根据树的结构,我们可以封装一个结点的结构BSNode:
template<class K,class V> struct BSNode { BSNode<K, V>* _left; BSNode<K, V>* _right; K _key; V _value; BSNode(const K& key, const V& value) :_left(NULL) , _right(NULL) ,_key(key) , _value(value) {} };在这里树的结构封装了key/value形式的键值对。
二叉搜索树的结构我们更加关注的是它的增删查改功能。而且在这过程中我们要保证整棵树中没有重复的key值(结点的值)所以封装一棵二叉搜索树BSTree:
template<class K,class V> class BSTree { public: typedef BSNode<K, V> Node;<pre name="code" class="cpp">//增删改查功能 protected: Node* _root; };
二。实现 (一)插入新结点
bool Insert(const K& key, const V& value)//<span style="color:#ff0000;">非递归形式</span> { if (_root == NULL) { _root = new Node(key, value); return true; } Node* parent = NULL; Node* cur = _root; 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->_left == NULL && parent->_key > key) { parent->_left = new Node(key, value); } else if (parent->_right == NULL && parent->_key < key) { parent->_right = new Node(key, value); } return true; }
bool Insert_R(const K& key, const V& value)//<span style="color:#ff0000;">插入的递归实现</span> { return _Insert_R(_root, key, value); }</span><pre name="code" class="cpp">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) _Insert_R(root->_left, key, value); else if (root->_key < key) _Insert_R(root->_right, key, value); else return false; return false; }
插入节点的思路就是递归的找要插入的位置,直到root为NULL,那么当前位置就是要插入的位置。
(二)查找结点,返回该结点
Node* Find(const K& key) //<span style="color:#ff0000;">非递归实现</span> { 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(const K& key)//<span style="color:#ff0000;">递归实现</span> { return _Find_R(_root, key); }<pre name="code" class="cpp">Node* _Find_R(Node* root,const K& key) { if (root == NULL) return NULL; if (root->_key > key) _Find_R(root->_left, key); else if (root->_key < key) _Find_R(root->_right, key); else return root; }查找的实现就是分三种情况,当前结点key大于key,小于key,等于key。大于key递归的在当前结点的右子树查找,小于在左子树找,等于就返回结点。
(三)删除结点,使剩下结点仍是一棵二叉搜索树
bool Remove(const K& key)//非递归实现 { return _Remove(_root, key); }
bool _Remove(Node* root, const K& key) { if (root == NULL) return false; Node* parent = NULL; Node* cur = root; Node* del = NULL; while (cur) { if (cur->_key > key) { parent = cur; cur = cur->_left; } else if (cur->_key < key) { parent = cur; cur = cur->_right; } else { del = cur; //待删除结点左为空 if (cur->_left == NULL) { if (parent && parent->_left == cur) parent->_left = cur->_right; else if (parent && parent->_right == cur) parent->_right = cur->_right; else _root = cur->_right; } else if (cur->_right == NULL)//待删除结点右为空 { if (parent && parent->_left == cur) parent->_left = cur->_left; else if (parent &&parent->_right == cur) parent->_right = cur->_left; else _root = cur->_left; } else if (cur->_left == NULL && cur->_right == NULL)//待删除结点左右都为空 { if (parent && parent->_left == cur) parent->_left = NULL; else if (parent && parent->_right == cur) parent->_right = NULL; else _root = NULL; } else if (cur->_left && cur->_right)//待删除结点左右都不为空 { //找出右子树的最左结点 Node* firstleft = cur->_right; parent = cur; while (firstleft->_left) { parent = firstleft; firstleft = firstleft->_left; } del = firstleft; swap(cur->_key, firstleft->_key); swap(cur->_value, firstleft->_value); //判断最左结点是它父节点的左结点还是右结点 if (parent && parent->_left == firstleft) { parent->_left = firstleft->_right; } else if (parent && parent->_right == firstleft) { parent->_right = firstleft->_right; } else //parent==NULL。待删除结点的右边只有一个结点,则最左结点就是它 { root->_right = NULL; } } delete del; return true; } } return false; }
bool Remove_R(const K& key)//递归实现 { return _Remove_R(_root, key); }<pre name="code" class="cpp">bool _Remove_R(Node*& root, const K& key) { if (root == NULL) return false; if (root->_key > key) { _Remove_R(root->_left, key); } else if (root->_key < key) { _Remove_R(root->_right, key); } else { Node* del = root; if (root->_left == NULL&&root->_right == NULL) { root = NULL; } else if (root->_left == NULL) { root = root->_right; } else if (root->_right == NULL) { root = root->_left; } else { Node* parent = NULL; Node* firstleft = root->_right; while (firstleft->_left) { parent = firstleft; firstleft = firstleft->_left; } del = firstleft; swap(root->_key, firstleft->_key); swap(root->_value, firstleft->_value); if (parent && parent->_left == firstleft) { parent->_left = firstleft->_right; } else if (parent && parent->_right == firstleft) { parent->_right = firstleft->_right; } else //parent==NULL。待删除结点的右边只有一个结点,则最左结点就是它 { root->_right = NULL; } } delete del; return true; } return false; }删除节点要考虑到的因素就要多了。我们可以划分子问题的方法来解决:
查找待删除的结点,每次判断:当前结点key值大于key。递归进入左子树,继续查找。
当前结点key值小于key。递归进入右子树,继续查找。
当前结点key值等于key。在这又分为4种情况:
当前结点的左子树为空。删除当前结点,把右子树给当前指针
当前结点的右子树为空。删除当前结点,把左子树给当前指针
当前结点的左右子树都为空。把根指针置空,删除当前结点。
当前结点的左右子树都不为空。找到右子树的最左结点,和待删除结点交换值,删除最左结点。
把这些因素都考虑周全就可以准确的删除二叉搜索树的任何一个结点。
相关文章推荐
- AVL树-自平衡二叉查找树(Java实现)
- C语言二叉树的非递归遍历实例分析
- 使用C语言构建基本的二叉树数据结构
- 一波二叉树遍历问题的C++解答实例分享
- 举例讲解C语言程序中对二叉树数据结构的各种遍历方式
- C++非递归队列实现二叉树的广度优先遍历
- PHP实现的线索二叉树及二叉树遍历方法详解
- C#使用前序遍历、中序遍历和后序遍历打印二叉树的方法
- C#非递归先序遍历二叉树实例
- C++将二叉树转为双向链表及判断两个链表是否相交
- C++非递归建立二叉树实例
- C语言实现找出二叉树中某个值的所有路径的方法
- C++实现二叉树遍历序列的求解方法
- C语言实现二叉树遍历的迭代算法
- C++实现查找二叉树中和为某一值的所有路径的示例
- 用C语言判断一个二叉树是否为另一个的子结构
- C++实现二叉树非递归遍历方法实例总结
- C++二叉树结构的建立与基本操作
- 深入遍历二叉树的各种操作详解(非递归遍历)
- Python实现二叉树结构与进行二叉树遍历的方法详解