当前位置:   article > 正文

数据结构--树

数据结构--树

一、树的基本术语

结点:树中的一个独立单元

结点的度:结点下分支的个数

树的度:树中所有结点中度的最大值

非终端结点:度不为0的结点

双亲和孩子:结点下的子树称为该结点的孩子.相应地,该结点称为孩子的双亲

兄弟:同一个双亲的孩子之间

祖先:从根到该结点所经分支上的所有结点

子孙:从某结点为根,其下直接或间接的结点

层次:从根开始,根的孩子为第二层,依次类推

堂兄弟:双亲在同一层的结点

树的深度:树中结点的最大层次称为树的深度或高度

有序树和无序树:如果将树中所有结点的各子树看成从左至右是有次序的,反之无序的为无序树(在有序树中最左边的子树的根称为第一个孩子最右边称为最后一个孩子)

森林m(m>=0)棵互不相交的树的集合

二、二叉树(Binary Tree)

1>有且仅有一个称为根的结点

2>除叶子结点,剩余每个结点可能有左孩子或右孩子(最多有两个)

二叉树具有天然递归结构

每个结点的左子树也是二叉树

每个结点的右子树也是二叉树

性质1:在二叉树的第i层上至多有2^(i-1)个结点(i>=1)

性质2:深度为k的二叉树至多有2^k-1个结点(k>=1)

性质3:对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0= n2+1(度为0的结点数比度为2的结点数多1)

三、二分搜索树

二分搜索树是二叉树

二分搜索树的每个结点的值(大于其左子树的所有结点的值|小于其右子树的所有结点的值)

每一棵子树也是二分搜索树

二分搜索树的相关操作

创建二分搜索树的类

  1. // 保存在树中的结点必须具有可比性
  2. public class BinearySearchTree<T extends Comparable<T>> {}

 创建树的结点

  1. private class Node<T> {
  2. private T ele;// 结点的值
  3. private int frequence;// 频率
  4. private Node<T> left, right;// 分别指向左右孩子的索引
  5. public Node(T ele) {
  6. this.ele = ele;
  7. this.frequence = 1;
  8. this.right = this.left = null;
  9. }
  10. }

 树对应的属性

  1. private Node<T> root;// 树的根节点
  2. private int size;// 书中结点的个数

构建树 

  1. public BinearySearchTree() {
  2. this.root = null;
  3. this.size = 0;
  4. }

 获取树中结点数

  1. public int getSize() {
  2. return this.size;
  3. }

 向树中添加结点

  1. public void add(T ele) {
  2. // 更新根节点
  3. this.root = addDG(this.root, ele);
  4. }
  5. // 语义:向以root为根的二分搜索树中添加元素ele
  6. private Node addDG(Node<T> root, T ele) {
  7. // 递归终止条件
  8. if (root == null) {
  9. this.size++;
  10. return new Node<T>(ele);
  11. }
  12. // 递归操作
  13. if (root.ele.compareTo(ele) > 0) {
  14. root.left = addDG(root.left, ele);
  15. } else if (root.ele.compareTo(ele) < 0) {
  16. root.right = addDG(root.right, ele);
  17. } else {
  18. // 更新频率
  19. root.frequence++;
  20. }
  21. return root;
  22. }

查询某个值在树中是否存在

  1. public boolean search(T ele) {
  2. return searchDG(this.root, ele);
  3. }
  4. // 语义:从以root为根的二分搜索树中查找元素ele
  5. private boolean searchDG(Node<T> root, T ele) {
  6. // 递归终止条件
  7. if (root == null) {
  8. return false;
  9. }
  10. // 递归操作
  11. if (root.ele.compareTo(ele) == 0) {
  12. return true;
  13. } else if (root.ele.compareTo(ele) > 0) {
  14. return searchDG(root.left, ele);
  15. } else {
  16. return searchDG(root.right, ele);
  17. }
  18. }

