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

日照的网站建设关键词林俊杰百度云

日照的网站建设,关键词林俊杰百度云,软件定制开发开什么发票,网上商城电商项目一、概念与性质 二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树结构,具有以下性质: 1)若任意节点的左子树不为空,则左子树上所有节点的值均小于它的根节点的值。 2)若任意…

一、概念与性质

二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树结构,具有以下性质:

1)若任意节点的左子树不为空,则左子树上所有节点的值均小于它的根节点的值。

2)若任意节点的右子树不为空,则右子树上所有节点的值均大于它的根节点的值。

3)任意节点的左子树、右子树均为二叉搜索树。

 二、二叉搜索树的特性


1. 中序遍历有序

      对 BST 进行中序遍历(左 → 根 → 右),结果是一个升序序列。
   - 示例中的树中序遍历结果:`1, 3, 4, 6, 7, 8, 10, 13, 14`

2.性能分析

最优情况下,其为完全二叉树(或者接近完全二叉树),其高度为: log 2 N
最差情况下,二叉搜索树退化为单支树(或者类似单支),如图,其高度为: N
所以综上所述,二叉搜索树增删查改时间复杂度为: O ( N )

3. 高效查找:利用有序性,每次比较可排除一半子树。


4. 动态操作:支持插入、删除、查找操作,时间复杂度与树的高度相关。

三、代码详解

1.树的创建

大致思路和我们之前创建二叉树是一样的,先造结点,之后再组装成树,只不过在这里我们没有再写一个初始化函数的必要了,因为我们可以利用c++的初始化列表在造结点的时候变完成初始化!具体代码如下:

template<class k>
struct BSTNode
{k _key;BSTNode<k>* _left;BSTNode<k>* _right;BSTNode(const k& key):_key(key),_left(nullptr),_right(nullptr){}
};template<class k>
class BSTree
{typedef BSTNode<k> Node;
public:
private:Node* _root = nullptr;
};

2.中序遍历

 这里和之前二叉树中序遍历代码基本一样,只不过我们将其进行了一下封装,详见代码注释!

void InOrder()
{_InOrder(_root);cout << endl;
}
//由于我们之后要遍历这棵树,还要传参,很麻烦,而且_root还是私有成员,我们不如在把这个函数封装一下,利于调用
void _InOrder(Node* root)
{if (root == nullptr){return;}_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);
}

3.插入功能的实现

由搜索二叉树的概念及性质我们知道,对于任意一个节点X来说,其左子树任意结点的值要小于X结点的值,其右子树任意的结点值要大于结点X,我们可以用这个性质进行插入功能的实现。具体方法如下:

1)首先确定要在什么位置插入,由于这是树状结构,如果我们只用一个指针的话即便找到位置也无法插入,因为指针不能倒着走回去,所以在这里我们可以借用之前的双指针法,依次定位追踪父节点和子节点,在结合上文所说的,大于当前结点向右看,小于向左看,从而确定插入的位置 

2)找到插入的位置之后,直接将要插入的数据打包成结点,并根据BSTree的性质,判断插在左子树还是右子树

注:插入值跟当前结点相等的值,可以往右走,也可以往左走,找到空位置,插入新结点。

(要注意的是要保持逻辑一致性,插入相等的值不要一会往右走,一会往左走)

代码实现如下:

bool Insert(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;}}//在cur这个位置插入结点cur = new Node(key);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;
}

 测试一下:

void test1()
{int a[]= { 8, 3, 1, 10, 1, 6, 4, 7, 14, 13 };BSTree<int> bst;for (auto e : a){bst.Insert(e);}bst.InOrder();
}
int main()
{test1();     //输出1 3 4 6 7 8 10 13 14return 0;
}

4.查找功能的实现

查找功能的代码较为简单,利用BStree的性质遍历即可,代码如下:

void Find(const k& key)
{Node* cur = _root;while (cur){if (cur->_key > key){cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}else{return true;}}return false;
}

5.删除功能的实现

要删除的结点X分为如下几种情况:

1)X的左右孩子均为空

2)X的左右孩子中有一个为空

3)X的左右孩子均不为空

解决方法如下:首先找到要删除的结点,

若为第一种情况,则直接删除

若为第二种情况,下一步要判断结点X是左孩子还是右孩子,并将X的父节点与X的子节点链接起来

