JS--树、二叉树(深度优先、广度优先遍历、平衡树旋转)

本文介绍了JavaScript中树结构和二叉树的特点,包括度、高度等概念,以及二叉搜索树的封装,详细讲解了插入、删除、查找节点的方法。此外,还阐述了深度优先遍历(先序、中序、后序)和广度优先遍历,并探讨了如何通过旋转操作将不平衡二叉树转换为平衡二叉树,包括LL、RR、LR和RL四种情况。
摘要由CSDN通过智能技术生成

JS–树、二叉树(深度优先、广度优先遍历、平衡树旋转)

一、树结构和特点

1、树结构

树的结构
树由节点组成,从根节点出发,每个节点可以拥有子节点,没有子节点的节点叫做叶子节点。

节点的度:节点拥有子节点的个数,度为0表示叶子节点
树的高度:从根节点开始计算(1开始)到叶子节点,一共拥有的层数
树的度:树中所有节点中最大的节点度

树中特殊的计算:

  • 一个二叉树第 i 层的最大结点数为:2^(i-1), i >= 1;
  • 深度为k的二叉树有最大结点总数为: 2^k - 1, k >= 1;
  • 对任何非空二叉树 T,若n0表示叶结点的个数、n2是度为2的 非叶结点个数,那么两者满足关系n0 = n2 + 1

特殊的树结构:

二叉树: 每一个节点最多可以有两个子节点(节点度为0-2的树)
二叉树

满二叉树:  一棵二叉树的结点要么是叶子结点,要么它有两个子结点(如果一个二叉树的层数为K,且结点总数是(2^k) -1,则它就是满二叉树。)

满二叉树

完全二叉树:  若设二叉树的深度为k,除第 k 层外,其它各层 (1~k-1) 的结点数都达到最大个数,第k 层所有的结点都连续集中在最左边,这就是完全二叉树。

完全二叉树
平衡二叉树: 左右子树高度相差不超过1
平衡二叉树

不平衡二叉树: 左右子树高度相差大于等于2

不平衡二叉树

2、树的特点

对于所有的树都具有以下特点:

  • 子树之间不可以相交
  • 除了根节点外,每个节点有且仅有一个父节点
  • 一颗N个节点的树有n-1条边

对二叉树:

  • 每个节点的度最大为2,节点的度为0-2
  • 树的度可能为0-2

在实际运用场景中,使用得最多的是二叉树的特殊实例——二叉搜索树,它具有二叉树的全部特点,并且:

  • 树中的节点一定有序,一般是升序
二、二叉搜索树的封装

二叉树常用数组或链表来实现,实际运用当中,使用链表是最好的,这里讲解使用链表封装二叉搜索树的详细过程:

1、创建二叉树节点:在节点中应该保存当前节点的数据、左边子节点、右边子节点

class Node{
   
    constructor(element){
   
        this.data = element;
        //左子节点
        this.left = null;
        //右子节点
        this.right = null;
    }
}

2、插入节点:首先创建二叉搜索树类BST(Binary Sort Tree的简写),在构造方法中定义一个变量root用于保存根节点;插入节点时仅需要一个参数即插入的数据,因为儿茶搜索树是有序的,因此,使用递归的方式来找到合适的位置插入节点,在插入节点时,需要创建一个辅助方法来实现递归。

//插入节点
    insert(element){
   
        let node = new Node(element);
        if(this.root == null){
   
            //当树为空时,直接将插入的节点当做根节点
            this.root = node;
        }else{
   
            //从根节点开始查找,在合适位置插入
            this.insertNode(this.root, node);
        }
    }
    //辅助方法
    insertNode(node, newNode){
   
        //根据大小决定插入在当前节点的左边还是右边
        if(newNode.data < node.data){
   
            if(node.left == null){
   
                //小于时放在左边,当左边节点为空时直接放在左边作为左边的节点
                node.left = newNode;
            }else{
   
                //当左边节点部位空时递归向下寻找
                this.insertNode(node.left, newNode);
            }
        }else{
   
            //当节点数据大于当前节点时,放在当前节点右边作为子节点
            if(node.right == null){
   
                //当前节点的右子节点为空时,直接插入作为右边子节点
                node.right = newNode;
            }else{
   
                //当前节点右子节点部位空时,递归向下寻找
                this.insertNode(node.right, newNode);
            }
        }
    }

3、先序遍历:根——左——右
在树中为提高效率,遍历树中节点时使用的是递归方式

//先序遍历  根-左-右
    preOderTraversal(callback){
   
    //callback是一个回调函数,仅用于输出当前遍历到的节点数据
    //data => {console.log(data)}
        //由根节点开始遍历
        this.preOderTraversalNode(this.root, callback);
    }
    //先序遍历节点(辅助方法)
    preOderTraversalNode(node, callback){
   
        if(node != null){
   
            callback(node.data);
            //递归遍历当前节点左子树
            this.preOderTraversalNode(node.left, callback);
            //递归遍历当前节点右子树
            this.preOderTraversalNode(node.right, callback);
        }
    }

4、中序遍历:左——根——右
通过中序遍历方法遍历出来的顺序是递增的

//中序遍历(升序)  左-根-右
    inOderTraversal(callback){
   
    //callback是一个回调函数,仅用于输出当前遍历到的节点数据
    //data => {console.log(data)}
        //从根节点开始
        this.inOderTraversalNode(this.root, callback);
    }
    //中序遍历节点(辅助方法)
    inOderTraversalNode(node, callback){
   
        if(node != null){
   
            //由根节点的左边开始遍历
            this.inOderTraversalNode(n
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值