二叉树的创建和遍历

一、二叉树的概念

1、定义

每个节点最多只有2个子节点的树叫做二叉树。

2、特性

A、在二叉树的第i层上最多有2^(i-1)个结点(i>=1)。

B、高度为k的二叉树,最多有2^k-1个结点(k>=0)。

C、对任何一棵二叉树,如果其叶结点有n个,度为2的非叶子结点有m个,则n = m + 1。

D、具有n个结点的完全二叉树的高度为logn + 1

E、对于有n个结点的完全二叉树,按层次对结点进行编号(从上到下,从左到右),对于任意编号为i的结点:

二、二叉树构建

1、二叉树的存储实现

java 复制代码
public class BinaryNode<T> {

    /**
     * 数据
     */
    T data;

    /**
     * 左节点
     */
    private BinaryNode left;

    /***
     * 右节点
     */
    private BinaryNode right;


    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public BinaryNode getLeft() {
        return left;
    }

    public void setLeft(BinaryNode left) {
        this.left = left;
    }

    public BinaryNode getRight() {
        return right;
    }

    public void setRight(BinaryNode right) {
        this.right = right;
    }
}

2、二叉树的创建

java 复制代码
public class BinaryTree<T> {

    private BinaryNode<T> root;



    // 树节点总数
    private int size ;

    public BinaryTree(T data) {
        root = new BinaryNode<T>();
        root.setData(data);
        size = 1;
    }

    /**
     * 给节点添加左节点
     * @param parent
     * @param data
     * @return
     */
    public BinaryNode addLeftNode(BinaryNode parent,T data) {
        BinaryNode<T> left = new BinaryNode<T>();
        left.setData(data);
        parent.setLeft(left);
        size++;
        return left;
    }

    /**
     * 给节点添加右节点
     * @param parent
     * @param data
     * @return
     */
    public BinaryNode addRightNode(BinaryNode parent,T data) {
        BinaryNode<T> right = new BinaryNode<T>();
        right.setData(data);
        parent.setRight(right);
        size++;
        return right;
    }

    public BinaryNode<T> getRoot() {
        return root;
    }


    public int getSize() {
        return size;
    }


}

构造一颗二叉树,如下图

代码如下:

ini 复制代码
BinaryTree<String> binaryTree = new BinaryTree<String>("A");
BinaryNode n2 = binaryTree.addLeftNode(binaryTree.getRoot(), "B");
BinaryNode n3 = binaryTree.addRightNode(binaryTree.getRoot(), "C");

BinaryNode n4 = binaryTree.addLeftNode(n2, "D");
BinaryNode n5 = binaryTree.addRightNode(n2, "E");

BinaryNode n6 = binaryTree.addLeftNode(n3, "F");
BinaryNode n7 = binaryTree.addRightNode(n3, "G");

三、二叉树遍历

1、前序遍历

前序遍历(根左右): 访问根结点,再访问左子树、再访问右子树。 前序遍历: ABDECFG

递归实现

scss 复制代码
public List<T> preorderTraversal () {
    ArrayList<T> ts = new ArrayList<>();
    preorderTraversal(root,ts);
    return ts;
}

/**
 * 前序遍历
 * @param binaryNode 节点
 * @param result 结果的list
 */
private void preorderTraversal (BinaryNode<T> binaryNode, List<T> result) {
    // 节点不为空,
    if (binaryNode != null) {
        result.add(binaryNode.getData());
    }
    if (binaryNode.getLeft() != null) {
        preorderTraversal(binaryNode.getLeft(),result);
    }
    if (binaryNode.getRight() != null) {
        preorderTraversal(binaryNode.getRight(),result);
    }
}

非递归实现

用到栈(FILO 先进后出的特性)

过程:

arduino 复制代码
/**
 * 非递归的前序遍历
 * @return
 */
public List<T> noRecursivePreTraversal () {
    ArrayList<T> ts = new ArrayList<>();
    noRecursivePreTraversal(root,ts);
    return ts;
}

/***
 * 非递归的前序遍历
 * @param binaryNode
 * @param result
 */
private void noRecursivePreTraversal (BinaryNode<T> binaryNode,List<T> result) {
    // 借助stack来实现
    Stack<BinaryNode> stack = new Stack<>();
    // 迭代的停止条件
    while (binaryNode != null || stack.size() > 0) {
        // 一直向左边进行迭代
        while (binaryNode != null) {
            // 把当前节点添加到结果集中
            result.add(binaryNode.getData());
            // 节点进栈,为了后面好,进行回溯
            stack.add(binaryNode);
            // 向左进行迭代
            binaryNode = binaryNode.getLeft();
        }
        // 循环走完了,要进行出栈
        if (stack.size() > 0) {
            binaryNode = stack.pop();
            // 向右边走
            binaryNode = binaryNode.getRight();
        }
    }
}

2、中序遍历

中序遍历(左根右): 先访问左子树,再访问根结点、再访问右子树。 中序遍历: DBEAFCG

递归实现

scss 复制代码
/**
 * 中序遍历
 * @return
 */
public List<T> midTraversal() {
    ArrayList<T> ts = new ArrayList<>();
    midTraversal(root,ts);
    return ts;
}