若为第三种情况, 由于直接删的代价太大,我们还是借助堆的删除的方法,交换法,找左子树的最大结点(最右结点)或者右子树的最小结点(最左结点),将二者交换,之后准备删除工作,首先要判断的是X结点在其父节点的哪一侧,(具体原因详见代码)之后删除结点,并将其父节点与X的子节点连接起来即可

bool Erase(const k& key)
{Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//开始删除if (cur->_left == nullptr){if (cur == _root){_root = cur->_right;}else{if (cur == parent->_right){parent->_right = cur->_right;}else{parent->_left = cur->_right;}}delete cur;}else if (cur->_right == nullptr){if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}delete cur;}else{// 找右子树的最小节点(最左节点)替代Node* replaceparnet = cur;Node* replace = cur->_right;//找最左节点while (replace->_left){replaceparnet = replace;replace = replace->_left;}swap(cur->_key, replace->_key);//此时还要判断一下replace在哪一侧,因为假如replace在右,而parent还有左孩子//此时直接改会导致原来的子树失联if (replaceparnet->_left == replace){//由于此时replace已经是最左结点(其没有左孩子了,但是右孩子不确定),// 所以parent的左孩子和replace的右孩子建立关系replaceparnet->_left = replace->_right;}else{//解释同上,确定好左右关系即可replaceparnet->_right = replace->_right;}delete replace;}return true;}}return false;
}

6.总体代码汇总

 这是bstree.h文件

#pragma once
#include<iostream>
using namespace std;
template<class k>
struct BSTNode
{k _key;BSTNode<k>* _left;BSTNode<k>* _right;BSTNode(const k& key):_key(key),_left(nullptr),_right(nullptr){}
};template<class k>
class BSTree
{typedef BSTNode<k> Node;
public:bool Insert(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;}}//在cur这个位置插入结点cur = new Node(key);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}void InOrder(){_InOrder(_root);cout << endl;}//由于我们之后要遍历这棵树,还要传参,而且_root还是私有成员,我们不如在把这个函数封装一下void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}void Find(const k& key){Node* cur = _root;while (cur){if (cur->_key > key){cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}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->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//开始删除if (cur->_left == nullptr){if (cur == _root){_root = cur->_right;}else{if (cur == parent->_right){parent->_right = cur->_right;}else{parent->_left = cur->_right;}}delete cur;}else if (cur->_right == nullptr){if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}delete cur;}else{// 找右子树的最小节点(最左节点)替代Node* replaceparnet = cur;Node* replace = cur->_right;//找最左节点while (replace->_left){replaceparnet = replace;replace = replace->_left;}swap(cur->_key, replace->_key);//此时还要判断一下replace在哪一侧,因为假如replace在右,而parent还有左孩子//此时直接改会导致原来的子树失联if (replaceparnet->_left == replace){//由于此时replace已经是最左结点(其没有左孩子了,但是右孩子不确定),// 所以parent的左孩子和replace的右孩子建立关系replaceparnet->_left = replace->_right;}else{//解释同上,确定好左右关系即可replaceparnet->_right = replace->_right;}delete replace;}return true;}}return false;}private:Node* _root = nullptr;
};

这是Test.cpp文件

#include "bstree.h"
void test1()
{int a[]= { 8, 3, 1, 10, 1, 6, 4, 7, 14, 13 };BSTree<int> bst;for (auto e : a){bst.Insert(e);}bst.InOrder();bst.Insert(18);bst.InOrder();bst.Insert(5);bst.InOrder();bst.Insert(0);bst.InOrder();bst.Erase(18);bst.InOrder();bst.Erase(0);bst.InOrder();bst.Erase(5);bst.InOrder();for (auto e : a){bst.Erase(e);bst.InOrder();}
}
int main()
{test1();     return 0;
}

7.扩展

在现实中,我们可能很少遇到结点变量只有一个的情况,比如我们想做一个英汉搜索字典,或者统计一下某个单词或字符出现了多少次,那我们便可以加一个模板参数,具体见代码!

这是.h文件

