利用JS实现二叉树遍历算法实例代码

目录
  • 前言
  • 一、二叉树
    • 1.1、遍历二叉树
    • 1.2、用js表示二叉树
    • 1.3、前序遍历算法
    • 1.4、中序遍历算法
    • 1.5、后序遍历算法
    • 1.6、按层遍历算法
  • 二、算法题
    • 1.1、二叉树的最大深度
    • 1.2、二叉树的所有路径
  • 总结

前言

在计算机科学中, 树(tree) 是一种广泛使用的抽象数据类型(ADT),是一类非线性数据结构。树在计算机领域得到广泛应用,尤其二叉树最为常用。

树的相关概念:

  • 结点:每个元素称为结点
  • 树根:根节点
  • 度:一个结点含有的子结点的个数称为该结点的度
  • 叶子节点:度为0的节点

一、二叉树

概念:每个节点最多含有两个子树的树称为二叉树。

1.1、遍历二叉树

二叉树有两种遍历深度遍历和广度遍历,其中深度遍历有前序、 中序和后序三种遍历方法。 广度遍历就是层次遍历,按层的顺序一层一层遍历。

四种遍历的主要思想:

  • 前序:先访问根,然后访问左子树,最后访问右子树,DLR。
  • 中序:先访问左子树,然后访问根,最后访问右子树,LDR。
  • 后序:先后访问左子树,然后访问右子树,最后访问根,LRD。
  • 广度:按层的顺序一层一层遍历。

例如a+b*(c-d)-e/f,该表达式用二叉树表示:

对他分别进行遍历:

  • 前序:-+a*b-cd/ef
  • 中序:a+b*c-d-e/f
  • 后序:abcd-*+ef/-
  • 广度:-+/a*efb-cd

1.2、用js表示二叉树

我们用js的对象来表示二叉树,对象拥有三个属性,left、value、right,分别是左子树,值和右子树,上面a+b*(c-d)-e/f的例子我们用js可以这样表示。

var tree = {
    value: '-',
    left: {
        value: '+',
        left: {
            value: 'a'
        },
        right: {
            value: '*',
            left: {
                value: 'b'
            },
            right: {
                value: '-',
                left: {
                    value: 'c'
                },
                right: {
                    value: 'd'
                }
            }
        }
    },
    right: {
        value: '/',
        left: {
            value: 'e'
        },
        right: {
            value: 'd'
        }
    }
}

1.3、前序遍历算法

前序:有两种方法,第一种很简单就是直接使用递归的办法。

function preOrder(treeNode) {
  if(treeNode) {
    console.log(treeNode.value); // 打印出来代表访问这个节点
    preOrder(treeNode.left);
    preOrder(treeNode.right);
  }
}

算法思路很简单,先遍历根节点,然后递归遍历左子树,左子树遍历结束后,递归右子树。

第二种非递归遍历

function preOrder(treeNode) {
  if(treeNode) {
    var stack = [treeNode]; //将二叉树压入栈
    while (stack.length !== 0) {
      treeNode = stack.pop(); // 取栈顶
      document.getElementById('text').appendChild(document.createTextNode(treeNode.value)); // 访问节点
      if(treeNode.right) stack.push(treeNode.right); // 把右子树入栈
      if(treeNode.left) stack.push(treeNode.left); // 把左子树入栈
    }
  }
}

第二种是使用栈的思想,我们都知道,栈是先进后出的一种数据结构,我们先把根节点入栈,然后取栈顶,访问根节点,分别把右左子树入栈,这边必须右边先入栈,因为我们是要先从左边开始访问的,所以右子树先入栈,然后就循环取出栈,直到栈空。

1.4、中序遍历算法

中序递归算法:

function InOrder(treeNode) {
    if(treeNode) {
        InOrder(treeNode.left);
        document.getElementById('text').appendChild(document.createTextNode(treeNode.value));
        InOrder(treeNode.right);
    }
}

