【数据结构】二叉树的原理及实现学习总结

来源:互联网 发布:shell编程 ${ 编辑:程序博客网 时间:2024/05/21 07:56

二叉树概述

数组、向量、链表都是一种顺序容器,它们提供了按位置访问数据的手段。而很多情况下,我们需要按数据的值来访问元素,而不是它们的位置来访问元素。比如有这样一个数组int num[3]={1,2,3},我们可以非常快速的访问数组中下标为2的数据,也就是说我们知道这个数据的位置,就可以快速访问。有时候我们是不知道元素的位置,但是却知道它的值是多少。假设我们有一个变量,存放在num这个数组中,我们知道它的值为2,却不知道它下标是多少,也就是说不知道它的位置。这个时候再去数组中访问这个元素就比较费劲,就得遍历数组,而且还要保证数组中没有重复的元素。

二叉树在很大程度上解决了这个缺点,二叉树是按值来保存元素,也按值来访问元素。怎么做到呢,和链表一样,二叉树也是由一个个节点组成,不同的是链表用指针将一个个节点串接起来,形成一个链,如果将这个链“拉直”,就像平面中的一条线,是一维的。而二叉树由根节点开始发散,指针分别指向左右两个子节点,像树一样在平面上扩散,是二维的。示意图如下:
这里写图片描述

二叉树的定义:

二叉树是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树的形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。
二叉树(BinaryTree)是n(n≥0)个结点的有限集,它或者是空集(n=0),或者由一个根结点及两棵互不相交的、分别称作这个根的左子树和右子树的二叉树组成。
这个定义是递归的。由于左、右子树也是二叉树, 因此子树也可为空树。下图中展现了五种不同基本形态的二叉树。
这里写图片描述]![这里写图片描述]![这里写图片描述
其中 (a) 为空树, (b) 为仅有一个结点的二叉树, (c) 是仅有左子树而右子树为空的二叉树, (d) 是仅有右子树而左子树为空的二叉树, (e) 是左、右子树均非空的二叉树。这里应特别注意的是,二叉树的左子树和右子树是严格区分并且不能随意颠倒的,图 (c) 与图 (d) 就是两棵不同的二叉树。

二叉树的遍历

对于二叉树来讲最主要、最基本的运算是遍历。
遍历二叉树 是指以一定的次序访问二叉树中的每个结点。所谓 访问结点 是指对结点进行各种操作的简称。例如,查询结点数据域的内容,或输出它的值,或找出结点位置,或是执行对结点的其他操作。遍历二叉树的过程实质是把二叉树的结点进行线性排列的过程。假设遍历二叉树时访问结点的操作就是输出结点数据域的值,那么遍历的结果得到一个线性序列。
从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:
 (1)访问结点本身(N),
 (2)遍历该结点的左子树(L),
 (3)遍历该结点的右子树(R)。
以上三种操作有六种执行次序:
 NLR、LNR、LRN、NRL、RNL、RLN。
注意:
前三种次序与后三种次序对称,故只讨论先左后右的前三种次序。
  由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtlee)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。

二叉树的java实现

首先创建一棵二叉树如下图,然后对这颗二叉树进行遍历操作(遍历操作的实现分为递归实现和非递归实现),同时还提供一些方法如获取双亲结点、获取左孩子、右孩子等。
这里写图片描述

