9.查找算法--二叉排序树
1.二叉排序树:插入和删除元素的效率不错,同时查找的效率也不错
. 通过中序遍历,可使得排序变为从小到大的序列:46--67--70--99--104--105--109--111--115
1.1二叉排序树的概念
算法代码:
#include <iostream>
#include <stdlib.h>
#include<string>
#include<cstring>
using namespace std;
int posi = 0;
class Tnode
{
public:string data; Tnode* lnext;Tnode* rnext;
};
bool CreBTree(Tnode *&T) //前序遍历创建二叉树
{//前序遍历输入数组astring a[18] = { "70","67","46","#","#","#","105","104","99","#","#","#","115","111","109","#" ,"#" ,"#" };if (a[posi] == "#"){posi++;T = NULL;}else{ if (posi == 18){return true;}T = new Tnode();//BUG: T = (Tnode*)malloc(sizeof(Tnode));T->data = a[posi++];CreBTree(T->lnext);CreBTree(T->rnext);}}
void MidTree(Tnode* &T)//中序遍历二叉树
{if (T){MidTree(T->lnext);cout << T->data <<" ";MidTree(T->rnext);}
}//二叉排序树
//T为根节点地址;key为要查找的关键字;f指向T的双亲节点,初始值为NULL
//若查找成功,p指向该元素节点,返回true;若失败,p指向查找路径上访问的最后一个节点,返回false
bool Search_BST(Tnode*& T, int key, Tnode*& f, Tnode* &p)
{//string s = to_string(key);if (!T)//查找不成功{p = f; //p获取T的双亲节点return false;}else if (key == atoi(T->data.c_str())) //查找成功,将string转化为int类进行关键字的比较{p = T; //p获取当前节点的位置return true;}else if (key < atoi(T->data.c_str())){return Search_BST(T->lnext, key, T, p);//在左子树继续查找}else {return Search_BST(T->rnext, key, T, p);//在又子树继续查找}
}//键字没找到后,插入带关键字的新节点操作
bool BST_insert(Tnode*& T, int key)
{string str_key = to_string(key);Tnode* f = NULL;Tnode* p=NULL;if (!Search_BST(T, key, f, p))//没找到查找,则插入{//创建节点Tnode* s = new Tnode();s->data = str_key;s->lnext = NULL;s->rnext = NULL;if (!p)//若树为空{*&T = s;}else if (key < atoi(p->data.c_str())){p->lnext = s;}else{p->rnext = s;}return true;}else //找到了{return false;}
}int main()
{Tnode* T;cout << "以前序遍历的方式(先双亲--左子树--右子树)输入二叉树节点,用#表示无叶节点:";CreBTree(T);MidTree(T);cout << endl;if (BST_insert(T, 1)) //TRUE{cout << "Insert SUCCEED" << endl;}else{cout << "Find it" << endl;}MidTree(T);//std::cout << "Hello World!\n";}
输出结果
代码解析:代码中有1个结构体 和 4个函数
1.二叉树节点结构体
结构体用来描述节点
2.前序遍历创建二叉树:bool CreBTree(Tnode *&T) //头节点T 的指针,作为参数
定义一个string 数组a,用来存放节点的data,如果data没有数据,则用“#”代替,之后再用if语句把“#”所在的节点T置为NULL;
若a数组有数据,则申请内存(注意要用new申请内存,用malloc申请内存,string类型的结构体成员会出现内存溢出),用递归的方式对左子树和右子树进行创建。
创建的二叉排序树如下图:
3.前序遍历二叉树:void PreTree(Tnode* &T) //头指针T作为参数
如果存在头结点T;则进行前序遍历
前序遍历规则:(递归进行访问)先双亲节点,再左节点,再右节点
4.查找二叉树中的关键元素节点:bool Search_BST(Tnode*& T, int key, Tnode*& f, Tnode* &p) //若查找成功,p指向该元素节点,返回true;若失败,p指向查找路径上访问的最后一个节点,返回false
输出参数:T:头结点指针; key关键词;f:用于指向T的双亲节点,初始值为NULL;p:的作用是:若查找成功,p指向该元素节点,返回true;若失败,p指向查找路径上访问的最后一个节点,返回false
采用递归的方式进行查找:
- 如果当已经搜索到叶节点了,如果找不到带关键词的节点,此时的叶节点T 都是=NULL的;则用p获取T的双亲节点,返回false。(这也是递归结束标志)
- 否则如果搜索到叶节点,则用p获取当前节点T的地址,返回true
- 否则如果key小于当前节点的data,则在左子树进行递归查找,并将当前节点T作为下一个节点的双亲节点,传入到 f参数位置
- 否则,在右子树进行递归查找,并将当前节点T作为下一个节点的双亲节点,传入到 f参数位置
5.关键字没找到后,插入带关键字的新节点操作:bool BST_insert(Tnode*& T, int key) //
如果未查找到关键字,则返回true
{
创建新节点;
如果树为空,则零新节点作为根节点
否则如果key< 上一个节点p的data(注意这里不是T->data, 而是p->data!!),将新节点s插入左子树
否则将新节点s插入左子树
}
否则搜索到关键字,则返回false
算法优化代码:
通过插入进行创建二叉排序树,而不是通过前序遍历来创建二叉排序树
// SearchBST_2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <stdlib.h>
#include<string>
#include<cstring>
using namespace std;
int posi = 0;
class Tnode
{
public:int data;Tnode* lnext;Tnode* rnext;
};void MidTree(Tnode*& T)//中序遍历二叉树
{if (T){MidTree(T->lnext);cout << T->data << " ";MidTree(T->rnext);}
}//二叉排序树
//T为根节点地址;key为要查找的关键字;f指向T的双亲节点,初始值为NULL
//若查找成功,p指向该元素节点,返回true;若失败,p指向查找路径上访问的最后一个节点,返回false
bool Search_BST(Tnode*& T, int key, Tnode*& f, Tnode*& p)
{//string s = to_string(key);if (!T)//查找不成功{p = f; //p获取T的双亲节点return false;}else if (key == T->data) //查找成功,将string转化为int类进行关键字的比较{p = T; //p获取当前节点的位置return true;}else if (key < T->data){return Search_BST(T->lnext, key, T, p);//在左子树继续查找}else{return Search_BST(T->rnext, key, T, p);//在又子树继续查找}
}//键字没找到后,插入带关键字的新节点操作,返回false;有关键字则返回true,
bool BST_insert(Tnode*& T, int key)
{Tnode* f = NULL;Tnode* p = NULL;if (!Search_BST(T, key, f, p))//找不到{//创建新节点Tnode* s = new Tnode();s->data = key;s->lnext = NULL;s->rnext = NULL;if (!p)//若无根节点{T = s;}else if (key < p->data){p->lnext = s;}else if (key > p->data){p->rnext = s;}elsereturn false;}elsereturn true;
}int main()
{Tnode* T=NULL;int c[9] = {70,105,115,104,67,46,99,111,109};for (int i = 0; i < 9; i++){BST_insert(T, c[i]); //用插入的方式进行二叉排序的创建}cout << "二叉排序为:";MidTree(T);
}
输出结果为:
二叉排序树的节点删除:
比如有如下二叉排序树
中序遍历输出的结果为:46--67--70--99--100--103--104--105--108--110--112--115
有3中删除情况:
1.要删除的节点为叶子节点:叶子节点可以直接删除
2.删除有左子树,无右子树的节点: 删除掉节点67,后面的节点46直接顶上去。如下图所示
4.删除有右子树,无左子树的节点P
3.删除及有左子树,又有右子树的节点105:只需要将104顶到105的位置,103顶到104的位置,只需要将data改变,节点的位置不用改动
算法代码
bool Delete(Tnode*& P)
{Tnode* Q = NULL; //用来存放:待删除节点的双亲节点Tnode* S = NULL; //每次迭代用到的节点//第一种情况,要删除的节点P是叶节点 or 节点P是有左子树,没有右子树if (P->rnext == NULL){Q = P;P = P->lnext; //左子树往上顶free(Q);}else if (P->lnext == NULL)//第二种情况,节点P的只有一个右子树,左子树为NULL, {Q = P;P = P->rnext;//右子树往上顶free(Q);}else//左子树不为NULL, 右子树不为NULL (这段代码太强了){Q = P; S = P->lnext;while (S->rnext){Q = S;S = S->rnext;}P->data = S->data;if (Q != P){Q->rnext = S->lnext;}else{Q->lnext = S->lnext;}free(S);}
}//删除节点,T:根节点,key关键词,
//若不存在要删除的关键字,返回false;存在则删除
bool DeletBST(Tnode*& T, int key)
{if (!T){return false;}else if (key == T->data){return Delete(T);}else if (key < T->data){return DeletBST(T->lnext, key);}else{return DeletBST(T->rnext, key);}
}
代码分析:
1. bool DeletBST(Tnode*& T, int key) //删除带关键词的节点
先递归查找关键词key,如果都一直到叶节点都没有找到key,则返回false;
否则如果找到key,则返回 删除;
否则如果key小于节点T的data,继续递归向左子树找;
否则如果key大于节点T的data,递归向右子树查找
2. bool Delete(Tnode*& P) //找到要删除的关键词节点后,将地址传入,P是要删除的关键词节点的地址
第一种情况:P是有左子树,无右子树,或者 P无左子树,也无右子树;如下图所示,比如要删除67或108
则用Q=P; P=P->lnex; free(Q);
第二种情况:节点P的只有一个右子树,左子树为NULL, 如下图所示:比如要删除20
第三种情况:左子树不为NULL, 右子树不为NULL,如下图所示,比如要删除105 ,其中还包含了两种情况
情况一:100节点存在右子树分支 ----->目的是变为:
情况二:100节点不存右子树分支 ----->目的是变为:
相关代码
else//左子树不为NULL, 右子树不为NULL (这段代码太强了),不通过删除关键词节点,而是采用data值进行传递起到data值覆盖的作用,最后删除{Q = P; S = P->lnext; //S赋值为P的左节点while (S->rnext) //对S的右子树进行迭代{Q = S; //使得Q始终是指向S的双亲节点S = S->rnext;}P->data = S->data; //将S->data直接覆盖掉P->dataif (Q != P) //如果S存在右子树,直接{Q->rnext = S->lnext; //让Q->rnext 指向S->lnext}else //如果S不存在右子树,即不存在104的右子树分支{Q->lnext = S->lnext; //让Q->lnext 指向S->lnext}free(S); //释放S 有两种情况,第一种S处于104位置,第二种S处于100的位置}
}
整体的代码
// SearchBST_2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <stdlib.h>
#include<string>
#include<cstring>
using namespace std;
int posi = 0;
class Tnode
{
public:int data;Tnode* lnext;Tnode* rnext;
};void MidTree(Tnode*& T)//中序遍历二叉树
{if (T){MidTree(T->lnext);cout << T->data << " ";MidTree(T->rnext);}
}//二叉排序树
//T为根节点地址;key为要查找的关键字;f指向T的双亲节点,初始值为NULL
//若查找成功,p指向该元素节点,返回true;若失败,p指向查找路径上访问的最后一个节点,返回false
bool Search_BST(Tnode*& T, int key, Tnode*& f, Tnode*& p)
{//string s = to_string(key);if (!T)//查找不成功{p = f; //p获取T的双亲节点return false;}else if (key == T->data) //查找成功,将string转化为int类进行关键字的比较{p = T; //p获取当前节点的位置return true;}else if (key < T->data){return Search_BST(T->lnext, key, T, p);//在左子树继续查找}else{return Search_BST(T->rnext, key, T, p);//在又子树继续查找}
}//键字没找到后,插入带关键字的新节点操作,返回false;有关键字则返回true,
bool BST_insert(Tnode*& T, int key)
{Tnode* f = NULL;Tnode* p = NULL;if (!Search_BST(T, key, f, p))//找不到{//创建新节点Tnode* s = new Tnode();s->data = key;s->lnext = NULL;s->rnext = NULL;if (!p)//若无根节点{T = s;}else if (key < p->data){p->lnext = s;}else if (key > p->data){p->rnext = s;}elsereturn false;}elsereturn true;
}bool Delete(Tnode*& P)
{Tnode* Q = NULL; //用来存放:待删除节点的双亲节点Tnode* S = NULL; //每次迭代用到的节点//第一种情况,要删除的节点P是叶节点 or 节点P是有左子树,没有右子树if (P->rnext == NULL){Q = P;P = P->lnext; //左子树往上顶free(Q);}else if (P->lnext == NULL)//第二种情况,节点P的只有一个右子树,左子树为NULL, {Q = P;P = P->rnext;//右子树往上顶free(Q);}else//左子树不为NULL, 右子树不为NULL (这段代码太强了),不通过删除关键词节点,而是采用data值进行传递起到data值覆盖的作用,最后删除{Q = P; S = P->lnext; //S赋值为P的左节点while (S->rnext) //对S的右子树进行迭代{Q = S; //使得Q始终是指向S的双亲节点S = S->rnext;}P->data = S->data; //将S->data直接覆盖掉P->dataif (Q != P) //如果S存在右子树,直接{Q->rnext = S->lnext; //让Q->rnext 指向S->lnext}else //如果S不存在右子树,即不存在104的右子树分支{Q->lnext = S->lnext; //让Q->lnext 指向S->lnext}free(S); //释放S 有两种情况,第一种S处于104位置,第二种S处于100的位置}return true;
}//删除节点,T:根节点,key关键词,
//若不存在要删除的关键字,返回false;存在则删除
bool DeletBST(Tnode*& T, int key)
{if (!T){return false;}else if (key == T->data){return Delete(T);}else if (key < T->data){return DeletBST(T->lnext, key);}else{return DeletBST(T->rnext, key);}
}int main()
{Tnode* T=NULL;int t;int c[9] = {70,105,115,104,67,46,99,111,109};for (int i = 0; i < 9; i++){BST_insert(T, c[i]); //用插入的方式进行二叉排序的创建}cout << "二叉排序为:";MidTree(T);cout << "删除关键词:"; cin >> t;DeletBST(T, t);cout << "二叉排序为:";MidTree(T);
}
9.查找算法--二叉排序树相关推荐
- 【查找算法】二叉排序树查找法
本篇文章将介绍二叉排序树的查找算法. 文章目录 何为二叉排序树查找? 查找算法实现 查找效率分析 二叉排序树的插入操作 二叉排序树的生成操作 二叉排序树的删除操作 何为二叉排序树查找? 上篇文章我们学 ...
- 查找算法系列之复杂算法:二叉排序树BST
前面总结了顺序查找,二分查找,分块查找算法,此篇博文将详解介绍二叉排序算法(Binary Sort Tree). 在介绍二叉排序算法之前,首先介绍什么事二叉排序树(BST). 首先从二叉树讲起: 1. ...
- 数据结构排序、查找算法
前言 这是数据结构的实验四的题目. 为了自己能在繁杂的文件中顺利.快速地找到自己熟悉的排序.查找算法代码,故借CSDN平台存放本人写的代码.另外,还请有缘看到此文章的同行们能多多指点. 非常感谢. 1 ...
- 数据结构-常用的查找算法
总第124篇/张俊红 本篇讲讲数据结构里面常用的几个查找算法,数据结构理论篇系列差不多接近尾声了,接下来会分享一些比较特殊的概念,比如KMP.郝夫曼树等等,讲完概念以后会进入刷题阶段.刷题会用Pyth ...
- 数据结构中基本查找算法总结
原文地址:https://www.cnblogs.com/xuzhp/p/4638937.html 基本查找算法 一.查找的基本概念 查找,也可称检索,是在大量的数据元素中找到某个特定的数据元素 ...
- 减治法在查找算法中的应用(JAVA)--二叉查找树的查找、插入、删除
减治法在查找算法中的应用 二叉查找树的查找与插入: 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于或等于它的根节点的值: (2)若右子树不空, ...
- 【数据结构与算法】比较法分析查找算法与查找结构
基本的查找技术: 线性表的查找技术 顺序查找 分块查找 二分查找(折半查找) 插值查找 树表的查找技术 二叉排序树 平衡二叉树 B树(B+树.B-树等) 散列表的查找技术 开散列表 闭散列表 顺序查找 ...
- java二分查找法视频_078-二分查找算法思路图解
2.网上数据结构和算法的课程不少,但存在两个问题: 1)授课方式单一,大多是照着代码念一遍,数据结构和算法本身就比较难理解,对基础好的学员来说,还好一点,对基础不好的学生来说,基本上就是听天书了 2) ...
- 折半查找和二叉排序树的时间性能_详解二叉排序树(基础篇)
前言 我们的线性表有2种,无序线性表和有序线性表. 无序线性表正如其名,它里面的数据是无序的,因为这个表不用维护什么东西,所有它的插入和删除操作的效率也不错..但是,正因为他是无序的,查找起来就很废时 ...
最新文章
- OpenCvSharp_FindContours函数参数详解
- iOS开发那些事-表视图UI设计模式
- Linux操作系统监视NVIDIA的GPU使用情况
- Python中super的用法
- Docker安装RabbitMQ(docker-compose.yml)
- elasticjob 分片策略
- dimension and x,y,z components
- servlet执行流程代码分析
- 安装mysql5.7数据库_使用MySQL的yum源安装MySQL5.7数据库的方法
- 学有小成-php基础语法-06
- 一分钟教你解决前端分流问题
- Nvme协议固态装纯净win10系统
- 实现折叠工具栏CollapsingToolbarLayout(折叠工具栏布局)
- 介绍兴趣爱好的网页html,介绍兴趣爱好的作文5篇
- Vs2008调试慢的问题
- 竖流式沉淀池集水槽设计计算_竖流沉淀池设计计算书.doc
- GrabCut提取图像前景色MATLAB代码实现(含解释说明)
- Could not build wheels for xx which use PEP 517 and cannot be installed directly
- 修复打不开计算机管理,win10系统设备管理器打不开的修复技巧
- 转自周金涛:一辈子有三次暴富机会,最近的一次在2019年?2018年你要怎么做? (2018-02-21 17:49:17)...