博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
重温数据结构系列--二叉树、堆
阅读量:6219 次
发布时间:2019-06-21

本文共 4395 字,大约阅读时间需要 14 分钟。

二叉树

二叉树是特殊的树,也是我们平时程序中用的比较多的一种数据结构,它具有以下特点:

  1. 每个结点最多有两颗子树,结点的度最大为2。
  2. 左子树和右子树是有顺序的,次序不能颠倒。
  3. 即使某个结点只有一个子树,也要区分左右子树。

下面是二叉树的数据特性

  1. 在二叉树的第i(根结点为1层)层上最多有2^(i-1)个结点(i>=1)。
  2. 高度为k的二叉树,最多有2^k-1个结点(k>=0)。
  3. 对任何一棵二叉树,如果其叶结点有n个,度为2的非叶子结点有m个,则 n=m+1。

特殊的二叉树及特点

1、斜树

所有的结点都只有左子树(左斜树),或者只有右子树(右斜树)。斜树应用场景较少。

2、满二叉树

所有的分支结点都存在左子树和右子树,并且所有的叶子结点都在同一层上。

满二叉树具有以下特点:

  1. 叶子结点只能出现在最下一层。
  2. 非叶子结点的度一定是2.
  3. 在同样深度的二叉树中,满二叉树的结点个数最多,叶子结点最多。

3、完全二叉树

对一棵具有n个结点的二叉树按层序排号,如果编号为i的结点与同样深度的满二叉树编号为i结点在二叉树中位置完全相同,就是完全二叉树。满二叉树必须是完全二叉树,反过来不一定成立。

完全二叉树具有以下特点:

  1. 叶子结点只能出现在最底部两层。
  2. 最底层叶子结点一定集中在左部连续位置。
  3. 倒数第二层如果有叶子结点,一定出现在右部连续位置。
  4. 同样数量结点的树,完全(满)二叉树的深度最小。
  5. 对于有n个结点的完全二叉树,按层次对结点进行编号(从上到下,从左到右),对于任意编号为i的结点:
  • 如果i=1,则结点i是二叉树的根
  • 如果i>1,则其双亲结点为i/2下取整。
  • 如果2i<=n,则结点i的做孩子2i。
  • 如果2i>n,则结点i无左孩子。
  • 如果2i+1<=n,则结点i的右孩子为2i+1。
  • 如果2i+1>n,则结点i无右孩子。

4、二叉排序树

二叉排序树,又称,也叫。

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1) 若左子树不为空,则左子树上所有结点的值均小于或等于它的根结点的值。
(2) 若右子树不为空,则右子树上所有结点的值均大于或等于它的根结点的值。
(3) 左、右子树也分别是二叉排序树。
(4) 二叉排序树中序遍历结果为递增有序数列。

关于二叉排序树更加详细的介绍,请阅读 ,这篇文章中详细介绍了二叉排序树的创建(结点查找及插入),结点删除的过程,并且使用kotlin给出了相应程序实现。下面我们使用JavaScript实现二叉排序树创建、查找、删除的相关逻辑。

