搜索二叉树实现->迭代器实现->转化为双向链表
来源:互联网 发布:战斗机的分类 知乎 编辑:程序博客网 时间:2024/06/04 00:02
二叉排序树及其查找过程
二叉排序树(Binary Sort Tree)或者是一颗空树;或者是具有下列性质的二叉树:
(1)、若它的左子树不空,则左子树上所有结点的值均小于它的根结点; (2)、若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; (3)、它的左、右子树也分别为二叉排序树;
二叉排序树又称二叉查找树,根据上述定义的结构特点可见,它的查找过程和次优二叉树类似。即当二叉排序树不空时,首先将给定值和根结点的关键字比较,若相等,则查找成功,否则将依据给定值和根结点的关键字之间的大小关系,分别在左子树或游戏书上继续查找。通常,可取二叉链表作为二叉排序树的存储结构,简单的查找算法:
//非递归 bool Find_Nor(const K& key) { Node* pCur = _pRoot; if (NULL == _pRoot) return false; while (pCur) { if (key < pCur->_key) pCur = pCur->_pLeft; else if (key > pCur->_key) pCur = pCur->_pRight; else return true; } return false; } //递归 bool _Find(Node* pRoot, const K& key) { if (NULL == pRoot) return false; if (key < pRoot->_key) return _Find(pRoot->_pLeft, key); else if (key > pRoot->_key) return _Find(pRoot->_pRight, key); else return true; }
我们都知道它叫做二叉搜索树(二叉查找树)所以它的查找效率应该是杠杠的;
二叉排序树的插入
二叉排序树是一种动态树表,其特点是,树的结构通常不是一次生成的,而是在查找过程中,当树中不存在关键字等于给定值得结点时再进行插入。新插入的结点一定是一个新添加的叶子结点,并且是查找不成功时查找路径上访问的最后一个节点的左孩子或者右孩子结点。为此,我们可以在查找的基础上加入添加元素,便可以完成插入;
//非递归 bool Insert_Nor(const K& key, const V& value) { Node* _node = new Node(key, value); if (NULL == _pRoot) { _pRoot = _node; return true; } Node* pParent = NULL; Node* pCur = _pRoot; while (pCur) //找到新结点要放的位置,所以它是NULL的,需要保存它的双亲 { if (key < pCur->_key) { pParent = pCur; pCur = pCur->_pLeft; } else if (key > pCur->_key) { pParent = pCur; pCur = pCur->_pRight; } else { cout << "数据已存在" << endl; return false; } } if (key < pParent->_key) //与双亲比较后,存放,满足二叉搜索树的性质 { pParent->_pLeft = _node; return true; } else { pParent->_pRight = _node; return true; } } //递归 bool _Insert(Node* &pRoot, const K& key, const V& value) { if (NULL == pRoot) { pRoot = new Node(key, value); return true; } if (key < pRoot->_key) return _Insert(pRoot->_pLeft, key, value);//return 什么时候使用? else if (key > pRoot->_key) return _Insert(pRoot->_pRight, key, value); else { cout << "数据已存在" << endl; return false; } }
二叉排序树的删除
首先查找元素是否在二叉搜索树中,如果不存在,则返回;否则要删除的结点可能分为下面四种情况:
1、要删除的结点无孩子结点(叶子结点)2、要删除的结点只有左孩子结点3、要删除的结点只有右孩子结点4、要删除的结点左右孩子都有;
对于这4中情况,相应的删除方法如下:
a、直接删除该结点;b、删除该结点且使被删除结点的双亲结点指向别删除结点的左孩子结点;c、删除该结点且使被删除结点的双亲结点指向被删除界定啊的右孩子结点;d、在他的右子树中寻找中序遍历下的第一个结点,用它的值填补到被删除结点中,在来处理该结点的删除问题;
最终:我们将第一种情况规划到2或3中一起处理就可以了;
要删除的结点只有左孩子结点
要删除的结点只有左孩子时,也要分为3中情况:
1、删除的结点为根结点,根结点直接指向它的下一个结点;2、要删除的结点为双亲结点的左孩子,双亲的左孩子应该指向被删除结点的左孩子;3、要删除的结点为双亲结点的右孩子,双亲的右孩子应该指向被删除结点的左孩子
下图仅供参考:
要删除的结点只有右孩子结点
同样,要删除的结点只有右孩子结点时,也可以分为上图的三种情况:
要删除的结点左右孩子都有
删除的这三种情况分起来还是比较容易混的,所以画图是一个很好的办法
参考代码:
//非递归 bool Remove_Nor(const K& key) //?????????????????????????????????? { if (NULL == _pRoot) return false; if (NULL == _pRoot->_pLeft && NULL == _pRoot->_pRight) { delete _pRoot; _pRoot = NULL; return true; } Node* pParent = NULL; Node* pDel = _pRoot; while (pDel) //查找要删的元素 { if (key < pDel->_key) { pParent = pDel; pDel = pDel->_pLeft; } else if (key > pDel->_key) { pParent = pDel; pDel = pDel->_pRight; } else break; } if (pDel) { if (pDel->_pLeft == NULL) //没有左子树 { if (pDel == _pRoot) //如果pDel是根结点 { _pRoot = pDel->_pRight; } else { if (pParent->_pLeft == pDel) pParent->_pLeft = pDel->_pRight; else pParent->_pRight = pDel->_pRight; } delete pDel; pDel = NULL; } else if (pDel->_pRight == NULL) //没有右子树 { if (pDel == _pRoot) _pRoot = pDel->_pLeft; else { if (pParent->_pLeft == pDel) pParent->_pLeft = pDel->_pLeft; else pParent->_pRight = pDel->_pLeft; } delete pDel; pDel = NULL; } else { //找到右子树中最小的结点 Node* FirstInder = pDel->_pRight; Node* prve = pDel; if (FirstInder->_pLeft) { prve = FirstInder; FirstInder = FirstInder->_pLeft; } std::swap(FirstInder->_key, pDel->_key); std::swap(FirstInder->_value, pDel->_value); if (prve->_pRight == FirstInder) prve->_pRight = FirstInder->_pRight; else prve->_pLeft = FirstInder->_pRight; delete FirstInder; FirstInder = NULL; } return true; } else { cout << "没有这个数" << endl; return false; } }//递归 bool _Remove(Node*& pRoot, const K& key) { if (NULL == pRoot) return false; if (key < pRoot->_key) return _Remove(pRoot->_pLeft, key); else if (key > pRoot->_key) return _Remove(pRoot->_pRight, key); else { Node* pDel = pRoot; if (pRoot->_pLeft == NULL) { pRoot = pRoot->_pRight; delete pDel; pDel = NULL; } else if (pRoot->_pRight == NULL) { pRoot = pRoot->_pLeft; delete pDel; pDel = NULL; } else { Node* FirstInder = pDel->_pRight; while (FirstInder->_pLeft) FirstInder = FirstInder->_pLeft; std::swap(FirstInder->_key, pDel->_key); std::swap(FirstInder->_value, pDel->_value); _Remove(pRoot->_pRight, key);//这里不能传临时变量 } } }
一般实现:上面是每个模块的单独代码,完整代码以上传GitHub中:搜索二叉树的插入与删除;
迭代器实现
利用迭代器实现 完整代码GitHub中:迭代器实现搜索二叉树
转化为双向链表
Node* _TreeToList(Node* pRoot, Node*& prev) { Node* cur = pRoot; if (NULL == cur) //树如果为空,退出 return NULL; _TreeToList(cur->_pLeft, prev); cur->_pLeft = prev; if (prev) { prev->_pRight = cur; } prev = cur; _TreeToList(cur->_pRight, prev); }
阅读全文
0 1
- 搜索二叉树实现->迭代器实现->转化为双向链表
- 二叉搜索树与双向链表(二叉搜索树转化为双向链表)
- 二叉搜索树转化为双向链表
- 二叉搜索树转化为双向链表
- 二叉搜索树转化为双向链表
- 二叉搜索树转化为有序双向链表
- 搜索二叉树转化为双向链表
- 二叉搜索树转化为双向链表
- 将二叉搜索树转化为双向链表
- 二叉搜索树转化为有序双向链表
- 将搜索二叉树转化为双向链表
- 二叉搜索树转化为双向链表
- 将二叉搜索树转化为双向链表
- 二叉搜索树转化双向链表
- 二叉树经典面试题2~将搜索二叉树转化为双向链表
- 如何将搜索二叉树转化为排序双向链表
- 读剑指offer有感--搜索二叉树转化为有序双向链表
- 将二叉搜索树转化为一个排序的双向链表
- 配置电子邮件传输
- IDEA中maven项目导入依赖包太慢,因为你的中央仓库配置的国外....
- HDU 1170 Balloon Comes!
- @RequestMapping @Responsebody与@RequestBody @PathVariable
- 人民币,大写中文与数字之间转换
- 搜索二叉树实现->迭代器实现->转化为双向链表
- Java中什么是GC?
- 第十届ACM省赛-A 谍报分析
- ReactNative仿《ONE》APP
- Machine Learning「Week1」
- javascript学习日记
- (53)组件之灯光组件
- bootstrap 常用记录
- 如何在服务器上展示你的你的网页--no!!!用github也可以