數組存儲方式的分析node
鏈式存儲方式的分析數組
樹存儲方式的分析數據結構
public class BinaryTreeDemo { public static void main(String[] args) { BinaryTree binaryTree = new BinaryTree(); // 建立須要的節點 HeroHode root = new HeroHode(1, "宋江"); HeroHode hode1 = new HeroHode(2, "吳用"); HeroHode hode2 = new HeroHode(3, "林沖"); HeroHode hode3 = new HeroHode(4, "武松"); HeroHode hode4 = new HeroHode(5, "孫權"); HeroHode hode5 = new HeroHode(6, "曹操"); HeroHode hode6 = new HeroHode(7, "劉備"); // 說明,先手動建立該二叉樹,之後會使用遞歸的方式建立二叉樹 root.setLeft(hode1); root.setRight(hode2); hode1.setLeft(hode3); hode1.setRight(hode4); hode2.setLeft(hode5); hode2.setRight(hode6); binaryTree.setRoot(root); // System.out.println(binaryTree.preOrderSearch(5)); // System.out.println(binaryTree.infixOrderSearch(2)); // System.out.println(binaryTree.postOrderSearch(4)); // 1 2 3 5 4 System.out.println("前序遍歷"); binaryTree.preOrder(); // 2 1 5 3 4 System.out.println("中序遍歷"); binaryTree.infixOrder(); // 2 4 3 1 System.out.println("後序遍歷"); binaryTree.postOrder(); binaryTree.deleteNode(5); System.out.println("刪除後: "); binaryTree.preOrder(); } }
/** * 二叉樹 */ class BinaryTree { private HeroHode root; public void setRoot(HeroHode root) { this.root = root; } /** * 前序遍歷 */ public void preOrder() { if (this.root != null) { this.root.preOrder(); } else { System.out.println("二叉樹爲空,沒法遍歷"); } } /** * 中序遍歷 */ public void infixOrder() { if (this.root != null) { this.root.infixOrder(); } else { System.out.println("二叉樹爲空,沒法遍歷"); } } /** * 後序遍歷 */ public void postOrder() { if (this.root != null) { this.root.postOrder(); } else { System.out.println("二叉樹爲空,沒法遍歷"); } } public HeroHode preOrderSearch(int no) { if (root != null) { return root.preOrderSearch(no); } else { return null; } } public HeroHode infixOrderSearch(int no) { if (root != null) { return root.infixOrderSearch(no); } else { return null; } } public HeroHode postOrderSearch(int no) { if (root != null) { return root.postOrderSearch(no); } else { return null; } } public void deleteNode(int no) { if (root != null) { if (root.getNo() == no) { root = null; } else { root.deleteNode(no); } } else { System.out.println("空樹,不能刪除!!!"); } } }
/** * 節點 */ class HeroHode { private int no; private String name; private HeroHode left; private HeroHode right; public HeroHode(int no, String name) { this.no = no; this.name = name; } @Override public String toString() { return "HeroHode{" + "no=" + no + ", name='" + name + '\'' + '}'; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } public String getName() { return name; } public void setName(String name) { this.name = name; } public HeroHode getLeft() { return left; } public void setLeft(HeroHode left) { this.left = left; } public HeroHode getRight() { return right; } public void setRight(HeroHode right) { this.right = right; } /** * 前序遍歷 */ public void preOrder() { // 先輸出父節點 System.out.println(this); // 遞歸向左子樹前序遍歷 if (this.left != null) { this.left.preOrder(); } // 遞歸向右子樹前序遍歷 if (this.right != null) { this.right.preOrder(); } } /** * 中序遍歷 */ public void infixOrder() { // 遞歸向左子樹中序遍歷 if (this.left != null) { this.left.infixOrder(); } // 輸出父節點 System.out.println(this); // 遞歸向右子樹中序遍歷 if (this.right != null) { this.right.infixOrder(); } } /** * 後續遍歷 */ public void postOrder() { if (this.left != null) { this.left.postOrder(); } if (this.right != null) { this.right.postOrder(); } System.out.println(this); } /** * 根據no前序遍歷查找 * * @param no * @return */ public HeroHode preOrderSearch(int no) { if (this.no == no) { return this; } HeroHode resNode = null; if (this.left != null) { resNode = this.left.preOrderSearch(no); } if (resNode != null) { // 說明在左子樹上找到了 return resNode; } if (this.right != null) { resNode = this.right.preOrderSearch(no); } return resNode; } /** * 根據no中序遍歷查找 * * * @param no * @return */ public HeroHode infixOrderSearch(int no) { HeroHode resNode = null; if (this.left != null) { resNode = this.left.infixOrderSearch(no); } if (resNode != null) { return resNode; } if (this.no == no) { return this; } if (this.right != null) { resNode = this.right.infixOrderSearch(no); } return resNode; } /** * 根據no後序遍歷查找 * * @param no * @return */ public HeroHode postOrderSearch(int no) { HeroHode resNode = null; if (this.left != null) { resNode = this.left.postOrderSearch(no); } if (resNode != null) { return resNode; } if (this.right != null) { resNode = this.right.postOrderSearch(no); } if (resNode != null) { return resNode; } if (this.no == no) { return this; } return resNode; } /** * 遞歸刪除節點 * * @param no */ public void deleteNode(int no) { if (this.left != null && this.left.no == no) { this.left = null; return; } if (this.right != null && this.right.no == no) { this.right = null; return; } if (this.left != null) { this.left.deleteNode(no); } if (this.right != null) { this.right.deleteNode(no); } } }
從數據存儲來看,數組存儲方式和樹的存儲方式能夠相互轉換,即數組能夠轉換成樹,樹也能夠轉換成數組。
ide
順序存儲二叉樹的特色:post
public class ArrBinaryTreeDemo { public static void main(String[] args) { int[] arr = {1, 2, 3, 4, 5, 6, 7}; ArrBinaryTree arrBinaryTree = new ArrBinaryTree(arr); // arrBinaryTree.preOrder(); // arrBinaryTree.infixOrder(); arrBinaryTree.postOrder(); } } class ArrBinaryTree { // 存儲數據節點的數組 private int[] arr; public ArrBinaryTree(int[] arr) { this.arr = arr; } public void preOrder() { preOrder(0); } /** * 順序存儲二叉樹的前序遍歷 * * @param index 數組的下標 */ public void preOrder(int index) { if (arr == null || arr.length == 0) { System.out.println("數組爲空,不能按照二叉樹的前序遍歷"); } // 輸出當前元素 System.out.println(arr[index]); // 向左遞歸遍歷 if ((index * 2 + 1) < arr.length) { preOrder(2 * index + 1); } // 向右遞歸遍歷 if ((index * 2 + 2) < arr.length) { preOrder(2 * index + 2); } } public void infixOrder() { infixOrder(0); } /** * 順序存儲二叉樹的前序遍歷 * * @param index 數組的下標 */ public void infixOrder(int index) { if (arr == null || arr.length == 0) { System.out.println("數組爲空,不能按照二叉樹的前序遍歷"); } // 向左遞歸遍歷 if ((index * 2 + 1) < arr.length) { infixOrder(2 * index + 1); } // 輸出當前元素 System.out.println(arr[index]); // 向右遞歸遍歷 if ((index * 2 + 2) < arr.length) { infixOrder(2 * index + 2); } } public void postOrder() { postOrder(0); } /** * 順序存儲二叉樹的前序遍歷 * * @param index 數組的下標 */ public void postOrder(int index) { if (arr == null || arr.length == 0) { System.out.println("數組爲空,不能按照二叉樹的前序遍歷"); } // 向左遞歸遍歷 if ((index * 2 + 1) < arr.length) { postOrder(2 * index + 1); } // 向右遞歸遍歷 if ((index * 2 + 2) < arr.length) { postOrder(2 * index + 2); } // 輸出當前元素 System.out.println(arr[index]); } }
基本介紹測試
赫夫曼樹幾個重要概念和舉例說明優化
構成赫夫曼樹的步驟:this
/** * 赫夫曼樹 * * @author jianjieming * @date 2019/11/20 14:09 */ public class HuffmanTree { public static void main(String[] args) { int[] arr = {13, 7, 8, 3, 29, 6, 1}; Node root = createHuffmanTree(arr); perOrder(root); } /** * 建立赫夫曼樹 * * @param arr 須要建立成赫夫曼樹的數組 * @return 返回建立好的赫夫曼樹的root節點 */ public static Node createHuffmanTree(int[] arr) { ArrayList<Node> nodes = new ArrayList<>(); for (int value : arr) { nodes.add(new Node(value)); } while (nodes.size() > 1) { nodes.sort(Comparator.comparing(Node::getValue)); System.out.println(nodes); // 1.取出權值最小的兩個二叉樹 Node leftNode = nodes.get(0); Node rightNode = nodes.get(1); // 2.構建一個新的二叉樹 Node parent = new Node(leftNode.value + rightNode.value); parent.left = leftNode; parent.right = rightNode; // 3.從ArrayList中刪除處理過的二叉樹 nodes.remove(leftNode); nodes.remove(rightNode); // 4.將parent加入到nodes nodes.add(parent); } // 返回赫夫曼樹的root節點 return nodes.get(0); } public static void perOrder(Node root) { if (root != null) { root.perOrder(); } else { System.out.println("樹是空的,沒法遍歷!!!"); } } } /** * 節點類 */ class Node { int value; Node left; Node right; public Node(int value) { this.value = value; } @Override public String toString() { return "Node{" + "value=" + value + '}'; } public int getValue() { return value; } /** * 前序遍歷 */ public void perOrder() { System.out.println(this.value); if (this.left != null) { this.left.perOrder(); } if (this.right != null) { this.right.perOrder(); } } }
二叉排序樹:BST: (Binary Sort(Search) Tree), 對於二叉排序樹的任何一個非葉子節點,要求左子節點的值比當前節點的值小,右子節點的值比當前節點的值大。
特別說明:若是有相同的值,能夠將該節點放在左子節點或右子節點。
好比(7, 3, 10, 12, 5, 1, 9),對應的二叉排序樹爲:
code
二叉排序樹的刪除狀況比較複雜,有下面三種狀況須要考慮:blog
/** * 二叉排序樹測試 * * @author jianjieming * @date 2019/11/21 9:48 */ public class BinarySortTreeDemo { public static void main(String[] args) { int[] arr = {7, 3, 10, 12, 5, 1, 9, 2}; BinarySortTree binarySortTree = new BinarySortTree(); for (int i = 0; i < arr.length; i++) { binarySortTree.add(new NodeDemo(arr[i])); } System.out.println("中序遍歷二叉排序樹: "); binarySortTree.infixOrder(); // 測試刪除葉子節點(2, 5, 9, 12) binarySortTree.delNode(2); binarySortTree.delNode(5); binarySortTree.delNode(9); binarySortTree.delNode(12); binarySortTree.delNode(7); binarySortTree.delNode(3); binarySortTree.delNode(10); binarySortTree.delNode(1); System.out.println("刪除節點後: "); binarySortTree.infixOrder(); } }
/** * 建立二叉排序樹 */ class BinarySortTree { private NodeDemo root; /** * 添加節點的方法 */ public void add(NodeDemo node) { if (root == null) { root = node; } else { root.add(node); } } public void infixOrder() { if (root != null) { root.infixOrder(); } else { System.out.println("二叉排序樹爲空,沒法遍歷!!!"); } } /** * 刪除節點 */ public void delNode(int value) { if (root == null) { return; } else { // 1. 先找到要刪除的節點 targetNode NodeDemo targetNode = search(value); // 若是沒有找到要刪除的節點 if (targetNode == null) { return; } // 若是當前這顆二叉排序樹只有一個節點 if (root.left == null && root.right == null) { root = null; return; } // 查找targetNode的父節點 NodeDemo parent = searchParent(value); // 若是要刪除的節點是葉子節點 if (targetNode.left == null && targetNode.right == null) { // 判斷targetNode是父節點的左子節點仍是右子節點 if (parent.left != null && parent.left.value == value) { // 是左子節點 parent.left = null; } else if (parent.right != null && parent.right.value == value) { // 是右子節點 parent.right = null; } } else if (targetNode.left != null && targetNode.right != null) { // 刪除有兩顆子樹的節點 int minVal = delRightTreeMin(targetNode.right); // int maxVal = delLeftTreeMax(targetNode.right); targetNode.value = minVal; } else { // 刪除只有一顆子樹的節點 // 若是要刪除的節點有左子節點 if (targetNode.left != null) { if (parent != null) { // 若是targetNode是parent的左子節點 if (parent.left.value == value) { parent.left = targetNode.left; } else { // targetNode是parent的右子節點 parent.right = targetNode.left; } } else { root = targetNode.left; } } else { if (parent != null) { // 要刪除的節點有右子節點 // 若是targetNode是parent的左子節點 if (parent.left.value == value) { parent.left = targetNode.right; } else { // targetNode是parent的右子節點 parent.right = targetNode.right; } } else { root = targetNode.right; } } } } } /** * 查找要刪除的節點 */ public NodeDemo search(int value) { if (root == null) { return null; } else { return root.search(value); } } /** * 查找父節點 */ public NodeDemo searchParent(int value) { if (root == null) { return null; } else { return root.searchParent(value); } } /** * 刪除以node 爲根節點的二叉排序樹最小節點 * * @param node 傳入的節點(當作二叉排序樹的根節點) * @return 返回的 以node 爲根節點的二叉排序樹最小節點的值 */ public int delRightTreeMin(NodeDemo node) { NodeDemo target = node; // 循環查找左節點,就會找到最小值 while (target.left != null) { target = target.left; } // 這時target就指向了最小節點, 刪除最小節點 delNode(target.value); return target.value; } public int delLeftTreeMax(NodeDemo node) { NodeDemo target = node; // 循環查找左節點,就會找到最小值 while (target.right != null) { target = target.right; } // 這時target就指向了最小節點, 刪除最小節點 delNode(target.value); return target.value; } }
/** * 節點 */ class NodeDemo { int value; NodeDemo left; NodeDemo right; public NodeDemo(int value) { this.value = value; } @Override public String toString() { return "NodeDemo{" + "value=" + value + '}'; } /** * 添加節點的方法 */ public void add(NodeDemo node) { if (node == null) { return; } // 判斷傳入節點的值,和當前子樹的根節點的值關係 if (node.value < this.value) { // 若是當前節點左子節點是否爲null if (this.left == null) { this.left = node; } else { // 遞歸向左子樹添加 this.left.add(node); } } else { // 添加的節點的值大於當前節點的值 if (this.right == null) { this.right = node; } else { // 遞歸向左子樹添加 this.right.add(node); } } } /** * 中序遍歷 */ public void infixOrder() { if (this.left != null) { this.left.infixOrder(); } System.out.println(this); if (this.right != null) { this.right.infixOrder(); } } /** * 查找要刪除的節點 * * @param value 但願刪除節點的值 */ public NodeDemo search(int value) { if (value == this.value) { return this; } else if (value < this.value) { // 若是查找的值,小於當前節點,則向左子樹遞歸查找 if (this.left == null) { // 若是左子節點爲空 return null; } return this.left.search(value); } else { // 若是查找的值,不小於當前節點,則向右子樹遞歸查找 if (this.right == null) { // 若是左子節點爲空 return null; } return this.right.search(value); } } /** * 查找要刪除節點的父節點 * * @param value 要找到的節點的值 * @return 返回的是要刪除節點的父節點, 沒有返回null */ public NodeDemo searchParent(int value) { // 若是當前節點就是要刪除的節點的父節點,就返回 if ((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)) { return this; } else { // 若是要查找的值小於當前節點的值,而且當前節點的左子節點不爲空 if (value < this.value && this.left != null) { // 向左子樹遞歸查找 return this.left.searchParent(value); } else if (value >= this.value && this.right != null) { // 向右子樹遞歸查找 return this.right.searchParent(value); } else { // 沒有找到父節點 return null; } } } }
若是以爲對你有幫助,歡迎來訪個人博客:http://jianjieming.com