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

在一个网站下建设多个子网站潍坊网站制作价格

在一个网站下建设多个子网站,潍坊网站制作价格,网站开发的工作经验要求,厦门it做网站最强目录 一、内容说明 二、二叉搜索树 2.1 二叉搜索树概念 2.2 二叉搜索树操作 2.2.1 二叉搜索树的查找 2.2.2 二叉搜索树的插入 2.2.3 二叉搜索树的删除 2.3 二叉搜索树的实现 2.3.1 二叉搜索树的节点设置 2.3.2 二叉搜索树的查找函数 2.3.2.1 非递归实现 2.3.2.2 递…

目录

一、内容说明

二、二叉搜索树

2.1 二叉搜索树概念

2.2 二叉搜索树操作

2.2.1 二叉搜索树的查找 

2.2.2 二叉搜索树的插入

2.2.3 二叉搜索树的删除

2.3 二叉搜索树的实现

2.3.1 二叉搜索树的节点设置

2.3.2 二叉搜索树的查找函数

2.3.2.1 非递归实现

2.3.2.2 递归实现

2.3.3 二叉搜索树的插入函数

2.3.3.1 非递归实现

2.3.4 二叉搜索树的中序遍历

2.3.5 二叉搜索树的删除函数

2.3.5.1 非递归实现当我们需要删除一个节点时找到删除节点,需要记录当前节点的父亲节点,防止删除的当前节点时,防止当前的节点的父亲节点中的指针变为野指针

2.3.6 二叉搜索树代码的整体实现

2.4 二叉搜索树的应用

2.5 二叉搜索树的性能分析

结尾


一、内容说明

二叉树在前面C数据结构阶段已经讲过:非线性表之堆的实际应用和二叉树的遍历-CSDN博客

  1. mapset特性需要先铺垫二叉搜索树,而二叉搜索树也是一种树形结构
  2. 二叉搜索树的特性了解,有助于更好的理解mapset的特性
  3. 二叉树中部分面试题稍微有点难度,在前面讲解大家不容易接受,且时间长容易忘
  4. 有些OJ题使用C语言方式实现比较麻烦,比如有些地方要返回动态开辟的二维数组,非常麻烦。 

此次二叉树是为后面mapset的实现做铺垫,也是对二叉树进行收尾。


二、二叉搜索树

2.1 二叉搜索树概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树


 2.2 二叉搜索树操作

2.2.1 二叉搜索树的查找 
  • a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
  • b、最多查找高度次,走到到空,还没找到,这个值不存在。
2.2.2 二叉搜索树的插入

插入的具体过程如下:

  • a. 树为空,则直接新增节点,赋值给root指针
  • b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

2.2.3 二叉搜索树的删除

首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情 况:

  • a. 要删除的结点无孩子结点
  • b. 要删除的结点只有左孩子结点
  • c. 要删除的结点只有右孩子结点
  • d. 要删除的结点有左、右孩子结点

看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程 如下:

  • 情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点--直接删除
  • 情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点--直接删除
  • 情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题--替换法删除

 2.3 二叉搜索树的实现

2.3.1 二叉搜索树的节点设置
template<class K>
struct BSTreeNode
{K _val;BSTreeNode<K>* _left;BSTreeNode<K>* _right;BSTreeNode(const K& val):_val(val),_left(nullptr),_right(nullptr){}
};

2.3.2 二叉搜索树的查找函数
  1. 从根节点开始查找,若查找值比根节点小,继续向左子树寻找,若查找值比根节点大,继续向右子树寻找。
  2. 最多查找高度次,若查找到空,那么在这棵树中没有这个值,返回false。 
2.3.2.1 非递归实现
template<class K>
class BSTree
{typedef BSTreeNode<K> Node;
public:bool Find(const K& key){Node* cur = _root;while (cur){if (cur->_val > key){cur = cur->_left;}else if(cur->_val < key){cur = cur->_right;}else{return true;}}return false;}
private:// 成员变量Node* _root = nullptr;
};
2.3.2.2 递归实现
template<class K>
class BSTree
{typedef BSTreeNode<K> Node;
public:bool FindR(const K& key)//使用递归查找{return _FindR(_root, key);}
private:bool _FindR(Node* _root,const K& key){if (_root == nullptr)return false;if (_root->_val > key){return _FindR(_root->_left, key);}else if (_root->_val < key){return _FindR(_root->_right, key);}else{return true;}}
private:Node* _root;
};

2.3.3 二叉搜索树的插入函数
  1. 若树为空,创建一个节点,赋值给root。
  2. 若树不为空,按照二叉搜索树的性质查找插入位置,插入新节点
