专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

算法——树

树:

定义:

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

112_1.png

概念:

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

112_2.png

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

112_3.png

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

112_4.png

树的父节点表示法:

 import java.util.ArrayList;
 import java.util.List;

 /**
  *   树的父节点表示法
  * @author wydream
  *
  */

 public class TreeParent<E> {

     //定义一个树类
     public static class Node<T>{
         T data;//保存数据
         int parent;//保存父节点的位置
         public Node(){

         }

         public Node(T data) {
             this.data=data;
         }

         //指定根节点
         public Node(T data,int parent) {
             this.data=data;
             this.parent=parent;
         }

         public String toString() {
             return "TreeParent$Node[data=" + data + ", parent=" + parent + "]";
         }
     }

     private final int DEFAULT_TREE_SIZE=100;//树的默认大小
     private int treeSize=0;//树的实际大小
     //使用一个node数组来记录该树里的所有节点
     private Node<E>[] nodes;
     //记录树的节点数
     private int nodeNums;

     //以指定节点创建树
     public TreeParent(E data) {
         treeSize=DEFAULT_TREE_SIZE;
         nodes=new Node[treeSize];
         nodes[0]=new Node<E>(data,-1);
         nodeNums++;
     }

     //以指定根节点、指定treeSize创建树
     public TreeParent(E data,int treeSize){
         this.treeSize=treeSize;
         nodes=new Node[treeSize];
         nodes[0]=new Node<E>(data,-1);
         nodeNums++;
     }

     //为指定节点添加子节点
     public void addNode(E data,Node<E> parent) {
         for(int i=0;i<treeSize;i++) {
             // 找到数组中第一个为null的元素,该元素保存新节点
             if(nodes[i]==null) {
                 nodes[i]=new Node<E>(data,pos(parent));
                 nodeNums++;
                 return;
             }
             // 创建新节点,并用指定的数组元素保存它
         }
         throw new RuntimeException("该树已满");
     }

     // 判断树是否为空
     public boolean isEmpty() {
         return nodes[0]==null;
     }

     // 返回根节点
     public Node<E> root() {
         return nodes[0];
     }

     // 返回指定节点(非根结点)的父节点
     public Node<E> parent(Node<E> node) {
         return nodes[node.parent];
     }

     // 返回指定节点(非叶子节点)的所有子节点
     public List<Node<E>> children(Node<E> parent){
         List<Node<E>> list=new ArrayList<Node<E>>();
         for(int i=0;i<treeSize;i++) {
             // 如果当前节点的父节点的位置等于parent节点的位置
             if(nodes[i]!=null&&nodes[i].parent==pos(parent)) {
                 list.add(nodes[i]);
             }
         }
         return list;
     }

     // 返回该树的深度
     public int deep() {
         //用于记录节点的最大深度
         int max=0;
         for(int i=0;i<treeSize&&nodes[i]!=null;i++) {
             //初始化本节点的深度
             int def=1;
             //m 记录当前节点的父节点的位置
             int m=nodes[i].parent;
             //如果其父节点存在
             while(m!=-1&&nodes[m]!=null) {
                 //向上继续搜索父节点
                 m=nodes[m].parent;
                 def++;
             }
             if(max<def) {
                 max=def;
             }
         }
         return max;
     }

     //返回包含指定值的节点
     public int pos(Node<E> node) {
         for(int i=0;i<treeSize;i++) {
             //找到指定节点
             if(nodes[i]==node) {
                 return i;
             }
         }
         return -1;
     }

     //测试
     public static void main(String[] args) {
         TreeParent<String> tp=new TreeParent<String>("root");
         TreeParent.Node root=tp.root();
         System.out.println(root);
         tp.addNode("节点1", root);
         System.out.println("此树的深度"+tp.deep());
         tp.addNode("节点2",root);
         //获取根节点的所有子节点
         List<TreeParent.Node<String>> nodes=tp.children(root);
         System.out.println("根节点的第一个子节点为:"+nodes.get(0));
         // 为根节点的第一个子节点新增一个子节点
         tp.addNode("节点3", nodes.get(0));
         System.out.println("此树的深度:" + tp.deep());

     }
 }

程序运行结果:

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

  