和前序递归算法同样的思路,只是访问节点位置不同

第二种:

function InOrder(node) {
  if(node) {
    var stack = [];             // 建空栈
    //如果栈不为空或结点不为空,则循环遍历
    while (stack.length !== 0 || node) {
      if (node) {               //如果结点不为空
          stack.push(node);     //将结点压入栈
          node = node.left;     //将左子树作为当前结点
      } else {                  //左子树为空,即没有左子树的情况
          node = stack.pop();   //将结点取出来
          document.getElementById('text').appendChild(document.createTextNode(node.value));
          node = node.right;    //将右结点作为当前结点
      }
    }
  }
}

非递归中序算法的思想就是,把当前节点入栈,然后遍历左子树,如果左子树存在就一直入栈,直到左子树为空,访问但前节点,然后让右子树入栈。

1.5、后序遍历算法

第一种:递归遍历算法

function postOrder(node) {
    if (node) { //判断二叉树是否为空
        postOrder(node.left); //递归遍历左子树
        postOrder(node.right); //递归遍历右子树
        document.getElementById('text').appendChild(document.createTextNode(node.value));
    }
}

第二种:非递归遍历算法

function postOrder(node) {
    if (node) { //判断二叉树是否为空
        var stack = [node]; //将二叉树压入栈
        var tmp = null; //定义缓存变量
        while (stack.length !== 0) { //如果栈不为空,则循环遍历
            tmp = stack[stack.length - 1]; //将栈顶的值保存在tmp中
            if (tmp.left && node !== tmp.left && node !== tmp.right) { //如果存在左子树,node !== tmp.left && node !== tmp.righ 是为了避免重复将左右子树入栈
                stack.push(tmp.left);   //将左子树结点压入栈
            } else if (tmp.right && node !== tmp.right) { //如果结点存在右子树
                stack.push(tmp.right);  //将右子树压入栈中
            } else {
                document.getElementById('text').appendChild(document.createTextNode(stack.pop().value));
                node = tmp;
            }
        }
    }
}

这里使用了一个tmp变量来记录上一次出栈、入栈的结点。思路是先把根结点和左树推入栈,然后取出左树,再推入右树,取出,最后取根结点。

下面是用这个算法遍历前面那个二叉树的过程

stack       tmp         node        打印
初始 :  -          null         -
第1轮:  -+          -           -
第2轮:  -+a         +           -
第3轮:  -+          a           a            a
第4轮:  -+*         +           a 
第5轮:  -+*b        *           a 
第6轮:  -+*         b           b            b
第7轮:  -+*-        *           b
第8轮:  -+*-c       -           b
第9轮:  -+*-        c           c            c
第10轮: -+*-d       -           c
第11轮: -+*-        d           d            d
第12轮: -+*         -           -            -
第13轮: -+          *           *            *
第14轮: -           +           +            +
第15轮: -/          -           +           
第16轮: -/e         /           +
第17轮: -/          e           e            e
第18轮: -/f         /           e           
第19轮: -/          f           f            f
第20轮: -           /           /            /
第21轮:             -           -            -

结果:abcd-*+ef/-

1.6、按层遍历算法

function breadthTraversal(node) {
    if (node) {                             //判断二叉树是否为空
        var que = [node];                   //将二叉树放入队列
        while (que.length !== 0) {          //判断队列是否为空
            node = que.shift();             //从队列中取出一个结点
            document.getElementById('text').appendChild(document.createTextNode(node.value));   //将取出结点的值保存到数组
            if (node.left) que.push(node.left);   //如果存在左子树,将左子树放入队列
            if (node.right) que.push(node.right); //如果存在右子树,将右子树放入队列
        }
    }
}

使用数组模拟队列,首先将根结点归入队列。当队列不为空时,执行循环:取出队列的一个结点,如果该节点有左子树,则将该节点的左子树存入队列;如果该节点有右子树,则将该节点的右子树存入队列。

二、算法题

