二叉搜索树的插入,删除,遍历操作详解
来源:互联网 发布:至此终年网络番外怀孕 编辑:程序博客网 时间:2024/04/28 14:35
今天来详细介绍下二叉搜索树的一些操作以及代码实现;参考书籍:《算法导论第三版》(二叉搜索树的相关章节),《数据结构与算法》
一,二叉搜索树的定义
一颗二叉搜索树是以一颗二叉树来组织的,这样的一棵树可以使用一个链表数据结构来表示:
struct TreeNode{TreeNode* le; //需要注意,C语言中需要这样写:struct TreeNode* le,下同,写惯了C++的人这里是一个小坑TreeNode* rh;int value;
//有些时候会加上父亲节点 TreeNode* pa;}
现在我们有了树的数据结构,可以给出二叉树的定义了: 设 X是二叉搜索树中的一个节点。如果Y是 X左子树中的一个节点,那么 必定有: Y.value<= X.value。如果Y是X右子树中的一个节点,那么,必定有Y.value>=X.value ;
这是算法导论上的定义,翻译一下就是对于任意一个二叉搜索树中的节点,左子树中的任意一个节点的值都会小于它的值,右子树中的任意一个节点的值都会大于它的
值
二叉搜索树本身是自排序的,看定义就明白了,一直往右是最大值,一直往左是最小值,因此二叉搜索树可以作为一个优先级队列,这个以后介绍。
二叉搜索树的基本操作所花费的时间和这个树的高度是成正比的,对于一个有N个节点的二叉搜索树的各种操作的平均时间是O(logn); 当极度不平衡时,即任意节点没
有左子树或者右子树时,退化为链表;
二,二叉搜索树的插入操作
插入操作挺好理解的,就是从根节点开始往下走,如果插入的值大于等于该节点的值就往右子树走,否则就往左子树走,这里我就直接贴代码了,代码中有详细的注释
#include<iostream>using namespace std;struct TreeNode{TreeNode* le;TreeNode* rh;int value;};void addNodeToSearchBT(TreeNode** ptrPtrRoot, int k){TreeNode* pa = nullptr; //用于保存插入位置的父节点,因为下面循环中出来的节点是nullptrauto root = *ptrPtrRoot;while (root != nullptr){//循环遍历比较,判断该往左走还是往右走pa = root;if (k >= root->value)root = root->rh;else if (k < root->value)root = root->le;}TreeNode* newNode = new TreeNode;newNode->le = nullptr;newNode->rh = nullptr;newNode->value = k;//这儿就是简单的判断大小然后插入就可以了if (pa == nullptr){*ptrPtrRoot = newNode; //二叉树为空return;}if (k >= pa->value)pa->rh = newNode;else if (k < pa->value)pa->le = newNode;}
三,二叉搜索树的删除操作
这里感觉第一次看还是比较复杂的,会详细的介绍,一般来说都是使用被删除节点的右子树中的最小值作为替换节点,所以下面就不讨论使用左子树的最大值作为替换
节点的情况了;首先第一步当然是找到这个要被删除的节点,假设这个节点是D, 需要注意的是,我们这里并没有使用双向链,所需需要保存D节点的父亲节点,因为,拼接子树的时候
需要用到父亲节点,这里假设为Dpa;,被用来替换的节点假设为X;1.如果D是叶子节点,直接删除就OK,见图一2.如果D有子树,并且只有右子树,那也就是可以直接将D的右子树接到Dpa上就可以,见图二3.如果D有子树,并且只有左子树,那么直接将D的左子树接到Dpa上就可以,见图三4.如果D有两个子树,那么就找到右子树中的最小值,也就是从D开始一直往左走,直到走到叶子左子树为空的节点,那么我们就找到可以被用来替换的节点了,见图四
图一 图二
图三图四
接下来只需要把X接到D的位置上,并且把X的右子树接到它的父节点的左子树上就可以了;下面把代码贴上来,代码中注释的很详细
TreeNode* findNodeInSearchBT(TreeNode*root, int k, TreeNode**pa = nullptr){//这里是不需要进行null判断的,因为后面隐式的判断了是否为nullwhile (root != nullptr){if (k > root->value){*pa = root;root = root->rh;}else if (k < root->value){*pa = root;root = root->le;}elsebreak; //找到了相应的节点}//找到了相应的节点就返回该节点,若不存在该节点的父节点则返回nullptrreturn root;}bool deleteNodeInSearchBT(TreeNode*root, int k){TreeNode*PatoDelete = nullptr; //用于保存D的父节点TreeNode* toDelete = findNodeInSearchBT(root, k, &PatoDelete); //找到D节点//需要先判断一下是否找到了这个节点,没找到就直接返回falseif (nullptr == toDelete)return false;//D节点没有左子树,或者左右子树都没有 第一第二中情况if (toDelete->le == nullptr){if (k < PatoDelete->value)PatoDelete->le = toDelete->rh; //需要把这个父节点的左节点替换为用来替换的节点elsePatoDelete->rh = toDelete->rh; //这里就是右子树需要被替换了delete toDelete;return true;}//D节点没有右子树第三种情况if (toDelete->rh == nullptr){if (k < PatoDelete->value)PatoDelete->le = toDelete->le; //需要把这个父节点的左节点替换为用来替换的节点elsePatoDelete->rh = toDelete->le; //这里就是右子树需要被替换了delete toDelete;return true;}//D节点左右子树都有,第四种情况auto minInRh = toDelete;TreeNode* minInRhpa = nullptr; //这里用来保存用来替换的节点的父节点while (minInRh->le != nullptr){minInRhpa = minInRh;minInRh = minInRh->le;} //找到X节点,保存了其父节点//其实这里就是对X做了一次删除操作,只不过这个X一定是第一种或者第二种情况minInRhpa->le = minInRh->rh; //这里右子树是否非空是没有关系的;直接对X使用第一或者第二中方法删除,然后用X替换D //需要把用来替换的节点的左右子树换成被删除子树的左右子树,不然就把树给弄断了minInRh->le = toDelete->le;minInRh->rh = toDelete->rh;//一切准备就绪,可以替换了if (k < PatoDelete->value)PatoDelete->le = minInRh; //需要把这个父节点的左节点替换为用来替换的节点elsePatoDelete->rh = minInRh; //这里就是右子树需要被替换了//注意不要忘记释放空间了delete toDelete;//走到了这里说明一切都很顺利,可以返回true了return true;}
三,遍历操作
中序遍历:左子节点--父节点--右子节点
void midTraverse(TreeNode*root){if (root == nullptr) return;midTraverse(root->le); cout << root->value;midTraverse(root->rh);}前序遍历:父节点--左子节点--右子节点
void midTraverse(TreeNode*root){if (root == nullptr) return; cout << root->value;midTraverse(root->le);midTraverse(root->rh);}
后序遍历:左子节点--右子节点--父节点
void midTraverse(TreeNode*root){if (root == nullptr) return;midTraverse(root->le);midTraverse(root->rh); cout << root->value;}
四,二叉树的重建---通过三种遍历方式中的两种重建二叉树
待续。。。。。。
0 0
- 二叉搜索树的插入,删除,遍历操作详解
- 二叉搜索树的搜索、插入、遍历和删除(Java)
- 二叉搜索树的创建、遍历、插入、删除(C++版本)
- 二叉搜索树的插入、删除与遍历
- 二叉树的查找,插入,删除,遍历,最小值,最大值 操作
- 二叉搜索树的插入,删除,查找操作
- 二叉搜索树的查找、插入、删除操作
- 二叉搜索树的插入与删除操作
- 二叉搜索树的插入、查找、删除等操作
- 二叉搜索树的插入,搜索,删除
- 二叉树的各种操作:前序、中序、后序、层序遍历,二叉树搜索、插入和删除等操作
- 二叉搜索树(插入、删除、迭代遍历)
- 二叉搜索树常用算法(创建,遍历,插入,删除)
- Java创建二叉搜索树,实现搜索,插入,删除操作
- 二叉搜索树的查找、插入、删除
- 二叉搜索树的插入和删除
- 二叉搜索树的插入,查找,删除
- 二叉搜索树的插入和删除
- oracle中的表空间
- Android 自定义View
- 一个TextView 显示多种样式的文本
- FreeRTOS中的堆栈设置”与“系统启动文件中堆栈”的关系
- C#索引器
- 二叉搜索树的插入,删除,遍历操作详解
- Centos7服务systemctl命令
- 蓝桥杯2017年第八届模拟题C_C++程序设计本科
- proGuard manual--Introduction翻译
- Java反射机制详解
- C++ 常用小知识解读
- HTML5基础加强css样式篇(CSS3 文本
- ANR问题分析指北
- 单链表的反转