# 数据结构 --- 二叉树

511 阅读4分钟

一、二叉树定义

   在计算机科学中,二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。
   一棵深度为k,且有2^k-1个结点的二叉树,称为满二叉树。这种树的特点是每一层上的结点数都是最大结点数。而在一棵二叉树中,除最后一层外,若其余层都是满的,并且或者最后一层是满的,或者是在右边缺少连续若干结点,则此二叉树为完全二叉树。具有n个结点的完全二叉树的深度为floor(log2n)+1。深度为k的完全二叉树,至少有2k-1个叶子结点,至多有2k-1个结点。

1.1基本概念

二叉树是递归定义的,其节点有左右子树之分,逻辑上二叉树有五种基本形态:

  • 空二叉树
  • 只有一个根节点的二叉树
  • 只有左子树
  • 只有右子树
  • 完全二叉树

注意:尽管二叉树与树有许多相似之处,但二叉树不是树的特殊情形

1.2类型

  1. 完全二叉树 ------若设二叉树的高度为h,除第h 层外,其他各层(1~h-1)的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到有依次排布,这就是完全二叉树

  2. 满二叉树 ------- 除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树

  3. 平衡二叉树 ------ 平衡二叉树又被称为AVL树,它是一颗二叉排序树,且具有以下性质:它是一棵空树或者它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树

1.3二叉树性质

  1. 在非空二叉树中,第i层的结点总数不超过,i>= 1;

  2. 深度为h 的二叉树最多有个阶段(h >= 1),最少有h个节点

  3. 对于任意一棵二叉树,如果其叶节点总数为NO,而度数为2的节点总数为N2,则N0 = N2 +1;

  4. 具有n个节点的完全二叉树的深度为

    5.有N个节点的完全二叉树各阶段如果用顺序方式存储,则结点之间有如下关系:

1.若l 为结点编号则如果l >1,则其父结点的编号为1/2;

2.如果2I<=N,则其左孩子(即左子树的根结点)的编号为2I;若2*I>N,则无左孩子;

3.如果2I+1<=N,则其右孩子的结点编号为2I+1;若2*I+1>N,则无右孩子

6.给定N个节点,能构成h(N)种不同的二叉树,h(N)为卡特兰数的第N项,h(n) = C(2*n,n)/(n+1)

7.设有i 个枝点,i 为所有枝点的道路长度总和,j为叶的道路长度总和j = l + 2i

1.4 二叉树遍历

遍历是对数的一种最基本的运算吗,所谓遍历二叉树,就是按一定的规则和顺序走遍二叉树的所有节点,使每一个节点都被访问一次,而且只被访问一次,由于二叉树是非线性结构,因此,树的遍历实质上是将二叉树的各个节点转换为一个线性序列来表示

  1. 先序遍历 首先访问根,再先序遍历左(右)子树

  2. 中序遍历

    首先遍历左(右)子树,再访问根,最后中序遍历右(左)子树

    3.后序遍历

首先后序遍历左(右)子树,再后序遍历右(左)子树,最后访问根

  1. 层次遍历

    即按照层次访问,通常用队列来做,访问根,访问子女,再访问子女的子女(越往后的层次越低)(两个子女的级别相同)

对该二叉树进行深度和广度遍历为:

  • 前序遍历:- + a b c / d e
  • 中序遍历:a + b c - d / e
  • 后序遍历:a b c + d e / -
  • 广度遍历:- + / a d e b c

1.5代码实现二叉树

/*二叉树的一个节点node由data,left,right组成,data保存本节点的值,left指向左节点,right指向右节点,二叉树有一个特性:相对本节点较小的值保存在左节点,相对本节点较大的值保存在右节点,该特性能让查值效率提高*/
​
function Node(data,left,right){
    this.data = data;
    this.left = left;
    this.right = right;
}
function BST(){
    this.root = null;
    this.insert = insert;
    this.find = find;
    this.remove = remove;
}
/*
* 二叉树增加节点
*/
function insert(data){
    var node = new Node(data,null,null);
    if(this.root == null){
        this.root = node;
    }else{
        var current = this.root;
        while(true){
            if(current.data > data){
                if(current.left === null){
                    current.left = node;
                    break;
                }
                current = current.left;
            }else{
                if(current.right === null){
                    current.right = node;
                    break;
                }
                current = current.right;
            }
        }
    }
}
/*
* 二叉树查节点
*/
function find(data){
    var current = this.root;
    while(true){
        if(data === current.data){
            return current;
        }
        current = data < current.data ? current.left : current.right;
        if(current === null){
            return null;
        }
    }
}
/*
* 二叉树删除节点 (只删除叶子节点、只有一个子节点的Node
*/
function remove(data){
    this.root = removeNode(this.root,data);
}
function removeNode(node,data){
    if(node === null){
        return null;
    }
    if(data === node.data){
        if(node.left === null && node.right === null){
            return null;
        }
        if(node.left === null){
            return node.right;
        }
        if(node.right === null){
            return node.left;
        }
    }else if(data < node.data){
        node.left = removeNode(node.left,data);
        return node;
    }else{
        node.right = removeNode(node.right,data);
        return node;
    }
}
var bst = new BST();
bst.insert(5);
bst.insert(3);
bst.insert(7);
bst.insert(2);
bst.remove(2);

\