当前位置: 首页 > news >正文

中国建设网站首页无锡seo公司哪家好

中国建设网站首页,无锡seo公司哪家好,站长工具 怎么做网站地图,封面型网站怎么做的文章目录二叉搜索树的概念二叉搜索树的实现二叉搜索树的节点构造函数拷贝构造函数赋值运算符重载析构函数插入函数非递归实现递归实现删除函数非递归实现递归实现查找函数非递归实现递归实现二叉搜索树的性能分析二叉搜索树的完整代码二叉搜索树的概念 二叉搜索树又称二叉排序…

文章目录

  • 二叉搜索树的概念
  • 二叉搜索树的实现
    • 二叉搜索树的节点
    • 构造函数
    • 拷贝构造函数
    • 赋值运算符重载
    • 析构函数
    • 插入函数
      • 非递归实现
      • 递归实现
    • 删除函数
      • 非递归实现
      • 递归实现
    • 查找函数
      • 非递归实现
      • 递归实现
  • 二叉搜索树的性能分析
  • 二叉搜索树的完整代码

二叉搜索树的概念

二叉搜索树又称二叉排序树或二叉查找树,它可以是空树,也可以是具备以下性质的二叉树:
1: 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值.

2: 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值.

3: 它的左右子树也分别为二叉搜索树.
在这里插入图片描述

注意:
二叉搜索树具备升序和排序的功能.因为根据二叉搜索树的性质,它一般是按照中序遍历的.

二叉搜索树的实现

二叉搜索树的节点