package com.zjn.tree;import java.util.Stack;/** * 二叉树的链式存储 *  * @author zjn */public class Tree {    private TreeNode root = null;    public Tree() {        root = new TreeNode(1, "rootNode(A)");    }    /**     * 二叉树的节点数据结构     *      */    private class TreeNode {        private int key = 0;        private String data = null;        private boolean isVisted = false;        private TreeNode leftChild = null;        private TreeNode rightChild = null;        /**         * @param key         *            层序编码         * @param data         *            数据域         */        public TreeNode(int key, String data) {            this.key = key;            this.data = data;            this.leftChild = null;            this.rightChild = null;        }    }    /**     * 创建一棵二叉树     *      * <pre>     *       *           A      *     B          C      *  D     E            F     * </pre>     *      * @param root     * @author WWX     */    public void createBinTree(TreeNode root) {        TreeNode newNodeB = new TreeNode(2, "B");        TreeNode newNodeC = new TreeNode(3, "C");        TreeNode newNodeD = new TreeNode(4, "D");        TreeNode newNodeE = new TreeNode(5, "E");        TreeNode newNodeF = new TreeNode(6, "F");        root.leftChild = newNodeB;        root.rightChild = newNodeC;        root.leftChild.leftChild = newNodeD;        root.leftChild.rightChild = newNodeE;        root.rightChild.rightChild = newNodeF;    }    public boolean isEmpty() {        return root == null;    }    // 树的高度    public int height() {        return height(root);    }    // 节点个数    public int size() {        return size(root);    }    private int height(TreeNode subTree) {        if (subTree == null)            return 0;// 递归结束:空树高度为0        else {            int i = height(subTree.leftChild);            int j = height(subTree.rightChild);            return (i < j) ? (j + 1) : (i + 1);        }    }    private int size(TreeNode subTree) {        if (subTree == null) {            return 0;        } else {            return 1 + size(subTree.leftChild) + size(subTree.rightChild);        }    }    // 返回双亲结点    public TreeNode parent(TreeNode element) {        return (root == null || root == element) ? null : parent(root, element);    }    public TreeNode parent(TreeNode subTree, TreeNode element) {        if (subTree == null)            return null;        if (subTree.leftChild == element || subTree.rightChild == element)            // 返回父结点地址            return subTree;        TreeNode p;        // 现在左子树中找,如果左子树中没有找到,才到右子树去找        if ((p = parent(subTree.leftChild, element)) != null)            // 递归在左子树中搜索            return p;        else            // 递归在右子树中搜索            return parent(subTree.rightChild, element);    }    public TreeNode getLeftChildNode(TreeNode element) {        return (element != null) ? element.leftChild : null;    }    public TreeNode getRightChildNode(TreeNode element) {        return (element != null) ? element.rightChild : null;    }    public TreeNode getRoot() {        return root;    }    // 在释放某个结点时,该结点的左右子树都已经释放,    // 所以应该采用后续遍历,当访问某个结点时将该结点的存储空间释放    public void destroy(TreeNode subTree) {        // 删除根为subTree的子树        if (subTree != null) {            // 删除左子树            destroy(subTree.leftChild);            // 删除右子树            destroy(subTree.rightChild);            // 删除根结点            subTree = null;        }    }    public void traverse(TreeNode subTree) {        System.out.println("key:" + subTree.key + "--name:" + subTree.data);        traverse(subTree.leftChild);        traverse(subTree.rightChild);    }    // 前序遍历    public void preOrder(TreeNode subTree) {        if (subTree != null) {            visted(subTree);            preOrder(subTree.leftChild);            preOrder(subTree.rightChild);        }    }    // 中序遍历    public void inOrder(TreeNode subTree) {        if (subTree != null) {            inOrder(subTree.leftChild);            visted(subTree);            inOrder(subTree.rightChild);        }    }    // 后续遍历    public void postOrder(TreeNode subTree) {        if (subTree != null) {            postOrder(subTree.leftChild);            postOrder(subTree.rightChild);            visted(subTree);        }    }    // 前序遍历的非递归实现    public void nonRecPreOrder(TreeNode p) {        Stack<TreeNode> stack = new Stack<TreeNode>();        TreeNode node = p;        while (node != null || stack.size() > 0) {            while (node != null) {                visted(node);                stack.push(node);                node = node.leftChild;            }            while (stack.size() > 0) {                node = stack.pop();                node = node.rightChild;            }        }    }    // 中序遍历的非递归实现    public void nonRecInOrder(TreeNode p) {        Stack<TreeNode> stack = new Stack<Tree.TreeNode>();        TreeNode node = p;        while (node != null || stack.size() > 0) {            // 存在左子树            while (node != null) {                stack.push(node);                node = node.leftChild;            }            // 栈非空            if (stack.size() > 0) {                node = stack.pop();                visted(node);                node = node.rightChild;            }        }    }    // 后序遍历的非递归实现    public void noRecPostOrder(TreeNode p) {        Stack<TreeNode> stack = new Stack<Tree.TreeNode>();        TreeNode node = p;        while (p != null) {            // 左子树入栈            for (; p.leftChild != null; p = p.leftChild) {                stack.push(p);            }            // 当前结点无右子树或右子树已经输出            while (p != null && (p.rightChild == null || p.rightChild == node)) {                visted(p);                // 纪录上一个已输出结点                node = p;                if (stack.empty())                    return;                p = stack.pop();            }            // 处理右子树            stack.push(p);            p = p.rightChild;        }    }    public void visted(TreeNode subTree) {        subTree.isVisted = true;        System.out.println("key:" + subTree.key + "--name:" + subTree.data);    }    // 测试    public static void main(String[] args) {        Tree bt = new Tree();        bt.createBinTree(bt.root);        System.out.println("the size of the tree is " + bt.size());        System.out.println("the height of the tree is " + bt.height());        System.out.println("*******(前序遍历)[ABDECF]遍历*****************");        bt.preOrder(bt.root);        System.out.println("*******(中序遍历)[DBEACF]遍历*****************");        bt.inOrder(bt.root);        System.out.println("*******(后序遍历)[DEBFCA]遍历*****************");        bt.postOrder(bt.root);        System.out.println("***非递归实现****(前序遍历)[ABDECF]遍历*****************");        bt.nonRecPreOrder(bt.root);        System.out.println("***非递归实现****(中序遍历)[DBEACF]遍历*****************");        bt.nonRecInOrder(bt.root);        System.out.println("***非递归实现****(后序遍历)[DEBFCA]遍历*****************");        bt.noRecPostOrder(bt.root);    }}
0 0
原创粉丝点击