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

wordpress建教学网站大连品牌网站建设公司

wordpress建教学网站,大连品牌网站建设公司,友情链接推广,wordpress php 模板目录 1.非递归版本 1.1查找 1.2插入 1.3删除 2.递归版本 2.1查找 2.2插入 2.3删除 1.非递归版本 1.1查找 从根节点开始,根据键值的比较进行查找 所给键值比节点键值大,到节点的右子树去寻找; 所给键值比节点键值小,到节点…

目录

1.非递归版本

1.1查找

1.2插入

1.3删除

2.递归版本

2.1查找

2.2插入

2.3删除


 

1.非递归版本

1.1查找

从根节点开始,根据键值的比较进行查找

所给键值比节点键值,到节点的右子树去寻找;

所给键值比节点键值,到节点的左子树去寻找;

所给键值与节点键值相等,就找到了(二叉搜索树默认不存在两个及以上键值相同的节点)

找不到,就会来到空树

Node* find(const K& key){//树为空if (!_root)return nullptr;//树不为空Node* cur = _root;while (cur){if (key > cur->_key){cur = cur->_right;}else if (key < cur->_key){cur = cur->_left;}else{return cur;}}//找不到return nullptr;
}

从根节点开始循环查找,节点为空就是循环结束条件

1.2插入

从根节点开始,根据键值的比较寻找合适的插入位置

所给键值比节点键值,到节点的右子树去寻找;

所给键值比节点键值,到节点的左子树去寻找;

一定能找到, 且插入位置是空树

bool Insert(const K& key){//树为空if (!_root){_root = new Node(key);return true;}//树不为空,根据key的大小找到相应位置//插入位置为空,提前保存其父亲节点Node* parent = _root;Node* cur = _root;while(cur){if (key > cur->_key){parent = cur;cur = cur->_right;}else if (key < cur->_key){parent = cur;cur = cur->_left;}else//相等的值不能插入{return false;}}//找到恰当位置了,插入位置一定为空Node* newnode = new Node(key, value);if (key > parent->_key)parent->_right = newnode;elseparent->_left = newnode;return true;
}

树不为空时,位置的查找与前面讲的节点的查找差不多,只是,找到插入位置后,我们不仅需要创建一个新节点来存储键值,更重要的是还要将所创建的节点连接到树上去,所以

需要提前保存当前节点的父亲节点,(父亲节点初始值可与当前节点一致)

//这种插入方式就有风险
if (parent->_left == cur)parent->_left = newnode;
else parent->_right = newnode;

正如注释所言,这种插入方式有风险,因为如果父亲节点没有孩子节点,所插入节点的插入位置就会受这种方式影响,

如:parent 键值 为 10 ,cur(新创建的节点) 键值 为 14,就会将其插入到左子树去

所以找到恰当位置之后,我们还需根据键值的比较来链接新的节点

1.3删除

从根节点开始,根据键值的比较寻找要删除的树节点

所给键值比节点键值,到节点的右子树去寻找;

所给键值比节点键值,到节点的左子树去寻找;

找不到就来到空树

	//非递归删除bool Erase(const K& key){//树为空if (!_root)return false;//树不为空//删除某节点时,需要更新其父亲节点的指针指向Node* parent1 = _root;Node* cur = _root;while (cur){if (key > cur->_key){parent1 = cur;cur = cur->_right;}else if (key < cur->_key){parent1 = cur;cur = cur->_left;}else//找到了{//...}}//没找到return false;}

树不为空时,以循环的方式查找要删除的节点,节点为空就是循环结束条件

当然,找到节点之后我们还不能直接删除该节点,还需更新其父亲节点的链接关系

所以需要提前保存其父亲节点的初始值(父亲节点初始值可与当前节点一致)

删除需要分情况进行讨论

//保存删除节点
Node* del = cur;
//先更新节点链接关系
//左为空
if (!cur->_left){if (parent1 == cur){_root = cur->_right;}//此更新关系建立在parent1和 cur 不同的情况下if (parent1->_left == cur){parent1->_left = cur->_right;}else{parent1->_right = cur->_right;}
}//右为空
else if (!cur->_right){//...
}//都不为空,替换法
else
{    //找右子树的最小节点Node* parent2 = cur;Node* rightMin = cur->_right;while (rightMin->_left){parent2 = rightMin;rightMin = rightMin->_left;}//交换关键值swap(rightMin->_key, cur->_key);//此时删除目标变为右子树的最小节点del = rightMin;//更新其关系,左为空if (parent2->_left == rightMin)parent2->_left = rightMin->_right;elseparent2->_right = rightMin->_right;
}delete del;
return true;

(1)将更新父亲节点的链接关系作为主要内容,提前保存删除节点 cur ,后续一步删除

(2)左为空与右为空代码逻辑类似,这里只讲左为空(都为空已被涵盖)

正如删除键值为 6 的树节点一样,只需让父亲节点指向右子树,但是,

需要判断键值为 6 的树节点属于父亲节点的左子树还是右子树

判断完成之后,将父亲节点的左或右孩子指针指向树节点的右子树即可,

if (parent1->_left == cur){parent1->_left = cur->_right;}else{parent1->_right = cur->_right;}

最坑的是 ,如果根节点就是要删除的节点这套逻辑行不通!办法是:

将根节点调整为根节点的右子树的根节点

if (parent1 == cur){_root = cur->_right;}