二叉搜索树有三个成员变量分别为: 左指针,右指针,节点值.
为了能够匹配储存多种数据类型,我们选择类模板.

 template < class K >struct BSTreeNode{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode( const K& key = K() ) //初始化列表:_left(nullptr),_right(nullptr),_key(key)}

构造函数

二查搜索树的成员只有_root根节点,所以只需要对根节点_root构造.

BSTree()
:_root(nullptr)
{
}

注意:
如果我们只写了拷贝构造没写构造函数,此时编译器就不会生成默认构造函数,即使在我们给了缺省值的情况下.

拷贝构造函数

拷贝构造的主要思路就是按照前序遍历的思想,拷贝出一个根节点后依次对它的左子树,右子树进行遍历.

//拷贝构造
BSTree( const BSTree<K>& t )
{_root = _Copy(t._root);
}//拷贝函数
Node* _Copy(Node* root )
{//如果根节点为nulptr,则直接返回到上一层函数栈帧.if( root == nullptr ) {return nullptr;}//遍历左右子树,并与根左右指针建立关系.Node* CopyRoot = new Node(root->_key );CopyRoot->_left = _Copy(root->_left);CopyRoot->_right = _Copy(root->_right);//左右子树递归完毕后返回到第一层函数栈帧.return CopyRoot;}

注意:
因为递归实参要传对象中的private成员,但是在类外却访问不到对象的私密成员,所以在类外我们很难传参.所以在用到递归的函数中,我们都将拷贝构造,插入等成员函数放在private位置,另外我们可以在public位置写一个成员函数来调用对象的内置成员传参,这样可以在类外调用拷贝构造了.(以下成员函数不另作说明)

赋值运算符重载

当我们显示写了拷贝构造就可以考虑现代写法,利用传值传参调用的拷贝构造产生的
BSTree类型的二叉搜索树与旧的二叉搜索树交换_root就行.

BSTree<K>& operator=( BSTree<K> t )
{swap( _root,t._root);return *this;
}

析构函数

二叉搜索树的析构函数本质上是后序遍历,排除root为nullptr后,依次遍历左右子树,再对根节点进行删除.

  ~BSTree()
{_Destroy(_root);  
}
Node* _Destroy( Node*& root )  //为了让形参的改变能影响到实参,故而取引用.
{if( root == nullptr ){return nullptr;    // 返回上一次函数栈帧.}_Destroy(root->_left);_Destroy(root->_right);delete(root);//当根节点删除完毕后,BSTree的_root为空.return nullptr;
}

插入函数

非递归实现

1: 如果为空树,直接在根节点处插入新节点.
 
2: 如果不为空,那么我们便要先查找要插入的位置.
(a):如果所给值key大于该节点值,那么cur就右遍历,并记录当前cur
的parent.
(b):如果所给值key小于该节点值,那么cur就向左遍历,并记录当前cur的parent.
( c ): 如果所给值key等于该节点值,那么表明插入的节点已经有了,不需要再插入了.

3:然后插入位置后与cur的parent的左右指针建立联系.

bool Insert( const K& key )
{if( _root == nullptr ){_root = new(root);return true;}Node* parent = nullptr;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;} }cur = new Node(key);           //插入key构造的新节点if( parent->_key < key )      //走到这,parent的左右子树一定为空.{parent->_right = cur;                                       //将新节点与parent的右指针相连.}else{parent->_left = cur;}retrn true;
}

递归实现

递归实现本质上类似与前序遍历思想.
1: 如果根为空,就在根处插入新节点.

2: 如果根不为空,比较key与当前节点root的值
( a ):如果key大于当前节点值,就递归root的右子树.
( b ):如果key小于当前节点值,就递归root的左子树.
( c) : 如果key等于当前节点值,就返回错误.(插入失败)

bool _InsertR(Node*& root,const K& key )
{if( root == nullptr){root = new Node(key);return true;}if( root->_key > key ){return _Insert(root->_left,key);}else if( root->_key < key ){return _Insert( root->_right,key);}else{return false;} }

删除函数

非递归实现

查找指定值
二叉搜索树删除时,首先要从根节点循环查找指定值,直到cur为空.
1:如果指定值大于当前结点值,则从当前结点的右子树寻找,并记录当前结点即为父节点.
2: 如果指定值小于当前结点值,则从当前结点的左子树寻找,并记录当前结点即为父节点.
删除指定值
( a )直接删除:
当删除结点只有一个孩子且左为空:
1:如果删除结点cur为根结点,则删除结点的右孩子就为根结点.
2:如果删除结点cur不为根结点,则直接让父结点指向min的右孩子
在这里插入图片描述
在这里插入图片描述

当删除结点只有一个孩子且右为空:
1:如果删除结点cur为根结点,则删除结点的左孩子就为根结点.
2:如果删除结点不为根结点,则直接让父结点指向右孩子

在这里插入图片描述

在这里插入图片描述

然后根据上述情况直接对删除结点删除.
( b )替换法删除:
当:删除结点左右都不为空,此时便要寻找右子树的最左结点替换结点值后删除,这样删除后可以保持二叉搜索树左子树的结点都比根结点小,右子树的结点都比根结点大的特性..

注意
对于替换发删除:
 
(a):寻找右子树的最左结点.用cur记录要删除结点,根据右子树的最左结点必为空的特性下不断向左循环查找,并且我们要记录右子树最左节点的父节点,便于父节点链接最左节点的孩子结点.
(b):替换删除.在寻找到右子树的最左结点的情况下,我们最终删除的是与cur交换过结点值的替换结点min,但是我们要先确定min结点在minParent的左边还是右边,这样才能方便与min的孩子连接(min的孩子一定为右结点),这种处理同时也包含了min无孩子这一情况.

如果min在minParent的左边,则需要将minParent的左指针指向min的右孩子后将cur与min的值替换删除.

如果min在minParent的右边,及删除结点右子树的最左结点为空的情况下,此时min就是右子树的最左结点,如果minParent初始化为nullptr,则无法进入循环寻找右子树的最左节点,所以可以将minParent初始化为cur.然后将minParent的右指针指向min的右孩子后将cur与min的值替换删除.

重要图示:
min在minParent的左边.
在这里插入图片描述
在这里插入图片描述

min在minParent的右边;

在这里插入图片描述

在这里插入图片描述

代码实现:

bool Erase( const K& key )
{Node* parent = nullptr;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                   //找到删除结点{ if( cur->_left == nullptr  ) //当cur的左孩子为空{ if( cur == _root )  //如果删除结点为根结点,则直接让_root指向cur的右孩子{_root = cur->_right;              } else{if( parent->_right == cur ){parent->_right = cur->_right; }else{parent->_left = cur->_right;}}    else if( cur->_right == nullptr )//当cur的右孩子为空{ if( cur == _root ) {_root = cur->_left;} else {if ( parent->_left == cur  ){     parent->_left = cur->_left;}else{parent->_right = cur->_left;}  }delete cur;       //删除结点return true;  }else            //左右都不为空{//替换法删除//Node* minParent = nullptr; 不能初始化为nullptr;Node* minParent = cur; Node* min =  cur->_right;while( min ->_left ){minParent = min;min = min->_left;    }//判断min在minParent的左边还是右边.if( minParent->_right == min ){minParent->_right = min->_right;}else{minParent->_left = min->_right;}swap( min->_key,cur->_key );delete min;     }  
//走到这里,说明指定结点删除完毕.return true;
}
}
//如果出了循环没有删除,二叉搜索树已经找完了.return false;
}

