【數據結構】二叉樹

1、順序存儲:採用數組來記錄二叉樹的全部節點。java

public class ArrayBinTree<T> {
    private final int DEFAULT_SIZE = 8;
    // 數組記錄該樹的全部節點
    private Object[] datas;
    // 保存該樹的深度
    private int deep;
    private int arraySize;

    // 以默認深度來建立二叉樹
    public ArrayBinTree() {
        this.deep = DEFAULT_SIZE;
        this.arraySize = (int)Math.pow(2, deep) - 1;
        this.datas = new Object[arraySize];
    }
    // 以指定深度來建立二叉樹
    public ArrayBinTree(int deep) {
        this.deep = deep;
        this.arraySize = (int)Math.pow(2, deep) - 1;
        this.datas = new Object[arraySize];
    }
    // 以指定深度、根節點建立二叉樹
    public ArrayBinTree(int deep, T data) {
        this.deep = deep;
        this.arraySize = (int)Math.pow(2, deep) - 1;
        this.datas = new Object[arraySize];
        datas[0] = data;
    }
    /**
     * 爲指定節點添加子節點
     * @param index 須要添加子節點的父節點索引
     * @param data 新子節點的數據
     * @param left 是否爲左節點
     */
    public void addNode(int index, T data, boolean left) {
        if (datas[index] == null) {
            throw new RuntimeException(index + "節點爲空,不能添加子節點");
        }
        if (2 * index + 1 >= arraySize) {
            throw new RuntimeException("樹底層的數組已滿,樹越界異常");
        }
        if (left) {
            datas[2 * index + 1] = data;
        } else {
            datas[2 * index + 2] = data;
        }
    }
    // 判斷二叉樹是否爲空
    public boolean empty() {
        // 根據根元素來判斷二叉樹是否爲空
        return datas[0] == null;
    }
    // 返回根節點
    public T root() {
        if (empty()) {
            throw new RuntimeException("樹爲空,沒法返回根節點");
        }
        return (T)datas[0];
    }
    // 返回指定節點(非根節點)的父節點
    public T parent(int index) {
        if (index == 0) {
            throw new RuntimeException("根節點沒有父節點");
        }
        return (T)datas[(index - 1) / 2];
    }
    // 返回指定節點(非葉子)的左子節點,當左子節點不存在時返回null
    public T left(int index) {
        if (2 * index + 1 >= arraySize) {
            throw new RuntimeException(index + "節點爲葉子節點,沒有左子節點");
        }
        return datas[index * 2 + 1] == null? null : (T)datas[index * 2 + 1];
    }
    // 返回該二叉樹的深度
    public int deep(int index) {
        return deep;
    }
    // 返回指定節點的位置
    public int pos(T data) {
        // 該循環實際上就是按廣度遍從來搜索每一個節點
        for (int i = 0; i < arraySize; i++) {
            if (datas[i] == data) {
                return i;
            }
        }
        return -1;
    }
    public String toString() {
        return java.util.Arrays.toString(datas);
    }
}

2、二叉鏈表存儲:每一個節點保留一個left、rigth域,分別指向其左、右子節點。node

public class TwoLinkBinTree<E> {