// 树的结点类class Node {    constructor(key, leftChild, rightChild) {        this.key = key;        this.left = leftChild;        this.right = rightChild;    }}// 二叉排序树类class BinarySortTree {    constructor() {}    // 创建二叉排序树的数据结构    create(data) {        if(!(data instanceof Array) || data.length < 1) {            return        }        var len = data.length;        var tree = new Node(data[0], null, null);        if(len == 1) {            return tree;        }        for(let i=1; i
currentNode.key) { currentNode.right = this.deleteNode(currentNode.right, key); return currentNode; }else { if(!currentNode.left && !currentNode.right) { // 如果是叶子结点 currentNode = null; return currentNode; } if(!currentNode.right) { // 如果只有左子树 currentNode = currentNode.left; return currentNode; }else if(!currentNode.left) { // 如果只有右子树 currentNode = currentNode.right; return currentNode; }else { // 既有左子树又有右子树 var minRightKey = this.findMinNode(currentNode.right); currentNode.key = minRightKey; currentNode.right = this.deleteNode(currentNode.right, minRightKey); return currentNode; } } } // 查找最小结点 findMinNode(rightTree) { if(rightTree) { while(rightTree && rightTree.left) { rightTree = rightTree.left; } return rightTree.key; } return null; }}const arr = [62, 88, 58, 47, 35, 73, 51, 99, 37, 93];var binSrotTree = new BinarySortTree();var bstree = binSrotTree.create(arr);console.log(bstree);var searchResult = binSrotTree.searchNode(bstree, 100);console.log(searchResult); // falsevar newbstree = binSrotTree.deleteNode(bstree, 62);console.log(newbstree);复制代码

5、平衡二叉树

平衡二叉树(Balanced BinaryTree)又被称为AVL树(有别于AVL算法),它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

注意:满二叉树和完全二叉树一定是平衡二叉树

二叉树的存储

1、链表存储(对象)

适用于所有二叉树,详细介绍见 树的存储--孩子兄弟表示法

2、顺序表存储(数组)

利用平衡二叉树平衡的特性,使用数组来存储完全二叉树,a[n]的左右子节点分别为a[2n+1],a[2n+2]。

注:数组的下标是从0开始的,二叉树是从1开始的。

二叉树的遍历

1、先序遍历

基本思想:先访问根结点,再先序遍历左子树,最后再先序遍历右子树即根—左—右。

图中先序遍历结果是:1,2,4,5,7,8,3,6。

先序遍历JavaScript实现见下面程序。

var sortedArr = [];function preOrder(tree) {    if(tree) {        sortedArr.push(tree.key);        middleOrder(tree.left);        middleOrder(tree.right);    }}复制代码

2、中序遍历

基本思想:先中序遍历左子树,然后再访问根结点,最后再中序遍历右子树即左—根—右。

图中中序遍历结果是:4,2,7,8,5,1,3,6。

中序遍历JavaScript实现见下面程序。

var sortedArr = [];function middleOrder(tree) {    if(tree) {        middleOrder(tree.left);        sortedArr.push(tree.key);        middleOrder(tree.right);    }}middleOrder(bstree); // bstree为上文中创建的二叉排序树console.log(sortedArr); //[ 35, 37, 47, 51, 58, 62, 73, 88, 93, 99 ]复制代码

3、后序遍历

基本思想:先后序遍历左子树,然后再后序遍历右子树,最后再访问根结点即左—右—根。

图中后序遍历结果是:4,8,7,5,2,6,3,1。

后序遍历JavaScript实现见下面程序。

var sortedArr = [];function postOrder(tree) {    if(tree) {        middleOrder(tree.left);        middleOrder(tree.right);        sortedArr.push(tree.key);    }}复制代码

堆及特点

堆是什么?一般情况下可以把堆认作是一种特殊的完全二叉树。非一般情况下堆是什么?阅读

堆可以分为大根堆和小根堆。
大根堆:所有父结点都比子结点大的完全二叉树。
小根堆:所有父结点都比子结点小的完全二叉树。

总结

关于数据结构中二叉树相关的知识点有很多很多,本文提到的二叉树属于二叉树应用中比较常见的几种。还有更多的知识点可以阅读文章中引用的文章。此外,堆排序也是一种比较常见(经典)的排序方式,后序会有专门文章介绍。

参考文章

拓展阅读

转载地址:http://jfmja.baihongyu.com/

你可能感兴趣的文章
Amazon DynamoDB 入门6:query 和 scan
查看>>
Mac OS X and python “ValueError: unknown locale: UTF-8”
查看>>
理解CSRF跨站请求伪造
查看>>
被误解的MVC和被神化的MVVM
查看>>
DevOps日常:别人家的运维这样过
查看>>
中台之上(一):重视业务架构,不要让“业务的归业务、技术的归技术”
查看>>
通过Visual Studio为Linux编写C++代码
查看>>
利用Apache Spark SQL和DataFrames扩展关系数据库
查看>>
Netflix 混沌工程手册 Part 3:实践方法
查看>>
2018年开源状况:代码贡献超310亿行,而漏洞超16000个
查看>>
Java初学者如何能够把知识深入贯彻
查看>>
仅售99美元!英伟达发布最小AI计算机Jetson Nano
查看>>
写守护进程时, 需要fork两次吗?
查看>>
方面和服务,差别大吗?
查看>>
Go现在接受来自GitHub PR的补丁
查看>>
JetBrains发布WebStorm 2016.2,改进对TypeScript和React的支持
查看>>
国内首例:飞步无人卡车携手中国邮政、德邦投入日常运营
查看>>
深入理解浏览器的缓存机制
查看>>
7道常见的数据分析面试题
查看>>
《反脆弱边缘:反脆弱实践》访谈
查看>>