[初等算法]--树
二叉搜索树,数据结构中的”hello world”
我们使用二叉搜索树(BST)作为数据结构中的“hello world”。Jon Bentley在他的《编程珠玑》一书中,曾给了这样一个有趣的题目:如何统计一段文字中每个单词出现的次数?下面的C++程序展示了一个解法。
1 | int (int, char∗∗ ){ |
C++标准库中提供的map是一种用平衡二叉树实现的字典数据结构。例子中用单词作为key,用单词出现的次数作为值。
一棵二叉搜索树
是一棵满足下面条件的二叉树:
- 所有左侧分支的值都小于本节点的值,
- 本节点的值小于所有右侧分支的值。
节点数据结构
1 | template<class T> |
插入
我们可以使用下述算法向一个二叉搜索树中插入一个键k(在实际应用中,有时会同时插入一对键和值):
- 如果树为空,创建一个叶子节点,令该节点的key = k;
- 如果k小于根节点的key,将它插入到左子树中;
- 如果k大于根节点的key,将它插入到右子树中。
遍历
遍历是指依次访问二叉树中的每个元素。有三种遍历方法,分别是前序遍历、中序遍历和后序遍历。它们是按照访问根节点和子节点的先后顺序命名的。
- 前序遍历:先访问key,然后访问左子树,最后访问右子树;
- 中序遍历:先访问左子树,然后访问key,最后访问右子树;
- 后序遍历:先访问左子树,然后访问右子树,最后访问key。
所有的“访问”操作都是递归的。先访问根后访问子分支称为先序,在访问左右分支的中间访问根称为中序,先访问子分支后访问根称为后序。对于图中的二叉树,下面分别列出了三种遍历的结果:
- 前序遍历:4, 3, 1, 2, 8, 7, 16, 10, 9, 14;
- 中序遍历:1, 2, 3, 4, 7, 8, 9, 10, 14, 16;
- 后序遍历:2, 1, 3, 7, 9, 14, 10, 16, 8, 4。
对二叉搜索树进行中序遍历,元素就会按照从小到大的顺序输出。
中序遍历的算法可以描述为:
- 如果树为空,则返回;
- 否则先中序遍历左子树,然后访问key,最后再中序遍历右子树。
搜索
Look up
二叉搜索树的定义使得它非常适合进行元素的搜索。可以按照下面描述的方法在树中搜索一个key:
- 如果树为空,搜索失败;
- 如果根节点的key等于待搜索的值,搜索成功,返回根节点作为结果;
- 如果待搜索的值小于根节点的key,继续在左子树中递归搜索;
- 否则,待搜索的值大于根节点的key,继续在右子树中递归搜索。
1 | template<class T> |
最小元素和最大元素
为了获取最小元素,我们可以不断向左侧前进,直到左侧分支为空。类似地,我们可以通过不断向右侧前进获取最大元素。
前驱(Successor)和后继(predecessor)
给定元素x,它的后继元素y是满足y > x的最小值。有两种情况:如果x所在的节点有一个非空的右子树,则右子树中的最小值就是答案。如图所示,8的后继元素为9,它是元素8的右子树中的最小值。另外一种情况是,如果x没有非空的右子树,我们需要向上回溯,找到最近的一个祖先,使得该祖先的左侧孩子,也为x的祖先。元素2所在的节点没有右侧分支,我们向上回溯一步找到元素1,但是1没有左侧分支,因此需要继续向上查找,这次我们到达了元素3所在的节点。而3的左侧孩子,同样也是2的祖先。至此,我们找到了2的后继元素3。
1 | def succ(x): |
代码如下:
1 |
|
插入排序的进化
1 | void isort(Key∗ xs, int n){ |
改进一
任何时刻,我们手中的牌都是已序的,因此我们可以用二分查找来搜索插入位置。
1 | def isort(xs): |
使用二叉搜索树的最终改进
1 | function Sort(A) |
原文地址:https://www.cnblogs.com/sanxiandoupi/p/11692299.html
- HDUOJ----4502吉哥系列故事——临时工计划
- HDUOJ----4004The Frog's Games(二分+简单贪心)
- HDUOJ----4006The kth great number(最小堆...)
- HDUOJ----4501小明系列故事——买年货(三维背包)
- message 弹出窗口
- HDUOJ---1862EXCEL排序
- HDUOJ-----3591The trouble of Xiaoqian
- HDUOJ-----2571跳舞毯
- Facebook开源PyTorch版本fairseq翻译模型,训练速度提高50%
- MySQL数据清理的需求分析和改进
- Go 语言常量
- Go 语言结构
- Go 语言函数
- Go语言指针
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- php如何利用pecl安装mongodb扩展详解
- PHP微信支付结果通知与回调策略分析
- PHP标准库(PHP SPL)详解
- php成功操作redis cluster集群的实例教程
- 在pytorch中动态调整优化器的学习率方式
- 可视化pytorch 模型中不同BN层的running mean曲线实例
- python如何删除文件、目录
- pytorch实现查看当前学习率
- python3.x中安装web.py步骤方法
- pytorch 网络参数 weight bias 初始化详解
- PHP中单例模式的使用场景与使用方法讲解
- pytorch查看模型weight与grad方式
- php+ajax 文件上传代码实例
- PHP将整数数字转换为罗马数字实例分享
- PHP如何通过表单直接提交大文件详解