树的子节点表示法:

 import java.util.ArrayList;
 import java.util.List;

 /**
  *   树的子节点表示法
  * @author wydream
  *
  */

 public class TreeChild<E> {

     private static class SonNode{
         //记录当前节点的位置
         private int pos;
         private SonNode next;

         public SonNode(int pos,SonNode next) {
             this.pos=pos;
             this.next=next;
         }

     }

     public static class Node<T>{
         T data;
         SonNode first;//记录第一个子节点

         public Node(T data) {
             this.data=data;
             this.first=null;
         }

         public String toString() {
             if (first != null) {
                 return "TreeChild$Node[data=" + data + ", first=" + first.pos + "]";
             } else {
                 return "TreeChild$Node[data=" + data + ", first=-1]";
             }
         }
     }

     private final int DEFAULT_TREE_SIZE = 100;
     private int treeSize=0;

     // 使用一个Node[]数组来记录该树里的所有节点
     private Node<E>[] nodes;

     //记录节点数
     private int nodeNums;

     // 以指定根节点创建树    
     public TreeChild(E data) {
         treeSize=DEFAULT_TREE_SIZE;
         nodes=new Node[treeSize];
         nodes[0]=new Node<E>(data);
         nodeNums++;
     }

     // 以指定根节点、指定treeSize创建树
     public TreeChild(E data,int treeSize) {
         this.treeSize=treeSize;
         nodes=new Node[treeSize];
         nodes[0]=new Node<E>(data);
         nodeNums++;
     }

     // 为指定节点添加子节点    
     public void addNode(E data,Node parent) {
         for(int i=0;i<treeSize;i++) {
             // 找到数组中第一个为null的元素,该元素保存新节点
             if(nodes[i]==null) {
                 // 创建新节点,并用指定数组元素保存它
                 nodes[i]=new Node(data);
                 if(parent.first==null) {
                     parent.first=new SonNode(i, null);
                 }else {
                     SonNode next=parent.first;
                     while(next.next!=null) {
                         next=next.next;
                     }
                     next.next = new SonNode(i, null);
                 }
                 nodeNums++;
                 return;
             }
         }
         throw new RuntimeException("该树已满,无法添加节点");
     }

     //判断树是否为空
     public boolean isEmpty() {
         return nodes[0]==null;
     }

     //返回根节点
     public Node<E> root(){
         return nodes[0];
     }

     //返回指定节点的所有子节点
     public List<Node<E>> children(Node<E> parent){
         List<Node<E>> list=new ArrayList<Node<E>>();
         // 获取parent节点的第一个子节点
         SonNode next=parent.first;
         // 沿着孩子链不断搜索下一个孩子节点
         while(next!=null) {
             list.add(nodes[next.pos]);
             next=next.next;
         }
         return list;
     }

     // 返回指定节点(非叶子节点)的第index个子节点
     public Node<E> child(Node parent,int index){
         // 获取parent节点的第一个子节点
         SonNode next=parent.first;
         // 沿着孩子链不断搜索下一个孩子节点
         for(int i=0;next!=null;i++) {
             if(index==i) {
                 return nodes[next.pos];
             }
             next=next.next;
         }
         return null;
     }

     // 返回该树的深度
     public int deep() {
         // 获取该树的深度
         return deep(root());
     }

     // 这是一个递归方法:每棵子树的深度为其所有子树的最大深度 + 1
     public int deep(Node node) {
         if(node.first==null) {
             return 1;
         }else {
             // 记录其所有子树的最大深度
             int max=0;
             SonNode next=node.first;
             // 沿着孩子链不断搜索下一个孩子节点
             while(next!=null) {
                 // 获取以其子节点为根的子树的深度
                 int tmp=deep(nodes[next.pos]);
                 if(tmp>max) {
                     max=tmp;
                 }
                 next=next.next;
             }
             // 最后,返回其所有子树的最大深度 + 1
             return max + 1;
         }
     }

     // 返回包含指定值得节点
     public int pos(Node node) {
         for (int i = 0; i < treeSize; i++) {
             // 找到指定节点
             if (nodes[i] == node) {
                 return i;
             }
         }
         return -1;
     }

     //测试
     public static void main(String[] args) {

         TreeChild<String> tp = new TreeChild<String>("root");
         TreeChild.Node root = tp.root();
         System.out.println(root);
         tp.addNode("节点1", root);
         tp.addNode("节点2", root);
         tp.addNode("节点3", root);
         System.out.println("添加子节点后的根结点:" + root);
         System.out.println("此树的深度:" + tp.deep());
         // 获取根节点的所有子节点
         List<TreeChild.Node<String>> nodes = tp.children(root);
         System.out.println("根节点的第一个子节点:" + nodes.get(0));
         // 为根节点的第一个子节点新增一个子节点
         tp.addNode("节点4", nodes.get(0));
         System.out.println("此树第一个子节点:" + nodes.get(0));
         System.out.println("此树的深度:" + tp.deep());

     }

 }

程序运行结果:

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

文章永久链接:https://tech.souyunku.com/36298

未经允许不得转载:搜云库技术团队 » 算法——树

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们