Java数据结构算法(三)树

本文旨作于收集整理使用!!

导航

一、树

树(Tree)是n(n≥0)个结点的有限集,n=0称之为空树。在非空树种:当有且仅有一个特定的称为根(Root)的结点; 其余结点可以划分为m(m>0)个互不相交的有限集T1、T2 、…、Tm,每个集Ti(1≤i≤m)均为树,且称为树的子树(SubTree), 如下图所示。


  • 根节点:根节点指没有双亲结点的结点,一棵树中最多有一个根节点(如A)
  • 叶子结点:没有孩子结点的结点叫作叶子结点(如L、M、F)
  • 兄弟结点:拥有相同双亲结点的所有孩子结点叫作兄弟结点(L、M是E的兄弟结点,I、J、K是D的兄弟结点)
  • 结点的深度:是指从根节点到该节点的路径长度(O点的深度为3,A—C—G—O)
  • 树的高度:是树中所有结点高度的最大值,树的深度是树中所有结点深度的最大值,对于同一棵树,其深度和高度是相同的,但是对于各个结点,其深度和高度不一定相同

二、二叉树

二叉树(Binary Tree)是n(n>=0)个节点的有限集合,该集合或为空集,或为由一个根节点和两颗互不相交的,分别称为根节点的左子树和右子树的二叉树组成。


二叉树
  1. 所有节点只有左子树的二叉树称为左斜树,只有右子树的二叉树称为右斜树

  2. 所有节点均含左子树和右子树,这样的二叉树称为满二叉树

    满二叉树

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

    完全二叉树

    二叉树的应用:编译器中的表达式树、用于数据压缩算法中的赫夫曼编码树、支持在集合中查找、插入和删除,其平均时间复杂度为O(lognn)的二叉搜索树(BST)、优先队列(PQ),它支持以对数时间(最坏情况下)对集合中的最小(或最大)数据元素进行搜索和删除;


1、二叉树的存储结构

基本了解了二叉树的组成后,我们学习怎么样去存储二叉树,了解二叉树的存储结构。

1.1、满二叉树

存储满二叉树可以使用数组,我们将上图中的满二叉树存储为数组为[A,B,C,D,E,F,G]),当然我们通过数组复原二叉树时也可以按照顺序复原二叉树。

1.2、完全二叉树

完全二叉树和满二叉树的存储方法相同,上图中的完全二叉树转换为数组([A,B,C,D,E,F,G,H,I])(图中最后的H为I)。

1.2、其他二叉树

有的二叉树既不是满二叉树又不是完全二叉树该如何存储?我们可以将缺少的二叉树的叶子节点用一些特殊的符号存储,将其转换为完全二叉树,如下图所示。