1.1、二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

比如下面这个二叉树,返回深度3。

3
   / \
  9  20
    /  \
   15   7

const tree = {
    value: 3,
    left: {
        value: 9
    },
    right: {
        value: 20,
        left: { value: 15 },
        right: { value: 9 }
    }
}

递归算法:递归算法的思路很简单,先拿到左子树最深层,再拿到右子树最深层,取他们最大值就是树的深度。

var maxDepth = function(root) {
  if (!root) {
    return 0;
  }
  const leftDeep = maxDepth(root.left) + 1;
  const rightDeep = maxDepth(root.right) + 1;
  return Math.max(leftDeep, rightDeep);
};
/*
maxDepth(root) = maxDepth(root.left) + 1  = 2
maxDepth(root.left) = maxDepth(root.left.left) + 1 = 1
maxDepth(root.left.left) = 0;

maxDepth(root) = maxDepth(root.right) + 1 = 3
maxDepth(root.right) = maxDepth(root.right.right) + 1 = 2
maxDepth(root.right.right) = maxDepth(root.right.right.right) + 1 = 1
maxDepth(root.right.right.right) = 0
*/

1.2、二叉树的所有路径

给定一个二叉树,返回所有从根节点到叶子节点的路径。

比如:

3
   / \
  9  20
    /  \
   15   7
 
返回:['3->9', '3->20->15', '3->20->7']

使用递归的方法:

var binaryTreePaths = function(root) {
  if (!root) return [];
  const res = [];
  function dfs(curNode, curPath) {
    if(!curNode.left && !curNode.right) {
      res.push(curPath);
    }
    if(curNode.left) {
      dfs(curNode.left, `${curPath}->${curNode.left.value}`)
    }
    if(curNode.right) {
      dfs(curNode.right, `${curPath}->${curNode.right.value}`)
    }
  }
  dfs(root, `${root.value}`);
  return res;
};

总结