   public static class TreeNode {
      private Object data;
      private TreeNode left;
      private TreeNode right;
      public TreeNode() {
      }
      public TreeNode(Object data) {
         this.data = data;
      }
      public TreeNode(Object data, TreeNode left, TreeNode right) {
         this.data = data;
         this.left = left;
         this.right = right;
      }
   }
   private TreeNode root;
   // 以默認構造器來建立二叉樹
   public TwoLinkBinTree() {
      this.root = new TreeNode();
   }
   // 以指定根元素來建立二叉樹
   public TwoLinkBinTree(E data) {
      this.root = new TreeNode(data);
   }
    /**
     * 爲指定節點添加子節點
     * @param parent 須要添加子節點的父節點的索引
     * @param data 新子節點的數據
     * @param left 是否爲左節點
     * @return 新增的節點
     */
   public TreeNode addNode(TreeNode parent, E data, boolean left) {
      if (parent == null) {
         throw new RuntimeException(parent + "節點爲空,沒法添加子節點");
      }
      if (left && parent.left != null) {
         throw new RuntimeException(parent + "節點已有左節點,沒法添加左節點");
      }
      if (!left && parent.right != null) {
         throw new RuntimeException(parent + "節點已有右節點,沒法添加右節點");
      }
      TreeNode newNode = new TreeNode(data);
      if (left) {
         parent.left = newNode;
      } else {
         parent.right = newNode;
      }
      return newNode;
   }
   // 判斷二叉樹是否爲空
   public boolean empty() {
       // 根據根元素來判斷二叉樹是否爲空
      return root.data == null;
   }
   // 返回根節點
   public TreeNode root() {
      if (empty()) {
         throw new RuntimeException("樹爲空,沒法返回根節點");
      }
      return root;
   }
   // 返回指定節點(非根節點)的父節點
   public E parent(TreeNode node) {
       // 對於二叉鏈表存儲法,若是要訪問指定節點的父節點必須遍歷二叉樹
      return null;
   }
   // 返回指定節點(非葉子)的左子節點,當左子節點不存在時返回null
   public E leftChild(TreeNode parent) {
      if (parent == null) {
         throw new RuntimeException(parent + "節點爲空,無左子節點");
      }
      return parent.left == null ? null : (E)parent.left.data;
   }
   // 返回指定節點(非葉子)的右子節點。當右子節點不存在時返回null
   public E rightChild(TreeNode parent) {
      if (parent == null) {
         throw new RuntimeException(parent + "節點爲空,無右子節點");
      }
      return parent.right == null ? null : (E)parent.right.data;
   }
   // 二叉樹的深度
   public int deep() {
       // 獲取該樹的深度
      deep(root);
   }
   // 遞歸方法:每顆子樹的深度爲其全部子樹的最大深度 + 1
   private int deep(TreeNode node) {
        if (node == null) {
            return 0;
        }
        if (node.right == null && node.left == null) {
            return 1;
        } else {
            int leftDeep = deep(node.left);
            int rightDeep = deep(node.right);
            int max = leftDeep > rightDeep? leftDeep : rightDeep;
            return max + 1;
        }
   }
}

3、三叉鏈表存儲:每一個節點保留一個left、right、parent域,分別指向其左、右子節點和父節點。數組

public class ThreeLinkBinTree<E> {