namespace key_value
{template<class k,class v>struct BSTNode{k _key;v _value;BSTNode<k,v>* _left;BSTNode<k,v>* _right;BSTNode(const k& key,const v& value):_key(key),_value(value), _left(nullptr), _right(nullptr){}};template<class k,class v>class BSTree{typedef BSTNode<k,v> Node;public:~BSTree(){Destory(_root);_root = nullptr;}bool Insert(const k& key,const v& value){if (_root == nullptr){_root = new Node(key,value);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这个位置插入结点cur = new Node(key,value);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}void InOrder(){_InOrder(_root);cout << endl;}//由于我们之后要遍历这棵树,还要传参,而且_root还是私有成员,我们不如在把这个函数封装一下void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_key << " " << root->_value << endl;_InOrder(root->_right);}Node* Find(const k& key){Node* cur = _root;while (cur){if (cur->_key > key){cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}else{return cur;}}return nullptr;}bool Erase(const k& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//开始删除if (cur->_left == nullptr){if (cur == _root){_root = cur->_right;}else{if (cur == parent->_right){parent->_right = cur->_right;}else{parent->_left = cur->_right;}}delete cur;}else if (cur->_right == nullptr){if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}delete cur;}else{// 找右子树的最小节点(最左节点)替代Node* replaceparnet = cur;Node* replace = cur->_right;//找最左节点while (replace->_left){replaceparnet = replace;replace = replace->_left;}swap(cur->_key, replace->_key);swap(cur->_value, replace->_key);//此时还要判断一下replace在哪一侧,因为假如replace在右,而parent还有左孩子//此时直接改会导致原来的子树失联if (replaceparnet->_left == replace){//由于此时replace已经是最左结点(其没有左孩子了,但是右孩子不确定),// 所以parent的左孩子和replace的右孩子建立关系replaceparnet->_left = replace->_right;}else{//解释同上,确定好左右关系即可replaceparnet->_right = replace->_right;}delete replace;}return true;}}return false;}void Destory(Node* root){if (root == nullptr){return;}Destory(root->_left);Destory(root->_right);delete root;}private:Node* _root = nullptr;};
}

 这是英汉词典和统计次数的示例

void test2()
{using namespace key_value;key_value::BSTree<string, string> dict;dict.Insert("left", "左边");dict.Insert("right", "右边");dict.Insert("insert", "插入");dict.Insert("string", "字符串");//查字典string str;while (cin >> str){auto ret = dict.Find(str);if (ret){cout << "->" << ret->_value << endl;}else{cout << "无此单词,请重新输入" << endl;}}//数水果string arr[] = { "苹果", "西瓜", "苹果","苹果","苹果", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };key_value::BSTree<string, int> countTree;for (auto& e : arr){BSTNode<string, int>* ret = countTree.Find(e);if (ret == nullptr){countTree.Insert(e, 1);}else{ret->_value++;}}countTree.InOrder();}

这是测试结果

http://www.dtcms.com/wzjs/306659.html

相关文章:

  • 购买域名和空间seo文章是什么意思
  • 刚做外贸最好用哪个网站英文seo是什么
  • 公安科技信息化建设 素材 网站软文广告的案例
  • 学做网站可以赚钱吗门户网站推广方案
  • 国外网站做freelancer品牌推广方案思维导图
  • 子网站用织梦系统网站推广费用一般多少钱
  • 网站名称更改需要多久网络营销策划名词解释
  • 厦门网站建设seo自己在家怎么做跨境电商
  • 微网站 pc端网站开发排名前50名免费的网站
  • 枝江网站建设万网域名交易
  • 祥网站建设营销网络的建设有哪些
  • 天津+交友+网站建设搜索引擎是指什么
  • html5做动态网站建设seo怎么优化关键词排名培训
  • 中国十大建筑设计院广告投放优化师
  • 为什么选择做游戏网站百度指数上多少就算热词
  • 一个人可以做几个网站负责人企业网站的推广方法有哪些
  • 网站建立之间不安全如何解决seo日常工作
  • 做外贸哪个英文网站好计算机培训短期速成班
  • 帮别人做网站 别人违法西安网站seo厂家
  • 响应式网站怎么制作优化排名
  • 做NBA网站目的河南新闻头条最新消息
  • 淄博高端网站如何seo网站推广
  • 关于公路建设的网站网站搜索引擎优化案例
  • 网站备案的重要性能打开各种网站的搜索引擎
  • 做网站用phpcms还是免费注册网页网址
  • 厦门做个网站多少钱营销管理培训课程
  • bob网站建设淘宝友情链接怎么设置
  • 巴彦淖尔专业做网站的武汉seo霸屏
  • 做网站宽度济南全网推广
  • 网站 建设可行性报告如何进行网站的宣传和推广