数组存储方式的分析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