二分搜索树的先序遍历

  1. public void preTravel() {
  2. List<AbstractMap.SimpleEntry<T, Integer>> list = new ArrayList<>();
  3. preTravelDG(this.root, list);
  4. String resStr = list.stream().map(item -> "[" + item.getKey() + ":" + item.getValue() + "]").collect(Collectors.joining("-"));
  5. System.out.println(resStr);
  6. }
  7. // 先序遍历以root为根的树,将结果保存在list中
  8. private void preTravelDG(Node<T> root, List<AbstractMap.SimpleEntry<T, Integer>> list) {
  9. // 递归终止条件
  10. if (root == null) {
  11. return;
  12. }
  13. // 递归操作
  14. list.add(new AbstractMap.SimpleEntry<>(root.ele, root.frequence));
  15. // 遍历左子树
  16. preTravelDG(root.left, list);
  17. // 遍历右子树
  18. preTravelDG(root.right, list);
  19. }

二分搜索树的中序遍历

  1. public void midTravel() {
  2. List<AbstractMap.SimpleEntry<T, Integer>> list = new ArrayList<>();
  3. midTravelDG(this.root, list);
  4. String resStr = list.stream().map(item -> "[" + item.getKey() + ":" + item.getValue() + "]").collect(Collectors.joining("-"));
  5. System.out.println(resStr);
  6. }
  7. // 中序遍历以root为根的树,将结果保存在list中
  8. private void midTravelDG(Node<T> root, List<AbstractMap.SimpleEntry<T, Integer>> list) {
  9. // 递归终止条件
  10. if (root == null) {
  11. return;
  12. }
  13. // 递归操作
  14. // 遍历左子树
  15. midTravelDG(root.left, list);
  16. list.add(new AbstractMap.SimpleEntry<>(root.ele, root.frequence));
  17. // 遍历右子树
  18. midTravelDG(root.right, list);
  19. }

二分搜索树的后序遍历

  1. public void sufTravel() {
  2. List<AbstractMap.SimpleEntry<T, Integer>> list = new ArrayList<>();
  3. sufTravelDG(this.root, list);
  4. String resStr = list.stream().map(item -> "[" + item.getKey() + ":" + item.getValue() + "]").collect(Collectors.joining("-"));
  5. System.out.println(resStr);
  6. }
  7. // 后序遍历以root为根的树,将结果保存在list中
  8. private void sufTravelDG(Node<T> root, List<AbstractMap.SimpleEntry<T, Integer>> list) {
  9. // 递归终止条件
  10. if (root == null) {
  11. return;
  12. }
  13. // 递归操作
  14. // 遍历左子树
  15. sufTravelDG(root.left, list);
  16. // 遍历右子树
  17. sufTravelDG(root.right, list);
  18. list.add(new AbstractMap.SimpleEntry<>(root.ele, root.frequence));
  19. }

层序遍历(依赖队列)

  1. public void levelTravel() {
  2. // 判断树是否为空
  3. if (this.isEmpty()) {
  4. return;
  5. }
  6. Queue<AbstractMap.SimpleEntry<Node<T>, Integer>> queue = new LinkedList<>();
  7. // 1.现将根节点入队
  8. queue.add(new AbstractMap.SimpleEntry<>(this.root, 1));
  9. // 2.遍历队列
  10. while (!queue.isEmpty()) {
  11. // 2-1 出队
  12. AbstractMap.SimpleEntry<Node<T>, Integer> pair = queue.poll();
  13. // 结点
  14. Node<T> node = pair.getKey();
  15. // 层
  16. int level = pair.getValue();
  17. System.out.println("[val:" + node.ele + ",level:" + level + "]");
  18. // 2-2 判断左右子树是否为空
  19. if (node.left != null) {
  20. queue.add(new AbstractMap.SimpleEntry<>(node.left, level + 1));
  21. }
  22. if (node.right != null) {
  23. queue.add(new AbstractMap.SimpleEntry<>(node.right, level + 1));
  24. }
  25. }
  26. }

判断是否为空

  1. public boolean isEmpty() {
  2. return this.size == 0;
  3. }

寻找树中最小元素

  1. public T getMinValue() {
  2. if (this.isEmpty()) {
  3. return null;
  4. }
  5. Optional<Node<T>> optional = getMinNode(this.root);
  6. return optional.get().ele;
  7. }
  8. // 语义:在以Node为根结点的树中查找最小结点
  9. private Optional<Node<T>> getMinNode(Node<T> node) {
  10. // 递归终止的条件
  11. if (node.left == null) {
  12. return Optional.of(node);
  13. }
  14. // 递归操作
  15. return getMinNode(node.left);
  16. }

