数据结构:树

树的定义

一棵树是一些节点的集合。这个集合可以为空集,若不为空,那么树由根节点A以及0个或多个非空的子树 T 1 T_{1} T1, T 2 T_{2} T2, •••, T k T_{k} Tk组成,这些子树中每一棵的根,都由来自根A的一条有向边所连接。
在这里插入图片描述

  1. 每一棵子树的根叫做根A的儿子,而根A是每一棵子树的父亲。
  2. 没有儿子的节点叫树叶。
  3. 具有相同父亲的节点称为兄弟。
  4. 从根A节点到 n i n_{i} ni唯一路径长为 n i n_{i} ni的深度。如根A的深度为0,T1的深度为1。
  5. n i n_{i} ni的高:从 n i n_{i} ni到一片树叶的最长路径。

树的实现

下图为window的C盘文件夹的部分目录结构:
在这里插入图片描述
将每个节点的所有儿子都放到树节点的链表中:

//树节点
public class TreeNode<T> {
    
    private T data;//数据域
    private TreeNode firstChild;//表示节点的第一个儿子
    private TreeNode nearNode;//与自己相邻的兄弟
    
}

则上图变成:
在这里插入图片描述
图中向下的箭头是firstChild(节点的第一个儿子)的链,水平箭头表示nearNode(与自己相邻的兄弟)。

树的遍历

利用上图C盘的树为例子:

创建树

public class Tree {
    /**
     * 创建树
     */
    public TreeNode creatTree() {
        //建立各节点
        TreeNode<String> nodeA = new TreeNode<>("C盘");
        TreeNode<String> nodeB = new TreeNode<>("window");
        TreeNode<String> nodeC = new TreeNode<>("bootmgr");
        TreeNode<String> nodeD = new TreeNode<>("program file");
        TreeNode<String> nodeE = new TreeNode<>("用户");
        TreeNode<String> nodeF = new TreeNode<>("addins");
        TreeNode<String> nodeG = new TreeNode<>("AppCompat");
        TreeNode<String> nodeH = new TreeNode<>("Help");
        TreeNode<String> nodeI = new TreeNode<>("Common Files");
        TreeNode<String> nodeJ = new TreeNode<>("Intel");
        TreeNode<String> nodeK = new TreeNode<>("Administrator");
        TreeNode<String> nodeL = new TreeNode<>("Default User");
        //各节点的关系
        nodeA.setFirstChild(nodeB);
        nodeB.setFirstChild(nodeF);
        nodeB.setNearNode(nodeC);
        nodeC.setNearNode(nodeD);
        nodeD.setFirstChild(nodeI);
        nodeD.setNearNode(nodeE);
        nodeE.setFirstChild(nodeK);
        nodeF.setNearNode(nodeG);
        nodeG.setNearNode(nodeH);
        nodeI.setNearNode(nodeJ);
        nodeK.setNearNode(nodeL);
        return nodeA;
    }
}

迭代法遍历

    public void printAll(TreeNode node) {
    	//节点不为空则打印当前节点数据
        if (node != null) {
            System.out.println(node.getData());
            //如果第一个儿子不为空,则迭代继续找子节点的第一个儿子节点,直到返回null
            if (node.getFstChild() != null) {
                printAll(node.getFirstChild());
            }
            //找完第一个儿子,继续找寻找相邻兄弟节点,迭代查找兄弟的兄弟节点。
            if (node.getNearNode() != null) {
                printAll(node.getNearNode());
            }
        }
    }

广度优先遍历

在这里插入图片描述
入队顺序:

  1. 当头结点A入队。
  2. 头结点A出队,A的第一个儿子节点B入队。
  3. 队头B出队。B的第一个儿子节点F入队,B的相邻兄弟节点C入队,此时对列中从队头到队尾排序为:F、C。
  4. 队头F出队。F的相邻兄弟节点G入队,此时对列中从队头到队尾排序为:C、G。
  5. 队头C出队。C的相邻兄弟节点D入队,此时对列中从队头到队尾排序为:G、D。

    最后依次打印:A、B、F、C、G、D、H、I、E、J、K、L。
   /**
    * 广度优先遍历 (Breadth FirstSearch)
    * 用到对列数据结构
    */
   public void printBFS(TreeNode root) {
       if (root == null) {
           return;
       }

       Queue<TreeNode> queue = new LinkedList<>();
       //添加根节点
       queue.offer(root);

       while (!queue.isEmpty()) {
           //出队
           TreeNode firstNode = queue.poll();
           System.out.println(firstNode.getData());
           //第一个儿子节点入队
           TreeNode firstChild = firstNode.getFirstChild();
           if (firstChild != null) {
               queue.offer(firstChild);
           }
           //相邻兄弟节点入队
           TreeNode nearNode = firstNode.getNearNode();
           if (nearNode != null) {
               queue.offer(nearNode);
           }
       }
   }

深度优先遍历

在这里插入图片描述
入栈顺序:

  1. 当头结点A入栈。
  2. 头结点A出栈,A的第一个儿子B入栈。
  3. 队头B出栈。B的第一个儿子F入栈,B的相邻兄弟C入栈。此时栈:C、F。
  4. 队头C出栈。C的相邻兄弟D入栈,此时栈:D、F。
  5. 队头D出队。D的第一个儿子I入队,D的相邻兄弟E入栈。此时栈:E、I、B。

    最后依次打印:A、B、C、D、E、K、L、I、J、F、G、H。
	/**
     * 深度优先遍历(Depth First Search)
     * 用到栈数据结构
     */
    public void printDFS(TreeNode root){
        if (root == null) {
            return;
        }
        
        Stack<TreeNode> stack = new Stack<>();
        //根节点入栈
        stack.push(root);

        while (!stack.isEmpty()) {
            //出栈
            TreeNode firstNode = stack.pop();
            System.out.println(firstNode.getData());
            //第一个儿子节点入栈
            TreeNode firstChild = firstNode.getFirstChild();
            if (firstChild != null) {
                stack.push(firstChild);
            }
            //相邻兄弟节点入队
            TreeNode nearNode = firstNode.getNearNode();
            if (nearNode != null) {
                stack.push(nearNode);
            }
        }
    }

数据结构与算法分析
大话数据结构

上一节 : 数据结构:队列

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值