    public static class TreeNode {
        private Object data;
        private TreeNode parent;
        private TreeNode left;
        private TreeNode right;
        public TreeNode() {

        }
        public TreeNode(Object data) {
            this.data = data;
        }
        public TreeNode(Object data, TreeNode parent, TreeNode left, TreeNode right) {
            this.data = data;
            this.parent = parent;
            this.left = left;
            this.right = right;
        }
    }
    private TreeNode root;
    // 以默認構造器來建立二叉樹
    public ThreeLinkBinTree() {
        root = new TreeNode();
    }
    // 以指定根元素來建立二叉樹
    public ThreeLinkBinTree(E data) {
        root = new TreeNode(data);
    }
    /**
     *  爲指定節點添加子節點
     * @param parent 須要添加子節點的父節點的索引
     * @param data 新子節點的數據
     * @param left 是否爲左節點
     * @return 新增的節點
     */
    public TreeNode addNode(TreeNode parent, E data, boolean left) {
        if (parent == null) {
            throw new RuntimeException(parent + "節點爲空,沒法添加子節點");
        }
        if (left && parent.left != null) {
            throw new RuntimeException(parent + "節點左節點不爲空,沒法添加左子節點");
        }
        if (!left && parent.right != null) {
            throw new RuntimeException(parent + "節點右節點不爲空,沒法添加右子節點");
        }
        TreeNode newNode = new TreeNode(data);
        if (left) {
            parent.left = newNode;
        } else {
            parent.right = newNode;
        }
        newNode.parent = parent;
        return newNode;
    }
    // 判斷二叉樹是否爲空
    public boolean empty() {
        // 根據根元素來判斷二叉樹是否爲空
        return root.data == null;
    }
    // 返回根節點
    public TreeNode root() {
        if (empty()) {
            throw new RuntimeException("根節點爲空");
        }
        return root;
    }
    // 返回指定節點(非根節點)的父節點
    public E parent(TreeNode node) {
        return (E)node.parent.data;
    }
    // 返回指定節點(非葉子)的左子節點。當左子節點不存在時返回null
    public E leftChild(TreeNode parent) {
        if (parent == null) {
            throw new RuntimeException(parent + "節點爲空,無左子節點");
        }
        return parent.left == null ? null:(E)parent.left.data;
    }
    // 返回指定節點(非葉子)的右子節點。當右子節點不存在時返回null
    public E rightChild(TreeNode parent) {
        if (parent == null) {
            throw new RuntimeException(parent + "節點爲空,無左子節點");
        }
        return parent.right == null ? null : (E)parent.right.data;
    }
    // 返回該二叉樹的深度
    public int deep() {
        // 獲取該樹的深度
        deep(root);
    }
    // 遞歸方法:每顆子樹的深度爲其全部子樹的最大深度 + 1
    private int deep(TreeNode node) {
        if (node == null) {
            return 0;
        }
        if (node.left == null && node.right == null) {
            return 1;
        } else {
            int leftDeep = deep(node.left);
            int rightDeep = deep(node.right);
            int max = leftDeep > rightDeep? leftDeep : rightDeep;
            return max + 1;
        }
    }
}
public class BinTreeTest {
    public static void main(String[] args) {
        ArrayBinTree<String> binTree = new ArrayBinTree<String>(4, "根");
        binTree.addNode(0, "第二層右子節點", false);
        binTree.addNode(2, "第三層右子節點", false);
        binTree.addNode(6, "第四層右子節點", false);
        System.out.println("【順序存儲】二叉樹:" + binTree.toString());
        TwoLinkBinTree<String> binTree2 = new TwoLinkBinTree<String>("根節點");
        TwoLinkBinTree.TreeNode tn1 = binTree2.addNode(binTree2.root(), "第二層左節點", true);
        TwoLinkBinTree.TreeNode tn2 = binTree2.addNode(binTree2.root(), "第二層右節點", false);
        TwoLinkBinTree.TreeNode tn3 = binTree2.addNode(tn2, "第三層左節點", true);
        TwoLinkBinTree.TreeNode tn4 = binTree2.addNode(tn2, "第三層右節點", false);
        TwoLinkBinTree.TreeNode tn5 = binTree2.addNode(tn3, "第四層左節點", true);
        System.out.println("tn2的左子節點:" + binTree2.leftChild(tn2));
        System.out.println("tn2的右子節點:" + binTree2.rightChild(tn2));
        System.out.println("【二叉鏈表存儲】樹深度:" + binTree2.deep());
        ThreeLinkBinTree<String> binTree3 = new ThreeLinkBinTree<String>("根節點");
        ThreeLinkBinTree.TreeNode ttn1 = binTree3.addNode(binTree3.root(), "第二層左節點", true);
        ThreeLinkBinTree.TreeNode ttn2 = binTree3.addNode(binTree3.root(), "第二層右節點", false);
        ThreeLinkBinTree.TreeNode ttn3 = binTree3.addNode(ttn2, "第三層左節點", true);
        ThreeLinkBinTree.TreeNode ttn4 = binTree3.addNode(ttn2, "第三層右節點", false);
        ThreeLinkBinTree.TreeNode ttn5 = binTree3.addNode(ttn3, "第四層左節點", true);
        System.out.println("tn2的左子節點:" + binTree3.leftChild(ttn2));
        System.out.println("tn2的右子節點:" + binTree3.rightChild(ttn2));
        System.out.println("tn2的父子節點:" + binTree3.parent(ttn2));
        System.out.println("【三叉鏈表存儲】樹深度:" + binTree3.deep());
    }
}
相關文章
相關標籤/搜索