二叉树的创建和遍历

一、二叉树的概念

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());
        }
    }

}
相关推荐
AI街潜水的八角33 分钟前
基于C++的决策树C4.5机器学习算法(不调包)
c++·算法·决策树·机器学习
白榆maple1 小时前
(蓝桥杯C/C++)——基础算法(下)
算法
JSU_曾是此间年少1 小时前
数据结构——线性表与链表
数据结构·c++·算法
许野平1 小时前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono
此生只爱蛋2 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
咕咕吖2 小时前
对称二叉树(力扣101)
算法·leetcode·职场和发展
齐 飞3 小时前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
九圣残炎3 小时前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
lulu_gh_yu3 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
LunarCod3 小时前
WorkFlow源码剖析——Communicator之TCPServer(中)
后端·workflow·c/c++·网络框架·源码剖析·高性能高并发