2.3.3.1 非递归实现
//插入
bool Insert(const K& key)
{Node* cur = _root;Node* parent = nullptr;if (_root == nullptr){Node* newnode = new Node(key);_root = newnode;}else{while (cur){if (cur->_val > key){parent = cur;cur = cur->_left;}else if (cur->_val < key){parent = cur;cur = cur->_right;}else{return false;}}Node* newnode = new Node(key);if (parent->_val > key){parent->_left = newnode;}else{parent->_right = newnode;}}return true;
}

2.3.3.2 递归实现

bool InsertR(const K& key)//使用递归插入
{return _InsertR(_root, key);
}bool _InsertR(Node*& root, const K& key)
{if (root == nullptr){root = new Node(key);return true;}if (root->_val < key){return _InsertR(root->_right, key);}else if (root->_val > key){return _InsertR(root->_left, key);}else{return false;}
}

2.3.4 二叉搜索树的中序遍历

二叉树的中序遍历是:先递归遍历左子树,再访问根节点,最后递归遍历右子树。

void InOrder()
{_InOrder(_root);cout << endl;
}void _InOrder(Node* cur)
{	//递归的形式遍历if (cur == nullptr)return;_InOrder(cur->_left);cout << cur->_val << " ";_InOrder(cur->_right);
}

2.3.5 二叉搜索树的删除函数
2.3.5.1 非递归实现
当我们需要删除一个节点时找到删除节点,需要记录当前节点的父亲节点,防止删除的当前节点时,防止当前的节点的父亲节点中的指针变为野指针
bool Erase(const K& key)
{Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_val > key){parent = cur;cur = cur->_left;}else if (cur->_val < key){parent = cur;cur = cur->_right;}else//找到了需要找的值{if (cur->_left == nullptr)//左为空{if (parent == nullptr)//删除结点为根结点{_root = cur->_right;}else{if (parent->_right == cur){parent->_right = cur->_right;}else{parent->_left = cur->_right;}}}//右为空else if (cur->_right == nullptr){if (parent == nullptr)//删除结点为根结点{_root = cur->_left;}else{if (parent->_right == cur){parent->_right = cur->_left;}else{parent->_left = cur->_left;}}}//左右不为空else{Node* parent = cur;Node* leftmax = cur->_left;while (leftmax->_right){parent = leftmax;leftmax = leftmax->_right;}swap(cur->_val, leftmax->_val);if (parent->_left == leftmax){parent->_left = leftmax->_left;}else{parent->_right = leftmax->_left;}cur = leftmax;}delete cur;return true;}}return false;
}

2.3.6.2 递归实现
这里bool _EraseR(Node*& root, const K& key)&的作用也是通过改变当前节点直接改变父亲节点的指向。

bool EraseR(const K& key)//使用递归删除
{return _EraseR(_root, key);
}
bool _EraseR(Node* root, const K& key)
{if (root == nullptr)return false;if (root->_val > key){_EraseR(root->_left, key);}else if (root->_val < key){_EraseR(root->_right, key);}else{Node* del = root;if (root->_left == nullptr){root = root->_right;}else if (root->_right == nullptr){root = root->_left;}else{Node* leftMax = root->_left;while (leftMax->_right){leftMax = leftMax->_right;}swap(root->_key, leftMax->_key);return _EraseR(root->_left, key);}delete del;return true;}
}