递归实现

1:首先对空树进行判断,如果为空,则返回false;

2: 根据所给结点值递归查找删除结点.
如果所给值大于当前结点值,就在当前结点的右子树递归查找.
如果所给值小于当前结点值,就在当前结点的左子树递归查找.
3: 删除指定结点
找到删除结点后,此时便要让删除结点父节点与删除节点孩子连接,此时有两种综合情况:
( a ):当删除结点只有一个孩子的情况下:
如果删除结点只有左孩子,则删除结点的父结点与删除结点左孩子连接.
如果删除结点只有右孩子,则删除结点的父节点与删除结点右孩子连接.
( b ): 当删除结点左右孩子都存在:
从删除结点的右子树的最左结点寻找替换点.
交换删除结点与替换点min,从删除结点的右子树递归删除.

//针对递归,公有成员函数调用私有
bool EraseR( const K& key )
{return _EraseR(_root,key );
}bool _EraseR( Node*& root,const K& key )
{     //寻找删除结点if( root == nullptr ){ return false;}if( root->_key < key ){ return _EraseR( root->_right,key );}else if( root -> _key > key ){return _EraseR ( root->_left,key);}else  //找到了,连接关系后删除{Node* del = root;if( root->_left == nullptr ){root = root->_right;  //此时的root实际上是删除结点父节点的右指针.}else if ( root->_right == nullptr ){ root = root->_left;  //此时root实际上是删除结点父节点的左指针.}else{Node* min = root->_right;while( min->_left )  //从右子树的最左结点开始寻找.{min = min->left;                }//走到这,说明已经找到了替换点.swap(root->_key,min->_key );//替换完成后,此时要删除替换点,再次复用递归.return _EraseR( root->_right,key );               }delete del;return true;}}

注意:
在找到替换结点(min)后,由于替换结点min的左孩子必为nullptr,所以再度递归EraseR时,编译器就不会再度走删除

查找函数

非递归实现

非递归查找与插入前的查找几乎一致:

bool Find(const K& key){Node* cur = _root;//如果二叉树不为空的情况下。while (cur){if (cur->_key < key){//parent = cur;cur = cur->_right;}else if (cur->_key > key){//parent = cur;cur = cur->_left;}//找到相等的,return true就行。。else{return true;}}//在循环里都没找到,说明找不到了。return false;}

递归实现

1: 如果为空,则返回false;

2: 如果指定值大于当前结点值,则递归从前结点的右子树寻找.

3: 如果指定值小于当前结点值的,则递从当前结点的左子树寻找.

4: 如果直接值等于当前结点值,就说明查找值已经找到了,返回true.

bool  FindR( const K& key )
{return _FindR( _root,key );
}bool _FindR( Node* root, const K& key )
{if( root = nullptr ){return false;}if( root->_key < key ) //递归从右子树开始查找{return _FindR( root->right,key );}else if ( root->_key > key ) //递归从左子树开始查找{ return _FindR( root->_left,key );}else       //走到这说明找到了.{return true;}}

二叉搜索树的性能分析

最优情况下,二叉搜索树为完全二叉树(或者接近为完全二叉树),时间复杂度为log2N.
在这里插入图片描述

最差情况下,二叉搜索树退化为单支树(或者为单支) ,时间复杂度为O(N);
在这里插入图片描述

二叉搜索树的完整代码

struct BSTreeNode
{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key):_left(nullptr), _right(nullptr), _key(key){}
};
template<class K>
class BSTree
{typedef BSTreeNode<K> Node;
public://注意,如果写了拷贝构造的话,编译器就不会主动生成默认构造函数,而我们有没有写,这是就会没有合适的默认构造,即使我们//在内置成员给上缺省值。BSTree(){}//拷贝构造BSTree(const BSTree<K>& t){_root = _Copy(t._root);}//析构~BSTree(){_Destroy(_root);}bool Inseret(const K& key){if (_root == nullptr){_root = new Node(key);return true; }Node* parent = nullptr;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;}}//找到之后new一个结点给它,可是在插入一个数之后,除了函数作用域cur就被销毁了,编译器找不到//这个结点了,所以链式结构,我们还得找到这个空的父亲的位置。cur = new Node(key);if( parent->_key < key ){parent->_right = cur;}else{parent->_left = cur;}return true;}bool Find(const K& key){Node* cur = _root;//如果二叉树不为空的情况下。while (cur){if (cur->_key < key){//parent = cur;cur = cur->_right;}else if (cur->_key > key){//parent = cur;cur = cur->_left;}//找到相等的,return true就行。。else{return true;}}//在循环里都没找到,说明找不到了。return false;}bool Erase(const K& key){Node* parent = nullptr;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{if (cur->_left == nullptr){//如果删除结点为跟结点if (cur == _root){_root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}//替换后删除delete cur;cur = nullptr;}else if (cur->_right == nullptr){if (cur == _root){_root = cur->_left;}else{if (cur == parent->_right){parent->_right = cur->_left;}else{parent->_left = cur->_left;}}//替换后删除。delete cur;}//删除的结点左右都不为空。//替换法删除。else{//如果设置MinParent的初始值为空的情况下,如果删除的结点的为root,//那么替换点要找右树的最左节点,此时min-left为空,不会进入1循环,//anemic在MinParent->_left会导致访问空指针程序崩溃。Node* MinParent = cur;Node* min = cur->_right;while (min->_left){MinParent = min;min = min->_left;} swap(min->_key, cur->_key);if (MinParent->_left == min){MinParent->_left = min->_right;}else{MinParent->_right = min->_right;}delete min;min = nullptr;}return true;}}return false;}bool FindR( const K& key ){return 	_FindR(_root,key);}bool  InsertR(const K& key){return _InsertR(_root, key);}bool  EraseR(const K& key){return _EraseR(_root, key);}void Inorder(){_Inorder(_root);}//显示写了拷贝构造就可以考虑使用现代写法,//传值传参,t是实参的临时拷贝,此时不需要加const因为临时拷贝对于实参本身没有任何的关系。//此时能加const对于类型,但是赋值过程中const BSTree<int>类型t已经发生改变了,//引用加const除了考虑权限还得考虑是否改变,类型加cosnt只需要考虑拷贝。BSTree<K>& operator=(  BSTree<K> t){swap(_root,t._root);//通过this指针获取BSTree<int>类型。return *this;}private://析构函数//为了让_root=nullptr为空形参改变实参,取引用。Node* _Destroy(Node*& root){//如果root为nullptr;if (root == nullptr){return nullptr;}//如果不为nullptr_Destroy(root->_left);_Destroy(root->_right);delete root;}private:Node* _root = nullptr;//拷贝构造:Node* _Copy(Node* root){if (root == nullptr){return nullptr; }//生成一个结点Node* CopyRoot = new Node(root->_key);//与结点的左右指针建立关系。CopyRoot->_left = _Copy(root->_left);CopyRoot->_right = _Copy(root->_right);return CopyRoot;}//查找的非递归玩法。bool _FindR(Node* root, const K& key){if (root == nullptr){return false;}if (root->_key < key){return  _FindR(root->_right, key);}else if (root->_key > key){return _FindR(root->_left, key);}//走到这,说明找到了else{return true;}}//删除的Erase玩法:bool _EraseR(Node*& root, const K& key){if (root == nullptr){return false;}//删除前先判断值的大小,以便确定删除的位置。if (root->_key < key){return _EraseR(root->_right,key);}else if (root->_key > key){return _EraseR(root->_left,key);}//如果相等就说明找到了,删除。else{Node* del = root;if (root->_left == nullptr){//与被删除的结点建立关系。root = root->_right;}else if (root->_right == nullptr) {    //与被删除的结点建立关系。root = root-> _left;}//删除的第三种情况,删除结点的_left和_right都不为nullptr问题。else{//寻找替换点,在右树的最左节点中寻找。Node* min = root->_right;  while (min->_left){min = min->_left;}//跳出来,说明已经找到了。swap(root->_key, min->_key);//转换为在root的右子树进行递归删除。return _EraseR(root->_right, key);}delete del;return true;}}//插入的递归玩法:bool _InsertR(Node*& root, const K& key){//找到了。if (root == nullptr){root = new Node(key);return;}if (root->_key < key){return _InsertR(root->_right, key);}else if (root->_key > key){return _Insert(root->_left, key);}else{return false;}}void _Inorder(Node* root){if (root == nullptr){return;}_Inorder(root->_left);cout << root->_key << " ";_Inorder(root->_right);}};
http://www.lbrq.cn/news/2655163.html

相关文章:

  • 网站上的图片做多大百度竞价效果怎么样
  • 搜一搜搜索如何优化seo技巧
  • 网站没有备案怎么做支付营销模式有几种
  • 三一国际网站设计搜狗搜索引擎推广
  • 网站全屏轮播代码新手做外贸怎么入门
  • 高校对网站建设的重视拉新app推广接单平台
  • 黄埔网站建设公司南宁seo外包要求
  • 企业网站开发的设计流程优化大师免费版下载
  • html5网站开发公司百度推广登录平台网址
  • 对网站建设的维护百度识图查图片
  • web.py做网站百度搜索引擎优化怎么做
  • 做个商城网站怎么做便宜吗网络营销活动案例
  • 国贸做网站的公司网站如何做seo推广
  • 日本手做网站深圳最好seo
  • 网站建设行业市场规模百度推广助手电脑版
  • 深圳市住房和建设工程交易网站seo源码
  • 浏览器怎么打开网站服务器设置b站推广链接
  • 手机苗木网站源码常州seo招聘
  • 百度网址名称是什么商品seo关键词优化
  • 青岛哪个网站建设公司价格低还能好一些网络营销的方式有几种
  • 怎样做网站的快捷方式网络营销推广策略有哪些
  • 赣州网站设计哪家强简述网站建设的流程
  • 哈尔滨房地产网站建设打开一个网站
  • 黄页引流推广网站软件免费百度指数
  • 建网站建设的基本流程今日热搜第一名
  • 网络代理是什么意思班级优化大师头像
  • 网站关键词优化到首页难度软件推广赚佣金渠道
  • 自搭建网站百度竞价代运营公司
  • 嘉定区网站建设公司营销网站建设大概费用
  • wordpress去除缓存石家庄百度seo
  • DBAPI 实现不同角色控制查看表的不同列
  • ES 调优帖:Gateway 批量写入性能优化实践
  • 容器技术基础与实践:从镜像管理到自动运行配置全攻略
  • C++11中的移动语义
  • FreeRTOS源码分析五:资源访问控制(一)
  • 使用 ast-grep 精准匹配指定类的方法调用(以 Java 为例)