zoukankan      html  css  js  c++  java
  • 算法——树

    树:

    定义:

    树是n个节点的有限集。n=0时称为空树。在任意一颗非空树中:(1)有且仅有一个特定的称为根(Root)的结点,(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1、T2、T3、……Tm,其中每一个集合本身又是一颗树,并称为根的子树,如下图

     

    概念:

    • 树的结点包含一个数据元素及若干指向其子树的分支。结点拥有的子树数称为结点的度(Degree)。度为0的结点称为叶结点(Leaf) 或终端结点;度不为0的结点称为非终端结点或分支结点。除根结点之外,分支结点也称为内部结点。树的度是树内各结点的度的最大值。因为这棵树结点的度的最大值是结点D的度为3,所以树的度也为3,如下图:

    •  结点的子树的根称为该结点的孩子,相应的,该结点称为孩子的双亲。同一个双亲的孩子之间互称兄弟,如下图:

    • 结点的层次从根开始,根为第一层,根的孩子为第二层。双亲在同一层的结点互为堂兄弟,树中结点的最大层次称为树的深度或者高度,如下图:

    树的父节点表示法:

      1 import java.util.ArrayList;
      2 import java.util.List;
      3 
      4 
      5 /**
      6  *   树的父节点表示法
      7  * @author wydream
      8  *
      9  */
     10 
     11 public class TreeParent<E> {
     12     
     13     //定义一个树类
     14     public static class Node<T>{
     15         T data;//保存数据
     16         int parent;//保存父节点的位置
     17         public Node(){
     18             
     19         }
     20         
     21         public Node(T data) {
     22             this.data=data;
     23         }
     24         
     25         //指定根节点
     26         public Node(T data,int parent) {
     27             this.data=data;
     28             this.parent=parent;
     29         }
     30         
     31         public String toString() {
     32             return "TreeParent$Node[data=" + data + ", parent=" + parent + "]";
     33         }
     34     }
     35     
     36     private final int DEFAULT_TREE_SIZE=100;//树的默认大小
     37     private int treeSize=0;//树的实际大小
     38     //使用一个node数组来记录该树里的所有节点
     39     private Node<E>[] nodes;
     40     //记录树的节点数
     41     private int nodeNums;
     42     
     43     //以指定节点创建树
     44     public TreeParent(E data) {
     45         treeSize=DEFAULT_TREE_SIZE;
     46         nodes=new Node[treeSize];
     47         nodes[0]=new Node<E>(data,-1);
     48         nodeNums++;
     49     }
     50     
     51     //以指定根节点、指定treeSize创建树
     52     public TreeParent(E data,int treeSize){
     53         this.treeSize=treeSize;
     54         nodes=new Node[treeSize];
     55         nodes[0]=new Node<E>(data,-1);
     56         nodeNums++;
     57     }
     58     
     59     //为指定节点添加子节点
     60     public void addNode(E data,Node<E> parent) {
     61         for(int i=0;i<treeSize;i++) {
     62             // 找到数组中第一个为null的元素,该元素保存新节点
     63             if(nodes[i]==null) {
     64                 nodes[i]=new Node<E>(data,pos(parent));
     65                 nodeNums++;
     66                 return;
     67             }
     68             // 创建新节点,并用指定的数组元素保存它
     69         }
     70         throw new RuntimeException("该树已满");
     71     }
     72     
     73     // 判断树是否为空
     74     public boolean isEmpty() {
     75         return nodes[0]==null;
     76     }
     77     
     78     // 返回根节点
     79     public Node<E> root() {
     80         return nodes[0];
     81     }
     82     
     83     // 返回指定节点(非根结点)的父节点
     84     public Node<E> parent(Node<E> node) {
     85         return nodes[node.parent];
     86     }
     87     
     88     // 返回指定节点(非叶子节点)的所有子节点
     89     public List<Node<E>> children(Node<E> parent){
     90         List<Node<E>> list=new ArrayList<Node<E>>();
     91         for(int i=0;i<treeSize;i++) {
     92             // 如果当前节点的父节点的位置等于parent节点的位置
     93             if(nodes[i]!=null&&nodes[i].parent==pos(parent)) {
     94                 list.add(nodes[i]);
     95             }
     96         }
     97         return list;
     98     }
     99     
    100     // 返回该树的深度
    101     public int deep() {
    102         //用于记录节点的最大深度
    103         int max=0;
    104         for(int i=0;i<treeSize&&nodes[i]!=null;i++) {
    105             //初始化本节点的深度
    106             int def=1;
    107             //m 记录当前节点的父节点的位置
    108             int m=nodes[i].parent;
    109             //如果其父节点存在
    110             while(m!=-1&&nodes[m]!=null) {
    111                 //向上继续搜索父节点
    112                 m=nodes[m].parent;
    113                 def++;
    114             }
    115             if(max<def) {
    116                 max=def;
    117             }
    118         }
    119         return max;
    120     }
    121     
    122     //返回包含指定值的节点
    123     public int pos(Node<E> node) {
    124         for(int i=0;i<treeSize;i++) {
    125             //找到指定节点
    126             if(nodes[i]==node) {
    127                 return i;
    128             }
    129         }
    130         return -1;
    131     }
    132     
    133     
    134     //测试
    135     public static void main(String[] args) {
    136         TreeParent<String> tp=new TreeParent<String>("root");
    137         TreeParent.Node root=tp.root();
    138         System.out.println(root);
    139         tp.addNode("节点1", root);
    140         System.out.println("此树的深度"+tp.deep());
    141         tp.addNode("节点2",root);
    142         //获取根节点的所有子节点
    143         List<TreeParent.Node<String>> nodes=tp.children(root);
    144         System.out.println("根节点的第一个子节点为:"+nodes.get(0));
    145         // 为根节点的第一个子节点新增一个子节点
    146         tp.addNode("节点3", nodes.get(0));
    147         System.out.println("此树的深度:" + tp.deep());
    148         
    149     }
    150 }

    程序运行结果:

    TreeParent$Node[data=root, parent=-1]
    此树的深度2
    根节点的第一个子节点为:TreeParent$Node[data=节点1, parent=0]
    此树的深度:3
    

      

    树的子节点表示法:

      1 import java.util.ArrayList;
      2 import java.util.List;
      3 
      4 /**
      5  *   树的子节点表示法
      6  * @author wydream
      7  *
      8  */
      9 
     10 
     11 public class TreeChild<E> {
     12 
     13     private static class SonNode{
     14         //记录当前节点的位置
     15         private int pos;
     16         private SonNode next;
     17         
     18         public SonNode(int pos,SonNode next) {
     19             this.pos=pos;
     20             this.next=next;
     21         }
     22         
     23     }
     24     
     25     public static class Node<T>{
     26         T data;
     27         SonNode first;//记录第一个子节点
     28         
     29         public Node(T data) {
     30             this.data=data;
     31             this.first=null;
     32         }
     33         
     34         public String toString() {
     35             if (first != null) {
     36                 return "TreeChild$Node[data=" + data + ", first=" + first.pos + "]";
     37             } else {
     38                 return "TreeChild$Node[data=" + data + ", first=-1]";
     39             }
     40         }
     41     }
     42     
     43     private final int DEFAULT_TREE_SIZE = 100;
     44     private int treeSize=0;
     45     
     46     // 使用一个Node[]数组来记录该树里的所有节点
     47     private Node<E>[] nodes;
     48     
     49     //记录节点数
     50     private int nodeNums;
     51     
     52     // 以指定根节点创建树    
     53     public TreeChild(E data) {
     54         treeSize=DEFAULT_TREE_SIZE;
     55         nodes=new Node[treeSize];
     56         nodes[0]=new Node<E>(data);
     57         nodeNums++;
     58     }
     59     
     60     // 以指定根节点、指定treeSize创建树
     61     public TreeChild(E data,int treeSize) {
     62         this.treeSize=treeSize;
     63         nodes=new Node[treeSize];
     64         nodes[0]=new Node<E>(data);
     65         nodeNums++;
     66     }
     67     
     68     // 为指定节点添加子节点    
     69     public void addNode(E data,Node parent) {
     70         for(int i=0;i<treeSize;i++) {
     71             // 找到数组中第一个为null的元素,该元素保存新节点
     72             if(nodes[i]==null) {
     73                 // 创建新节点,并用指定数组元素保存它
     74                 nodes[i]=new Node(data);
     75                 if(parent.first==null) {
     76                     parent.first=new SonNode(i, null);
     77                 }else {
     78                     SonNode next=parent.first;
     79                     while(next.next!=null) {
     80                         next=next.next;
     81                     }
     82                     next.next = new SonNode(i, null);
     83                 }
     84                 nodeNums++;
     85                 return;
     86             }
     87         }
     88         throw new RuntimeException("该树已满,无法添加节点");
     89     }
     90     
     91     //判断树是否为空
     92     public boolean isEmpty() {
     93         return nodes[0]==null;
     94     }
     95     
     96     //返回根节点
     97     public Node<E> root(){
     98         return nodes[0];
     99     }
    100     
    101     //返回指定节点的所有子节点
    102     public List<Node<E>> children(Node<E> parent){
    103         List<Node<E>> list=new ArrayList<Node<E>>();
    104         // 获取parent节点的第一个子节点
    105         SonNode next=parent.first;
    106         // 沿着孩子链不断搜索下一个孩子节点
    107         while(next!=null) {
    108             list.add(nodes[next.pos]);
    109             next=next.next;
    110         }
    111         return list;
    112     }
    113     
    114     // 返回指定节点(非叶子节点)的第index个子节点
    115     public Node<E> child(Node parent,int index){
    116         // 获取parent节点的第一个子节点
    117         SonNode next=parent.first;
    118         // 沿着孩子链不断搜索下一个孩子节点
    119         for(int i=0;next!=null;i++) {
    120             if(index==i) {
    121                 return nodes[next.pos];
    122             }
    123             next=next.next;
    124         }
    125         return null;
    126     }
    127     
    128     // 返回该树的深度
    129     public int deep() {
    130         // 获取该树的深度
    131         return deep(root());
    132     }
    133     
    134     // 这是一个递归方法:每棵子树的深度为其所有子树的最大深度 + 1
    135     public int deep(Node node) {
    136         if(node.first==null) {
    137             return 1;
    138         }else {
    139             // 记录其所有子树的最大深度
    140             int max=0;
    141             SonNode next=node.first;
    142             // 沿着孩子链不断搜索下一个孩子节点
    143             while(next!=null) {
    144                 // 获取以其子节点为根的子树的深度
    145                 int tmp=deep(nodes[next.pos]);
    146                 if(tmp>max) {
    147                     max=tmp;
    148                 }
    149                 next=next.next;
    150             }
    151             // 最后,返回其所有子树的最大深度 + 1
    152             return max + 1;
    153         }
    154     }
    155     
    156     
    157     // 返回包含指定值得节点
    158     public int pos(Node node) {
    159         for (int i = 0; i < treeSize; i++) {
    160             // 找到指定节点
    161             if (nodes[i] == node) {
    162                 return i;
    163             }
    164         }
    165         return -1;
    166     }
    167     
    168     //测试
    169     public static void main(String[] args) {
    170 
    171         TreeChild<String> tp = new TreeChild<String>("root");
    172         TreeChild.Node root = tp.root();
    173         System.out.println(root);
    174         tp.addNode("节点1", root);
    175         tp.addNode("节点2", root);
    176         tp.addNode("节点3", root);
    177         System.out.println("添加子节点后的根结点:" + root);
    178         System.out.println("此树的深度:" + tp.deep());
    179         // 获取根节点的所有子节点
    180         List<TreeChild.Node<String>> nodes = tp.children(root);
    181         System.out.println("根节点的第一个子节点:" + nodes.get(0));
    182         // 为根节点的第一个子节点新增一个子节点
    183         tp.addNode("节点4", nodes.get(0));
    184         System.out.println("此树第一个子节点:" + nodes.get(0));
    185         System.out.println("此树的深度:" + tp.deep());
    186 
    187     }
    188 
    189 
    190     
    191     
    192 }

    程序运行结果:

    TreeChild$Node[data=root, first=-1]
    添加子节点后的根结点:TreeChild$Node[data=root, first=1]
    此树的深度:2
    根节点的第一个子节点:TreeChild$Node[data=节点1, first=-1]
    此树第一个子节点:TreeChild$Node[data=节点1, first=4]
    此树的深度:3
    
  • 相关阅读:
    说说 Java 线程间通信
    Java 内存模型与内存结构
    Spring Boot 整合 Shiro
    HashMap 实现原理
    Spring Boot 自动配置原理
    Spring Cloud 全链路追踪实现
    JVM 类加载机制
    volatile 关键字的作用
    Spring Boot 整合 Redis
    Docker命令
  • 原文地址:https://www.cnblogs.com/wugongzi/p/11211287.html
Copyright © 2011-2022 走看看