则如上图中的二叉树转换为数组([A,B,C,D,E,F,G,#.#,H,#,#,#,I,J]


2二叉树的遍历

二叉树的遍历分为前序遍历、中序遍历和后序遍历

3.1 前序遍历

先遍历左子树,再遍历右子树

2.2、 中序遍历

从根结点开始(注意并不是先访问根结点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树

2.3 后序遍历

从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根结点

3、实现二叉树

如下,需要构建如下二叉树,并实现其三种遍历方法


/**
 * 构造如下二叉树
 *            A
 *      B           C
 * D        E            G
 *
 */
import java.util.List;

/**
 * 构造如下二叉树
 * A
 * B           C
 * D        E            G
 */
public class BinaryTree {
    TreeNode root = null;

    public BinaryTree() {
        root = new TreeNode(0, "A");
    }

    /**
     * 传统方法构造二叉树
     */
    public void createBinaryTree() {
        TreeNode nodeB = new TreeNode(2, "B");
        TreeNode nodeC = new TreeNode(3, "C");
        TreeNode nodeD = new TreeNode(4, "D");
        TreeNode nodeE = new TreeNode(5, "E");
        TreeNode nodeF = new TreeNode(6, "F");
        root.leftChild = nodeB;
        root.rightChild = nodeC;
        nodeB.leftChild = nodeD;
        nodeB.rightChild = nodeE;
        nodeC.rightChild = nodeF;
    }

    /**
     * 出入二叉树的数组,创建二叉树
     *
     * @param size  二叉树所有节点的数量和
     * @param datas 二叉树的List集合
     * @return 返回创建的节点
     */
    public TreeNode createBinerTree(int size, List<String> datas) {
        TreeNode node = null;
        if (datas.size() == 0) {
            return null;
        }
        String data = datas.get(0);
        if ("#".equals(data)) {
            datas.remove(0);
            return node;
        }
        int index = size - datas.size();
        node = new TreeNode(index, data);
        if (index == 0) {
            root = node;
        }
        datas.remove(0);
        node.leftChild = createBinerTree(size, datas);
        node.rightChild = createBinerTree(size, datas);
        return node;
    }

    /**
     * 前序遍历
     */
    public void preOrder(TreeNode node) {
        if (node == null) {
            return;
        } else {
            System.out.println("preOrder data:" + node.getData());
            preOrder(node.leftChild);
            preOrder(node.rightChild);
        }
    }


    /**
     * 中序遍历
     */
    public void midOrder(TreeNode node) {
        if (node == null) {
            return;
        } else {
            midOrder(node.leftChild);
            System.out.println("midOrder data:" + node.getData());
            midOrder(node.rightChild);
        }
    }

    /**
     * 后序遍历
     */
    public void postOrder(TreeNode node) {
        if (node == null) {
            return;
        } else {
            preOrder(node.leftChild);
            preOrder(node.rightChild);
            System.out.println("postOrder data:" + node.getData());
        }
    }

    class TreeNode {
        private int index;
        private String data;
        private TreeNode leftChild;
        private TreeNode rightChild;

        public TreeNode(int index, String data) {
            this.index = index;
            this.data = data;
        }

        public TreeNode getLeftChild() {
            return leftChild;
        }

        public void setLeftChild(TreeNode leftChild) {
            this.leftChild = leftChild;
        }

        public TreeNode getRightChild() {
            return rightChild;
        }

        public void setRightChild(TreeNode rightChild) {
            this.rightChild = rightChild;
        }

        public int getIndex() {
            return index;
        }

        public void setIndex(int index) {
            this.index = index;
        }

        public String getData() {
            return data;
        }

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

传入数组测试

public class test {
    public static void main(String[] args) {
        BinaryTree binaryTree=new BinaryTree();
        String data[]={"A","B","C","D","E","#","F"};
        ArrayList<String>datas=new ArrayList<>(Arrays.asList(data));
        binaryTree.createBinerTree(datas.size(), datas);
        binaryTree.preOrder(binaryTree.root);
    }
}

结果

preOrder data:A
preOrder data:B
preOrder data:C
preOrder data:D
preOrder data:E
preOrder data:F

三、搜索二叉树

二叉查找树(又:二叉搜索树,二叉排序树),它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。二叉排序树的查找过程和次优二叉树类似,通常采取二叉链表作为二叉排序树的存储结构中序遍历二叉排序树可得到一个关键字的有序序列,一个无序序列可以通过构造一棵二叉排序树变成一个有序序列,构造树的过程即为对无序序列进行排序的过程。每次插入的新的结点都是二叉排序树上新的叶子结点,在进行插入操作时,不必移动其它结点,只需改动某个结点的指针,由空变为非空即可

1、搜索二叉树的实现

/**
 * Author: Active_Loser
 * Date: 2018/7/30 23:17
 * Content: 实现搜索二叉树的建立、添加、删除等操作
 */
public class SearchBinryTree {
    public TreeNode root;

    public TreeNode put(int data) {
        TreeNode node;
        TreeNode parent = null;
        if (root == null) {
            node = new TreeNode(data);
            root = node;
            return node;
        }
        node = root;
        while (node != null) {
            parent = node;
            if (data > parent.data) {
                node = parent.rightChild;
            } else if (data < parent.data) {
                node = parent.leftChild;
            } else {
                return node;
            }
        }
        node = new TreeNode(data);
        if (data < parent.data) {
            parent.leftChild = node;
            node.parent = parent;
        } else if (data > parent.data) {
            parent.rightChild = node;
            node.parent = parent;
        }
        return node;
    }

    public TreeNode search(int value) {
        TreeNode node = root;
        while (node != null && node.data != value) {
            if (node.data > value) {
                node = node.rightChild;
            } else if (node.data < value) {
                node = node.leftChild;
            }
        }
        return node;
    }

    /**
     * @param value 删除的数值
     * @return 返回删除的节点
     */
    public TreeNode delete(int value) {
        //判断是否包含需要删除的数
        TreeNode deleteNode = search(value);
        if (null == deleteNode) {
            return null;
        }else {
            delete(deleteNode);
        }
    }

    private void delete(TreeNode node) {
        if (node==null){
            return null;
        }
        TreeNode parent=node.parent;
        //做节点与有节点皆为NULL
        if (node.leftChild==null&&node.rightChild==null){
            if (parent.leftChild==node){
                parent.leftChild=null;
            }else {
                parent.rightChild=null;
            }  
            return;
        }
        //有左节点没有右节点1.父节点的左节点2.父节点的右节点
        if (node.leftChild!=null&&node.rightChild==null){
            if (parent.leftChild==node){
                parent.leftChild=node.leftChild;
            }else if (parent.rightChild==node){
                parent.rightChild=node.leftChild;
            }
             return;
      }
        //有右节点没有左节点1.父节点的左节点2.父节点的右节点
        if (node.leftChild!=null&&node.rightChild==null){
            if (parent.leftChild==node){
                parent.leftChild=node.rightChild;
            }else if (parent.rightChild==node){
                parent.rightChild=node.rightChild;
            }
             return;
        }
        //既有左节点也有右节点
        //获取删除节点的后继节点
        TreeNode next=getNextNode(node);
        delete(next);
        node.data=next.data;
    }


    private TreeNode getNextNode(TreeNode node) {
        if (node==null){
            return null;
        }else {
            if (node.rightChild!=null){
                return getMinTreeNode(node.rightChild);
            }else {
                TreeNode parent=node.parent;
                while (parent!=null&&node==parent.rightChild){
                    node=parent;
                    parent=parent.parent;
                }
                return parent;  
            }
        }
        return null;
    }


  //右子树最小值,左子树最大值
    public TreeNode getMinTreeNode(TreeNode node){
        if (node==null){
            return null;
        }else {
            while (node.leftChild !=null){
                node=node.leftChild;
            }
        }
        return node;
    }

    public void midOrder(TreeNode node) {
        if (node == null) {
            return;
        } else {
            midOrder(node.leftChild);
            System.out.println("midOrder:" + node.data);
            midOrder(node.rightChild);
        }
    }

    class TreeNode {
        private TreeNode leftChild;
        private TreeNode rightChild;
        private TreeNode parent;
        private int data;

        public TreeNode(int data) {
            this.data = data;
        }

        public TreeNode getLeftChild() {
            return leftChild;
        }

        public void setLeftChild(TreeNode leftChild) {
            this.leftChild = leftChild;
        }

        public TreeNode getRightChild() {
            return rightChild;
        }

        public void setRightChild(TreeNode rightChild) {
            this.rightChild = rightChild;
        }

        public TreeNode getParent() {
            return parent;
        }

        public void setParent(TreeNode parent) {
            this.parent = parent;
        }

        public int getData() {
            return data;
        }

        public void setData(int data) {
            this.data = data;
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,809评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,189评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,290评论 0 359
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,399评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,425评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,116评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,710评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,629评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,155评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,261评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,399评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,068评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,758评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,252评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,381评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,747评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,402评论 2 358

推荐阅读更多精彩内容

  • 目录 1、什么是树 2、相关术语 3、二叉树 3.1、二叉树的类型 3.2、二叉树的性质 3.3、二叉树的结构 3...
    我哈啊哈啊哈阅读 2,564评论 0 10
  • 一些概念 数据结构就是研究数据的逻辑结构和物理结构以及它们之间相互关系,并对这种结构定义相应的运算,而且确保经过这...
    Winterfell_Z阅读 5,845评论 0 13
  • 数据结构和算法--二叉树的实现 几种二叉树 1、二叉树 和普通的树相比,二叉树有如下特点: 每个结点最多只有两棵子...
    sunhaiyu阅读 6,473评论 0 14
  • 1.树(Tree): 树是 n(n>=0) 个结点的有限集。当 n=0 时称为空树。在任意一颗非空树中:有且仅有一...
    ql2012jz阅读 1,007评论 0 3
  • 我站在马路的街道上, 汽笛声和耳鸣声在我耳畔响起 此时正值酷夏 两旁都是绿茵茵的白杨树 它们, 一半在阳光里飞扬,...
    一抹歆绿阅读 190评论 0 0