2.3.6 二叉搜索树代码的整体实现
namespace lxp
{template<class K>struct BSTreeNode{K _val;BSTreeNode<K>* _left;BSTreeNode<K>* _right;BSTreeNode(const K& val):_val(val),_left(nullptr),_right(nullptr){}};template<class K>class BSTree{typedef BSTreeNode<K> Node;public:BSTree():_root(nullptr){}BSTree(const BSTree<K>& t){_root = Copy(t._root);}BSTree<K>& operator=(BSTree<K> t){swap(_root, t._root);return *this;}~BSTree(){Destroy(_root);}//插入bool Insert(const K& key){Node* cur = _root;Node* parent = nullptr;if (_root == nullptr){Node* newnode = new Node(key);_root = newnode;}else{while (cur){if (cur->_val > key){parent = cur;cur = cur->_left;}else if (cur->_val < key){parent = cur;cur = cur->_right;}else{return false;}}Node* newnode = new Node(key);if (parent->_val > key){parent->_left = newnode;}else{parent->_right = newnode;}}return true;}bool Find(const K& key){Node* cur = _root;while (cur){if (cur->_val > key){cur = cur->_left;}else if(cur->_val < key){cur = cur->_right;}else{return true;}}return false;}bool Erase(const K& key){Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_val > key){parent = cur;cur = cur->_left;}else if (cur->_val < key){parent = cur;cur = cur->_right;}else//找到了需要找的值{if (cur->_left == nullptr)//左为空{if (parent == nullptr)//删除结点为根结点{_root = cur->_right;}else{if (parent->_right == cur){parent->_right = cur->_right;}else{parent->_left = cur->_right;}}}//右为空else if (cur->_right == nullptr){if (parent == nullptr)//删除结点为根结点{_root = cur->_left;}else{if (parent->_right == cur){parent->_right = cur->_left;}else{parent->_left = cur->_left;}}}//左右不为空else{Node* parent = cur;Node* leftmax = cur->_left;while (leftmax->_right){parent = leftmax;leftmax = leftmax->_right;}swap(cur->_val, leftmax->_val);if (parent->_left == leftmax){parent->_left = leftmax->_left;}else{parent->_right = leftmax->_left;}cur = leftmax;}delete cur;return true;}}return false;}void InOrder(){_InOrder(_root);cout << endl;}void _InOrder(Node* cur){	//递归的形式遍历if (cur == nullptr)return;_InOrder(cur->_left);cout << cur->_val << " ";_InOrder(cur->_right);}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);}private:Node* Copy(Node* root){if (root == nullptr)return nullptr;Node* copyroot = new Node(root->_val);copyroot->_left = Copy(root->_left);copyroot->_right = Copy(root->_right);return copyroot;}void Destroy(Node*& root){if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;root = nullptr;}bool _EraseR(Node* root, const K& key){if (root == nullptr)return false;if (root->_val > key){_EraseR(root->_left, key);}else if (root->_val < key){_EraseR(root->_right, key);}else{Node* del = root;if (root->_left == nullptr){root = root->_right;}else if (root->_right == nullptr){root = root->_left;}else{Node* leftMax = root->_left;while (leftMax->_right){leftMax = leftMax->_right;}swap(root->_key, leftMax->_key);return _EraseR(root->_left, key);}delete del;return true;}}bool _InsertR(Node*& root, const K& key){if (root == nullptr){root = new Node(key);return true;}if (root->_val < key){return _InsertR(root->_right, key);}else if (root->_val > key){return _InsertR(root->_left, key);}else{return false;}}bool _FindR(Node* _root,const K& key){if (_root == nullptr)return false;if (_root->_val > key){return _FindR(_root->_left, key);}else if (_root->_val < key){return _FindR(_root->_right, key);}else{return true;}}private:Node* _root;};
}


2.4 二叉搜索树的应用

1. K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。

        比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:   

  • 以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树
  • 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

2. KV模型:每一个关键码key,都有与之对应的值Value,即的键值对。该种方式在现实生活中非常常见:

  • 比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文就构成一种键值对;
  • 再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是就构成一种键值对。
template<class K, class V>
struct BSTreeNode
{BSTreeNode<K, V>* _left;BSTreeNode<K, V>* _right;K _key;V _value;BSTreeNode(const K& key, const V& value):_key(key), _value(value), _left(nullptr), _right(nullptr){}
};template<class K, class V>
class BSTree
{typedef BSTreeNode<K, V> Node;
public:	bool Insert(const K& key, const V& value){// 树为空则,该节点为根if (_root == nullptr){_root = new Node(key, value);return true;}Node* cur = _root;Node* prev = nullptr;while (cur){prev = cur;// 当当前节点的值大于要插入的值,那么向左找if (cur->_key > key){cur = cur->_left;}// 当当前节点的值小于要插入的值,那么向右找else if (cur->_key < key){cur = cur->_right;}// 二叉搜索树不允许相同的值存在,当这个值已经存在过了,那么返回false,即插入失败else{return false;}}if (prev->_key > key){prev->_left = new Node(key, value);return true;}else{prev->_right = new Node(key, value);return true;}return false;}	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* cur = _root;Node* prev = nullptr;// 找到需要删除的节点while (cur){if (cur->_key > key){prev = cur;cur = cur->_left;}else if (cur->_key < key){prev = cur;cur = cur->_right;}else{break;}}// 当当前根节点的左树为空时,那么链接右边if (cur->_left == nullptr){if (cur == _root){_root = cur->_left;delete cur;return true;}else{if (prev->_left == cur)prev->_left = cur->_right;elseprev->_right = cur->_right;delete cur;cur = nullptr;return true;}}// 当当前根节点的右树为空时,那么链接左边else if (cur->_right == nullptr){if (cur == _root){_root = cur->_left;delete cur;return true;}else{if (prev->_left == cur)prev->_left = cur->_left;elseprev->_right = cur->_left;delete cur;cur = nullptr;return true;}}else{prev = cur;Node* del = cur->_right;while (del->_left != nullptr){prev = del;del = del->_left;}swap(del->_key, cur->_key);if (prev->_left == del)prev->_left = del->_right;elseprev->_right = del->_right;delete del;del = nullptr;return true;}return false;}void InOrder(){_InOrder(_root);cout << endl;}~BSTree(){Destory(_root);}BSTree() {}BSTree(const BSTree<K, V>& T){_root = Copy(T._root);}BSTree<K, V>& operator=(BSTree<K, V> T){swap(_root, T._root);return *this;}private:Node* Copy(Node* Troot){if (Troot == nullptr)return nullptr;Node* root = new Node(Troot->_key);root->_left = Copy(Troot->_left);root->_right = Copy(Troot->_right);return root;}void Destory(Node*& root){if (root == nullptr)return;Destory(root->_left);Destory(root->_right);delete root;root = nullptr;}bool _InsertR(Node*& root, const K& key){if (root == nullptr){root = new Node(key);return true;}if (root->_key > key)return _InsertR(root->_left, key);else if (root->_key < key)return _InsertR(root->_right, key);// 出现相同的数字,返回falseelsereturn false;}void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << ':' << root->_value << endl;_InOrder(root->_right);}Node* _root = nullptr;
};void TestBSTree()
{BSTree<string, string> dict;dict.Insert("insert", "插入");dict.Insert("erase", "删除");dict.Insert("left", "左边");dict.Insert("string", "字符串");dict.InOrder();string str;while (cin >> str){auto ret = dict.Find(str);if (ret){cout << str << ":" << ret->_value << endl;}else{cout << "单词拼写错误" << endl;}}string strs[] = { "苹果", "西瓜", "苹果", "樱桃", "苹果", "樱桃", "苹果", "樱桃", "苹果" };// 统计水果出现的次BSTree<string, int> countTree;for (auto str : strs){auto ret = countTree.Find(str);if (ret == NULL){countTree.Insert(str, 1);}else{ret->_value++;}}countTree.InOrder();
}

2.5 二叉搜索树的性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。

对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。

但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:

最优情况下,二叉搜索树为完全二叉树(或者接近完全二叉树),其平均比较次数为:logN(log以2为底N的对数)

最差情况下,二叉搜索树退化为单支树(或者类似单支),其平均比较次数为:N

问题:如果退化成单支树,二叉搜索树的性能就失去了。那能否进行改进,不论按照什么次序插 入关键码,二叉搜索树的性能都能达到最优?那么我们后续章节学习的AVL树和红黑树就可以上场了。 


结尾

如果有什么建议和疑问,或是有什么错误,希望大家可以在评论区提一下。
希望大家以后也能和我一起进步!!
如果这篇文章对你有用的话,请大家给一个三连支持一下!!

谢谢大家收看🌹🌹

http://www.yayakq.cn/news/364167/

相关文章:

  • qingdao城乡住房建设厅网站广告设计专业学校
  • 山东信达建设有限公司网站手机参数网
  • 企业网站建设前网站目的需明确建设企业网站技术解决方案
  • 电商优惠券网站 建设大型网页设计服务公司
  • 广西住房和城乡建设网站视频专栏郑州千锋教育培训机构怎么样
  • 网站做最优是什么意思787878域名
  • 网站怎样做漂浮南宁专业做网站
  • 网站建设深圳给原码Python能开发WordPress
  • 陕西煤业化工建设集团网站深圳设计公司电话
  • 中国城市建设网网站wordpress 4.7.3 id
  • 有域名怎样做网站博客发布 网站模版
  • html 网站源码 卖手机做网站外包大学生
  • 自己做视频网站犯法农业门户网站模板
  • 做网站图片代码怎么居中网站建设的成本有哪些内容
  • 网站开发技术网站模板wordpress粘贴word
  • Seo建设网站的步骤那个网站专门做二手衣服的
  • 建设银行网站登录没反应电商平台商户
  • 中国空间站什么时候建成网站建设的特征
  • 网站建设的基本流程包括企业手机网站建设资讯
  • 使用php的大型网站甘德县公司网站建设
  • 网站添加搜索做清洁找什么网站
  • 辽宁手机版建站系统开发wordpress编辑文字内容
  • 江门做网站哪家好小语种外贸建站
  • 南宁隆安网站建设网站开发swf素材
  • 免费无广告建站网站创建的基本流程
  • 聊城网站建设动态如何查询网站后台地址
  • 怎么给网站做logo泊头公司做网站
  • 海宁市住房和城乡规划建设局网站辽宁建设工程造价信息网官网
  • 仓库管理系统网站建设自建房外观设计网站推荐
  • 网站设计的流程资源平台