到此这篇关于利用JS实现二叉树遍历算法的文章就介绍到这了,更多相关JS二叉树遍历算法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JavaScript编程通过Matlab质心算法定位学习

    目录 Matlab质心算法 Matlab作为封闭的商业软件,受美国政府左右,无视商业道德,故不建议使用.如果喜欢Matlab语法,可移步开源的octave,其语法与matlab完全相同. Matlab质心算法 所谓质心,就是当密度作为像素点灰度值时的重心,例如其质心的x坐标为 最直观的方法就是下面的这种方式了. %%通过质心算法找到img的质心位置 function [x,y] = oCenter(img) img = double(img); [m,n] = size(img); x = 0;

  • JavaScript实现的七种排序算法总结(推荐!)

    目录 前言 冒泡排序 基础算法 第二种写法是在基础算法的基础上改良而来的: 选择排序 基础算法 二元选择排序-优化 插入排序 交换法插入排序 移动法 希尔排序 堆排序 快速排序 归并排序 总结 前言 所谓排序算法,即通过特定的算法因式将一组或多组数据按照既定模式进行重新排序.这种新序列遵循着一定的规则,体现出一定的规律,因此,经处理后的数据便于筛选和计算,大大提高了计算效率.对于排序,我们首先要求其具有一定的稳定性,即当两个相同的元素同时出现于某个序列之中,则经过一定的排序算法之后,两者在排序前

  • 如何利用JavaScript实现排序算法浅析

    目录 冒泡排序 选择排序 插入排序 总结 冒泡排序 冒泡排序就是重复从序列右边开始比较相邻两个数字的大小,再根据结果交换两个数字的位置. JavaScript代码实现: 代码简介:声明一个数组变量,通过while给数组变量赋值,当输入"#"时停止输入,然后遍历相邻的两个数,让相邻的两个数升序排列,遍历n-1次实现排序; var a = Array(); flag=true; var i = 0; var j = 0; var temp = 0; while(flag){ var b =

  • js实现指定红包顺序和金额算法

    本文实例为大家分享了js实现指定红包顺序和金额的具体代码,供大家参考,具体内容如下 前言 朋友拜托而写 单个包最小金额为0.01 如果除指定金额外,其余都为0.01,最后尾包存在为0的几率 本算法通过了1000000次测试,出错率为百万分之3 效果展示 空包问题 红包算法 /* param: float, int, int, float param1:红包金额总额 param2:红包数目 param3:指定特殊红包 param4:指定特殊红包金额 */ let getPrize = functi

  • 如何利用javascript做简单的算法

    目录 1 问题 2 方法 3 实验结果与讨论 1 问题 众所周知,无论是Pycharm或是IDLE.java都可以计算简单的算法,比如加减乘除.然而在Hbuilder中,javascript也可以用来计算数值的加减乘除. 比如,我们计算:假设 y=5,计算 x=y+2,并显示结果. 2 方法 首先利用<p></p>标签写算法题题目.然后利用<button></button>标签创造一个事件,其中标签里面onclick后面的命名一定要加().再然后写一个<

  • 如何用JavaScript学习算法复杂度

    概述 在本文中,我们将探讨 "二次方" 和 "n log(n)" 等术语在算法中的含义. 在后面的例子中,我将引用这两个数组,一个包含 5 个元素,另一个包含 50 个元素.我还会用到JavaScript中方便的performance API来衡量执行时间的差异. const smArr = [5, 3, 2, 35, 2]; const bigArr = [5, 3, 2, 35, 2, 5, 3, 2, 35, 2, 5, 3, 2, 35, 2, 5, 3,

  • 面向JavaScript入门初学者的二叉搜索树算法教程

    目录 什么是二叉搜索树 (BST)? 二叉树基本遍历(中序.后序.前序) 中序遍历 后序遍历 前序遍历 什么是有效的二叉搜索树? 如何找到二叉树最大深度 如何找到两个树节点之间的最小公共祖先

  • 浅谈JavaScript构造树形结构的一种高效算法

    引言 我们经常会碰到树形数据结构,比如组织层级.省市县或者动植物分类等等数据.下面是一个树形结构的例子: 在实际应用中,比较常见的做法是将这些信息存储为下面的结构,特别是当存在1对多的父/子节点关系时: const data = [ { id: 56, parentId: 62 }, { id: 81, parentId: 80 }, { id: 74, parentId: null }, { id: 76, parentId: 80 }, { id: 63, parentId: 62 }, {

  • 利用JS实现二叉树遍历算法实例代码

    目录 前言 一.二叉树 1.1.遍历二叉树 1.2.用js表示二叉树 1.3.前序遍历算法 1.4.中序遍历算法 1.5.后序遍历算法 1.6.按层遍历算法 二.算法题 1.1.二叉树的最大深度 1.2.二叉树的所有路径 总结 前言 在计算机科学中, 树(tree) 是一种广泛使用的抽象数据类型(ADT),是一类非线性数据结构.树在计算机领域得到广泛应用,尤其二叉树最为常用. 树的相关概念: 结点:每个元素称为结点 树根:根节点 度:一个结点含有的子结点的个数称为该结点的度 叶子节点:度为0的节

  • 使用 Node.js 实现图片的动态裁切及算法实例代码详解

    背景&概览 目前常见的图床服务都会有图片动态裁切的功能,主要的应用场景用以为各种终端和业务形态输出合适尺寸的图片. 一张动辄以 MB 为计量单位的原始大图,通常不会只设置一下显示尺寸就直接输出到终端中,因为体积太大加载体验会很差,除了影响加载速度还会增加终端设备的内存占用.所以要想在各种终端下都能保证图片质量的同时又确保输出合适的尺寸,那么此时就需要根据图片 URL 来对原始图片进行裁切,然后动态生成并输出一张新的图片. URL 的设计 图片 URL 需要包含图片 id.尺寸.质量等信息.有两种

  • php实现的二叉树遍历算法示例

    本文实例讲述了php实现的二叉树遍历算法.分享给大家供大家参考,具体如下: 今天使用php来实现二叉树的遍历 创建的二叉树如下图所示 php代码如下所示: <?php class Node { public $value; public $child_left; public $child_right; } final class Ergodic { //前序遍历:先访问根节点,再遍历左子树,最后遍历右子树:并且在遍历左右子树时,仍需先遍历根节点,然后访问左子树,最后遍历右子树 public s

  • JavaScript数据结构与算法之二叉树遍历算法详解【先序、中序、后序】

    本文实例讲述了JavaScript数据结构与算法之二叉树遍历算法.分享给大家供大家参考,具体如下: javascript数据结构与算法--二叉树遍历(先序) 先序遍历先访问根节点, 然后以同样方式访问左子树和右子树 代码如下: /* *二叉树中,相对较小的值保存在左节点上,较大的值保存在右节点中 * * * */ /*用来生成一个节点*/ function Node(data, left, right) { this.data = data;//节点存储的数据 this.left = left;

  • jQuery 利用ztree实现树形表格的实例代码

    最近公司的项目中要做一个树形表格,因为之前一直在用ztree实现基本的树形结构,理所当然的首先想到利用ztree来做. 网上找了一下别人做的树形表格,有使用ztree的,也有使用treeTable的,但效果都不太好,于是参考使用ztree的做法自己做了一个,贴出来供大家参考,请看注释说明,效果如下所示. <!DOCTYPE HTML> <html> <head> <link href="https://cdn.bootcss.com/zTree.v3/3

  • Java使用异或运算实现简单的加密解密算法实例代码

    Java简单的加密解密算法,使用异或运算 实例1: package cn.std.util; import java.nio.charset.Charset; public class DeEnCode { private static final String key0 = "FECOI()*&<MNCXZPKL"; private static final Charset charset = Charset.forName("UTF-8"); pr

  • c语言5个常用的排序算法实例代码

    1.插入排序 基本思想:插入排序就是每一步都将一个待排数据按其大小插入到已经排序的数据中的适当位置,直到全部插入完毕. void insertSort(vector<int>& nums) { int k = 0; for (int i = 0; i < nums.size(); ++i) { int temp = nums[i]; int j = i; for (; j > 0 && temp < nums[j-1]; --j) nums[j] =

  • JS控制下拉列表左右选择实例代码

    使用JS控制下拉列表左右选择 需求分析 在我们的分类管理中,我们要能够去修改我们的分类信息,当我们一点修改的时候,跳转到一个可以编辑的页面,这里面能够修改分类的名称,分类的描述,以及分类的商品 技术分析 ondblclick="selectOne()":双击事件 select标签的属性multiple="multiple": 代码实现 <!DOCTYPE html> <html> <head> <meta charset=&

  • 使用 Opentype.js 生成字体子集的实例代码详解

    字体子集是将字体文件中部分多余的字符删除,来减小文件大小,从而在 Web 端使用或嵌入到其他应用或系统中,在网上可以找到不少这方面的工具. Opentype.js是一套可以支持浏览器环境和 Node.js 环境的开源 OpenType 字体读写库,利用这个库可以很轻松实现浏览器环境和 Node.js 环境的字体子集功能. 在浏览器环境创建字体子集工具 首先创建一个简单的 HTML界面,包括一个选取字体文件按钮,一个输入框用于输入保留的字符,和一个保存下载按钮. HTML <!DOCTYPE ht

  • 原生JS实现的放大镜效果实例代码

    这是我用原生js写的放大镜效果,与各种各样的框架技术相比,我喜欢使用原生的js,在这里,想和大家一起谈谈原生和框架技术的理解与个人喜好. <!DOCTYPE HTML> <html> <head> <title>js放大镜效果</title> <meta http-equiv="content-type" content="text/html;charset=utf-8"/> <style

随机推荐