二叉搜索树的增删查(递归与非递归)实现
来源:互联网 发布:python unpackbits 编辑:程序博客网 时间:2024/05/29 17:37
二叉搜索树(BinarySearchTree):
二叉搜索树性质:
1. 每个节点都有一个作为搜索依据的关键码(key),所有节点的关键码互不相同。
2. 左子树上所有节点的关键码(key)都小于根节点的关键码(key)。
3. 右子树上所有节点的关键码(key)都大于根节点的关键码(key)。
4. 左右子树都是二叉搜索树。
如图:是一个二叉搜索树
本文将实现二叉搜索树的插入删除查找
我们先定义一个二叉搜索树的结点结构体
template<class K>struct BinarySearchTreeNode{ BinarySearchTreeNode<K>* _left; BinarySearchTreeNode<K>* _right; K _key; BinarySearchTreeNode(const K& key) :_left(NULL) , _right(NULL) , _key(key) {}};
插入
插入的返回类型为bool,因为有可能会插入失败
搜索二叉树还有一个特点就是不能有重复的数,因为有重复的数会导致冗余
思想(非递归):我们完成插入的函数需要定义两个结点,cur和parent,我们需要用parent来记录cur的父亲,进入函数首先判断这棵树是否为空,若为空,直接新建结点,并且返回值为true,我们将_root给cur,我们首先要遍历一下这棵树,比根小的向左边走,比根大的向右边走,在这里每次走之前都要先将cur的值给parent,如果相等则返回false(二叉搜索树不能有重复的结点,会冗余),
找到key放的位置后,我们要判断key在parent的左边还是右边,如果在左边,则让parent->_left等于存放key值的结点,反之让parent->_right等于存放key的结点。最后返回true,这样我们的非递归插入就实现好了。(注意:在这里的插入不能用我们下面实现的Find()函数,因为Find()函数只能返回当前结点,而当前节点的parent找不到。没有parent我们Insert()就无法判断结点放左边还是右边)
bool Insert(const K& key) { if (_root == NULL) { _root = new Node(key); return true; } Node* parent = NULL; Node* cur = _root; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { return false; } } if (parent->_key > key) { Node* tmp = new Node(key); parent->_left = tmp; } else { Node* tmp = new Node(key); parent->_right = tmp; } return true; }
插入(递归实现)思想:
插入的递归实现主要是利用了root的引用,在这里root有两层含义,一个是当前的值,一个是上一层的值也就是当前值的parent。递归实现代码相对简单,但是不太容易理解。
bool _InsertR(Node* &root, const K& key) { if (root == NULL) { root = new Node(key); return true; } if (root->_key > key) { _InsertR(root->_left,key); } else if (root->_key < key) { _InsertR(root->_right,key); } else { return false; } }
查找
思想:查找的函数思想就很简单了,只要cur为真就进入循环:比根小的向左边走,比根大的向右边走等于根就返回cur.
Node* Find(const K& key) { Node* cur = _root; while (cur) { if (cur->_key < key) { cur = cur->_right; } else if (cur->_key > key) { cur = cur->_right; } else { return cur; } } return NULL; }
删除
二叉搜索树的删除是在这里最重要的
删除可以分为三种情况:
1,左为空
2,右为空
3,两边都不为空。
删除的非递归思想:
我们先遍历一下这棵树,找到要删除的结点,我们把当前要删除的结点给del,先看左为空,
先判断当前要删除的结点是不是根,是根的话就把根给根的右孩子。
不是根的话,我们需要判断的是cur在parent的左边还是右边
用一幅图来讲解
右为空的情况跟作左为空是相似的,就还是用图直白的解释一下
第三种情况:左右都不为空
我们如果直接删除一个左右都不为空的结点,会导致他的左右孩子没有父亲,导致野指针情况发生,我们在这里可以找一个结点去替换一个左右都不为空的结点,然后删除这个结点,那么这个结点应该选择哪个呢:
我们可以找左子树的最右结点(左子树中最大的数)或者右子树的最左结点(右子树中最小的数),本文使用的是右子树的最左结点,暂且把它叫做subleft,去替换要删除的这个数,然后删除subleft。这样我们的二叉树就还是二叉搜索树。
这里需要特别注意的一点是我们不能将parent的初始值给为NULL,而要给成cur.
我们这里parent是subleft的父亲,和上面一样我们要判断subleft在parent的左边还是右边,两边情况不一样。
bool Remove(const K& key) { Node* parent = NULL; Node* cur = _root; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { //1,左为空 或 右为空 //3,左右都不为空 Node* del = cur; //左为空 if (cur->_left == NULL) { if (cur == _root) { _root = cur->_right; } else { if (cur == parent->_right) { parent->_right = cur->_right; } else { parent->_left = cur->_right; } } } //右为空 else if (cur->_right == NULL) { if (cur == _root) { _root = cur->_left; } else { if (cur == parent->_right) { parent->_right = cur->_left; } else { parent->_left = cur->_left; } } } //左右都不为空 else { Node* parent = cur; Node* subleft = cur->_right; while (subleft->_left) { parent = subleft; subleft = subleft->_left; } cur->_key = subleft->_key; del = subleft; if (parent->_left == subleft) { parent->_left = subleft->_right; } else { parent->_right = parent->_left; } } delete del; return true; } } }
删除(递归实现)
这里特别要注意的是root的引用
这是递归实现的关键
bool _RemoveR(Node* &root, const K& key) { if (root == NULL) { return false; } if (root->_key < key) { return _RemoveR(root->_right, key); } else if (root->_key > key) { return _RemoveR(root->_left, key); } else { //1,左为空或右为空 //2,左右都不为空 if (root->_left == NULL) { root = root->_right; } else if (root->_right == NULL) { root = root->_left; } 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->_key = subLeft->_key; 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->_key << " "; _Inorder(root->_right); }
我们要让每个key对应一个value
我们就要给代码中加入value
下面完整代码是我们实现的二叉搜索树的key-value树
#include<iostream>#include<assert.h>using namespace std;template<class K,class V>struct BinarySearchTreeNode{ BinarySearchTreeNode<K,V>* _left; BinarySearchTreeNode<K,V>* _right; K _key; V _value; BinarySearchTreeNode(const K& key,const V& value) :_left(NULL) , _right(NULL) , _key(key) , _value(value) {}};template<class K,class V>class BinarySearchTree{ typedef BinarySearchTreeNode<K,V> Node;public: BinarySearchTree() :_root(NULL) {} bool Insert(const K& key,const V& value) { 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->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { return false; } } if (parent->_key > key) { Node* tmp = new Node(key,value); parent->_left = tmp; } else { Node* tmp = new Node(key,value); parent->_right = tmp; } return true; } void InsertR(const K& key,const V& value) { _InsertR(_root,key,value); } bool _InsertR(Node* &root, const K& key, const V& value) { if (root == NULL) { root = new Node(key,value); return true; } if (root->_key > key) { _InsertR(root->_left,key,value); } else if (root->_key < key) { _InsertR(root->_right,key,value); } else { return false; } } Node* Find(const K& key) { Node* cur = _root; while (cur) { if (cur->_key < key) { cur = cur->_right; } else if (cur->_key > key) { cur = cur->_right; } else { return cur; } } return NULL; } bool Remove(const K& key) { Node* parent = NULL; Node* cur = _root; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { //1,左为空 或 右为空 //3,左右都不为空 Node* del = cur; //左为空 if (cur->_left == NULL) { if (cur == _root) { _root = cur->_right; } else { if (cur == parent->_right) { parent->_right = cur->_right; } else { parent->_left = cur->_right; } } } //右为空 else if (cur->_right == NULL) { if (cur == _root) { _root = cur->_left; } else { if (cur == parent->_right) { parent->_right = cur->_left; } else { parent->_left = cur->_left; } } } //左右都不为空 else { Node* parent = cur; Node* subleft = cur->_right; while (subleft->_left) { parent = subleft; subleft = subleft->_left; } cur->_key = subleft->_key; del = subleft; if (parent->_left == subleft) { parent->_left = subleft->_right; } else { parent->_right = parent->_left; } } delete del; return true; } } } bool RemoveR(const K& key) { return _RemoveR(_root,key); cout << endl; } bool _RemoveR(Node* &root, const K& key) { if (root == NULL) { return false; } if (root->_key < key) { return _RemoveR(root->_right, key); } else if (root->_key > key) { return _RemoveR(root->_left, key); } else { //1,左为空或右为空 //2,左右都不为空 if (root->_left == NULL) { root = root->_right; } else if (root->_right == NULL) { root = root->_left; } 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->_key = subLeft->_key; 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->_key << root->_value<<" "; _Inorder(root->_right); }private: Node* _root;};void Test(){ BinarySearchTree<int,int> b; /*b.InsertR(0)*/; int a[] = { 4, 5, 1, 2, 0, 3, 9, 8, 7, 6 }; for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) { b.InsertR(a[i],i); } b.Inorder(); b.RemoveR(5); b.RemoveR(1); b.RemoveR(4); b.RemoveR(2); b.RemoveR(0); b.RemoveR(6); b.RemoveR(8); b.Inorder();}
- 二叉搜索树的增删查(递归与非递归)实现
- 【数据结构】二叉搜索树(增、删、查)的递归与非递归实现
- 【数据结构】二叉搜索树的递归与非递归实现
- 【数据结构】搜索二叉树的(递归与非递归)实现,包括:增Insert,删Remove,查Find
- 二叉搜索树的实现(查找,插入,删除的递归与非递归)
- 二叉搜索树的非递归实现
- 二叉树算法的实现(递归与非递归)
- 二叉搜索树递归&&非递归的基本实现
- 二叉搜索树(递归和非递归分别实现)
- C++实现二叉搜索树(递归&非递归)
- 二叉搜索树(BST)递归与非递归的插入、删除、查找的实现
- 递归与非递归实现二叉树
- Java实现二叉树的递归与非递归遍历
- 二叉树的递归遍历与非递归算法实现
- 二叉树的递归遍历与非递归算法实现
- 二叉树的递归与非递归实现
- 递归与非递归实现二叉树的遍历
- 二叉树的递归与非递归遍历实现
- 基于R-CNN的物体检测
- 如何在函数体内给外部指针申请内存
- java 中Map 常用的子类 之 Hashtable
- C++练习
- 构建高并发高可用的电商平台架构
- 二叉搜索树的增删查(递归与非递归)实现
- hadoop 压缩 gzip biz2 lzo snappy
- adaboost算法
- 【leetcode】寻找两个已排序数组的中位数(类似二分)
- Apache和nginx服务运行原理
- NOIP模拟(10.22)T2 杆子的排列
- centos6.8安装zabbix3.2
- tp3.2 缓存
- 实验四——顺序栈