private void  midTraversal(BinaryNode<T> binaryNode,List<T> result) {
    if (binaryNode != null) {
        if (binaryNode.getLeft() != null) {
            midTraversal(binaryNode.getLeft(),result);
        }
        result.add(binaryNode.getData());
        if (binaryNode.getRight() != null) {
            midTraversal(binaryNode.getRight(),result);
        }
    }
}

非递归实现

csharp 复制代码
/**
 * 非递归中序遍历
 * @return
 */
public List<T> noRecursiveMidTraversal() {
    ArrayList<T> ts = new ArrayList<>();
    noRecursiveMidTraversal(root,ts);
    return ts;
}

private void  noRecursiveMidTraversal(BinaryNode<T> binaryNode,List<T> result) {
    // 借助栈
    Stack<BinaryNode> stack = new Stack<>();
    // 栈不为空
    while (!stack.isEmpty() || binaryNode !=null) {
        // 一直向左迭代
        while (binaryNode != null) {
            stack.add(binaryNode);
            binaryNode = binaryNode.getLeft();
        }
        // 出栈
        binaryNode = stack.pop();
        //  保存结果集
        result.add(binaryNode.getData());
        binaryNode = binaryNode.getRight();
    }

}

3、后序遍历

后续遍历(左右根): 先访问左子树,再访问右子树,再访问根结点。 后续遍历: DEBFGCA

递归实现

scss 复制代码
/**
 * 后序遍历
 * @return
 */
public List<T> afterTraversal() {
    ArrayList<T> ts = new ArrayList<>();
    afterTraversal(root,ts);
    return ts;
}


private void  afterTraversal(BinaryNode<T> binaryNode,List<T> result) {
    if (binaryNode != null) {
        // 先左节点
        if (binaryNode.getLeft() != null) {
            afterTraversal(binaryNode.getLeft(),result);
        }
        // 再右节点
        if (binaryNode.getRight() != null) {
            afterTraversal(binaryNode.getRight(),result);
        }
        // 父节点
        result.add(binaryNode.getData());
    }
}

非递归实现

scss 复制代码
/**
 * 后序遍历
 * @return
 */
public List<T> noRecursiveAfterTraversal() {
    ArrayList<T> ts = new ArrayList<>();
    noRecursiveAfterTraversal(root,ts);
    return ts;
}



private void  noRecursiveAfterTraversal(BinaryNode<T> binaryNode,List<T> result) {

    Stack<BinaryNode> stackA = new Stack<>();
    Stack<BinaryNode> stackB = new Stack<>();

    stackA.push(binaryNode);

    while (!stackA.isEmpty()) {
        binaryNode = stackA.pop();
        stackB.push(binaryNode);
        // 左边有节点
        if (binaryNode.getLeft() != null) {
            stackA.push(binaryNode.getLeft());
        }
        // 右边有节点
        if (binaryNode.getRight() != null) {
            stackA.push(binaryNode.getRight());
        }
    }

    while (!stackB.isEmpty()) {
        BinaryNode<T> pop = stackB.pop();
        result.add(pop.getData());
    }
}

4、二叉树层序遍历(BFS)

用到队列(FIFO 先进先出的特性)代码后有队列和其中元素的关系具体过程,建议静下心来慢慢看,有助于理解代码如何运行

scss 复制代码
/**
 * 层序遍历
 * @return
 */
public List<T> bfsTraversal() {
    ArrayList<T> ts = new ArrayList<>();
    bfsTraversal(root,ts);
    return ts;
}

private void  bfsTraversal(BinaryNode<T> binaryNode,List<T> result) {
    // 借助队列
    Queue<BinaryNode> queue = new ArrayDeque();
    if (binaryNode != null) {
        queue.add(binaryNode);
    }
    // 队列不为空
    while (!queue.isEmpty() ) {
        // 出队
        binaryNode = queue.poll();
        result.add(binaryNode.getData());
        // 左边有节点
        if (binaryNode.getLeft() != null) {
            queue.add(binaryNode.getLeft());
        }
        // 右边有节点
        if (binaryNode.getRight() != null) {
            queue.add(binaryNode.getRight());
        }
    }

}
相关推荐
程序员阿达几秒前
开题报告之基于SpringBoot框架的路面故障信息上报系统设计与实现
java·spring boot·后端
用户3421674905523 分钟前
鱼皮模拟面试,吊打面试官
后端
夜晚中的人海3 分钟前
【C++】滑动窗口算法习题
开发语言·c++·算法
violet-lz37 分钟前
数据结构四大简单排序算法详解:直接插入排序、选择排序、基数排序和冒泡排序
数据结构·算法·排序算法
·白小白41 分钟前
力扣(LeetCode) ——118.杨辉三角(C++)
c++·算法·leetcode
我是天龙_绍1 小时前
java 中的 Lombok
后端
hwangsy1 小时前
SpringCloud gateway偶发creationTime key must not be null
后端
初见0011 小时前
Spring事务失效的十大陷阱与终极解决方案
后端·架构
子夜master1 小时前
玩转EasyExcel,看这一篇就够了!!(合并导入 自定义导出 动态表头 合并单元格)
后端
武子康1 小时前
大数据-131 Flink CEP 实战 24 小时≥5 次交易 & 10 分钟未支付检测 案例附代码
大数据·后端·flink