(3)删除节点左右子树都存在,使用替换法删除

只能选用删除节点的左子树的最大键值或右子树的最小键值与删除节点的键值进行替换操作

因为这样才能满足二叉搜索树的定义

替换之后,需要删除的节点就变为了左子树或右子树中键值与删除节点替换前的键值一致的节点,所以,在查找左子树的最大键值或右子树的最小键值仍需保存当前节点的父亲节点以便后续链接关系的更新,当然,此时的链接关系得到简化(要么左为空,要么右为空)

2.递归版本

2.1查找

根据键值大小,前序遍历进行递归查找,最小子问题是空树

当前节点不是要查找的节点就先去左子树查找,再到右子树查找

Node* findR(const K& key){return _findR(_root, key);
}Node* _findR(Node* root, const K& key){if (!root)return nullptr;if (key > root->_key){return _findR(root->_right, key);}else if (key < root->_key){return _findR(root->_left, key);}else{return root;}
}

为了外界能够简单的传参(只传入键值),递归嵌套调用子函数

2.2插入

仍是前序遍历根据键值的比较找到插入的恰当位置

恰当位置就是树为空的位置

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

为了外界能够简单的传参(只传入键值),递归嵌套调用子函数

查找逻辑以及默认二叉搜索树的节点键值都不同非递归版本都有提及,这里着重讲解

父亲节点连接关系的更新

节点指针的引用可谓是神之一笔

树为空,root 是 _root 的别名,root 指向 新创建的节点,_root 也指向 新创建的节点。

树不为空,且找到恰当位置后, 当前栈帧中的 root 是 前一个栈帧中 root->left 或 root->right

的别名,引用就形成了天然的连接关系,此时只需要将 当前栈帧中的 root 指向 新创建的节点即可将新创建的节点链接到树中

2.3删除

仍是前序遍历根据键值的比较找到要删除的节点

bool EraseR(const K& key){return _EraseR(_root, key);
}bool _EraseR(Node*& root, const K& key){//找不到的情况就是节点值为空if (!root)return false;if (key > root->_key){return _EraseR(root->_right, key);}else if (key < root->_key){return _EraseR(root->_left, key);}else//找到了{Node* del = root;//更新链接关系if (!root->_left){//root是父亲节点某一指针的别名//直接修改root即可root = root->_right;}else if (!root->_right){root = root->_left;}else{//找到左子树的最大节点Node* leftMax = root->_left;while (leftMax->_right){leftMax = leftMax->_right;}//交换值swap(leftMax->_key, root->_key);//此时删除目标变为leftMax		return _EraseR(root->_left, key);}delete del;return true;}
}

为了外界能够简单的传参(只传入键值),递归嵌套调用子函数

查找逻辑以及默认二叉搜索树的节点键值都不同非递归版本都有提及,这里着重讲解

父亲节点连接关系的更新,节点的删除可一笔带过

节点指针的引用仍是神之一笔

无需提前保存父亲节点

(1)没有孩子节点或者只有一个孩子节点

找到删除节点后, 当前栈帧中的 root 是 前一个栈帧中 root->left 或 root->right

的别名,引用就形成了天然的连接关系,此时只需要将 当前栈帧中的 root 指向 它的左子树或右子树即可将它的左子树或者右子树链接到树中

(2)当删除节点有两个孩子节点时,仍是选择  替换法进行删除

这里的精妙之处在于递归调用函数进行删除操作

替换的是左子树的最大键值,那就只能去左子树中删除

替换的是右子树的最小键值,那就只能去右子树中删除

而不能从当前这棵中去删除,因为会找不到!!

http://www.dtcms.com/a/530372.html

相关文章:

  • 手机网站模板下载免费crm管理系统销售
  • 网站的域名能修改么北京商场排名
  • 企业做电商网站创建自己的网站能干什么
  • 网站创建软件海口智能建站详情
  • 一个可以做行程的网站wordpress微信群二维码
  • 电子商务网站名称apache 写wordpress
  • 低价代网站网站网站制作公司哪家好
  • 网络编程就是做网站么湖南人文科技学院是几本
  • 建设网站商城宁夏 网站开发
  • 有建网站的公司吗网站建设的技术风险分析与规避
  • 《玩转Docker》[应用篇12]:Docker安装思源笔记使用指南
  • 镇江 网站建设网络舆情现状分析
  • 有名的网站制佛山市网络seo推广公司
  • 广东网站建设报价官网软装设计收费标准
  • 程序地址空间
  • 做企业门户网站网站建好后维护麻烦吗
  • 雅菲奥朗人工智能知识墙分享(三):『AI算力:人工智能时代的“核心引擎”』
  • 如何判断网站是否被收录wordpress加载视频教程
  • 手机版网站系统网站建设和媒体渠道
  • 网站加速 wordpresswordpress媒体库一直转圈
  • Linux 离线迁移conda R虚拟环境教程
  • 过界女主个人做网站的班级网站的建设
  • 杭州公司网站建设套餐怎样申请建立自助网站
  • 网站备案号查询网温州论坛官方网
  • 做网站百度推广南沙网站建设公司哪家好
  • 重庆网站建设推荐网站营销推广有哪些
  • 网站控制做百度网站需不需要备案吗
  • ps制作网站网站开发文档模板下载
  • 手机站建设前端网站设计
  • 门户网站建设招投标php网站视频代码