寻找树中最大元素

  1. public T getMaxValue() {
  2. if (this.isEmpty()) {
  3. return null;
  4. }
  5. Optional<Node<T>> optional = getMaxNode(this.root);
  6. return optional.get().ele;
  7. }
  8. // 语义:在以Node为根结点的树中查找最大结点
  9. private Optional<Node<T>> getMaxNode(Node<T> node) {
  10. // 递归终止的条件
  11. if (node.right == null) {
  12. return Optional.of(node);
  13. }
  14. // 递归操作
  15. return getMaxNode(node.right);
  16. }

删除最小结点

  1. public T removeMinNode() {
  2. T result = getMinValue();
  3. if (result == null) {
  4. return null;
  5. }
  6. // 更新根节点
  7. this.root = removeMinNode(this.root);
  8. return result;
  9. }
  10. /**
  11. * 语义:从以node为根的二分搜索树中删除元素最小的结点
  12. *
  13. * @param node 树的根结点
  14. * return 删除最小结点之后的树的根结点
  15. */
  16. private Node<T> removeMinNode(Node<T> node) {
  17. // 递归终止条件
  18. if (node.left == null) {
  19. // 删除操作
  20. // 1.记录右子树
  21. Node<T> rightTree = node.right;
  22. // 2.失去关联关系
  23. node.right = null;
  24. // 3.更新size
  25. this.size--;
  26. return rightTree;
  27. }
  28. // 递归操作
  29. node.left = removeMinNode(node.left);
  30. return node;
  31. }

删除最大结点 

  1. public T removeMaxNode() {
  2. T result = getMaxValue();
  3. if (result == null) {
  4. return null;
  5. }
  6. // 更新根节点
  7. this.root = removeMaxNode(this.root);
  8. return result;
  9. }
  10. /**
  11. * 语义:从以node为根的二分搜索树中删除元素最大的结点
  12. *
  13. * @param node 树的根结点
  14. * return 删除最大结点之后的树的根结点
  15. */
  16. private Node<T> removeMaxNode(Node<T> node) {
  17. // 递归终止条件
  18. if (node.right == null) {
  19. // 删除操作
  20. // 1.记录左子树
  21. Node<T> leftTree = node.left;
  22. // 2.失去关联关系
  23. node.left = null;
  24. // 3.更新size
  25. this.size--;
  26. return leftTree;
  27. }
  28. // 递归操作
  29. node.right = removeMaxNode(node.right);
  30. return node;
  31. }

 删除任意结点

  1. public void remove(T ele) {
  2. // 根据值查找结点
  3. this.root = remove(this.root, ele);
  4. }
  5. private Node<T> remove(Node<T> node, T ele) {
  6. // 递归终止条件
  7. // 没有找到的情况
  8. if (node == null) {
  9. return null;
  10. }
  11. // 找到了删除的结点
  12. if (node.ele.compareTo(ele) == 0) {
  13. this.size--;
  14. // node就是要删除的结点
  15. // 1.左子树空,右子树不为空
  16. if (node.left == null) {
  17. Node<T> rightNode = node.right;
  18. node.right = null;
  19. return rightNode;
  20. } else if (node.right == null) {
  21. // 2.右子树空,左子树不为空
  22. Node<T> leftNode = node.left;
  23. node.left = null;
  24. return leftNode;
  25. } else {
  26. // 3.左右子树都不为空
  27. // 3-1从右子树中找最小结点
  28. Node<T> suffixNode = getMinNode(node.right).get();
  29. // 从右子树中删除最小结点
  30. suffixNode.right = removeMinNode(node.right);
  31. suffixNode.left = node.left;
  32. // 将node结点的左右子树失去关联关系
  33. node.left = node.right = null;
  34. this.size++;
  35. return suffixNode;
  36. }
  37. }
  38. // 递归操作
  39. if (node.ele.compareTo(ele) > 0) {
  40. node.left = remove(node.left, ele);
  41. } else {
  42. node.right = remove(node.right, ele);
  43. }
  44. return node;
  45. }

 删除根结点

  1. public void removeRoot() {
  2. if (this.root == null) {
  3. return;
  4. }
  5. remove(this.root.ele);
  6. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/46748?site
推荐阅读
相关标签
  

闽ICP备14008679号