二叉树,二叉树遍历,二叉树搜索

向右看齐 2023-07-07 12:30 119阅读 0赞

树形结构

树形结构应该就比较容易理解了,树是二维数据结构中的一种,至于说二叉树又是树的一种了。

树和图的区别在这里说明一下,重点:
树形结构为二维数据结构中的一种特殊结构

  1. 1.树形结构有一个根节点
  2. 2.树形结构没有回路(就是只能一直往下,有回路的称为图,树是图的一种)
  3. 3.树形结构我们称为 有向循环图
  4. 几个关键字,拓补结构,树,图,有向循环图

二叉树

  1. 就三种,一种根节点,一种节点,一种叶子节点
  2. 二叉树,就是只有两个枝的结构

二叉树代码实现:

  1. //二叉树结构
  2. function Rout(value) {
  3. this.value = value;
  4. this.left = null;
  5. this.right = null;
  6. }
  7. // 赋值
  8. var a = new Rout("a");
  9. var b = new Rout("b");
  10. var c = new Rout("c");
  11. var d = new Rout("d");
  12. var e = new Rout("e");
  13. var f = new Rout("f");
  14. var g = new Rout("g");
  15. // 结构图
  16. a.left = b;
  17. a.right = c;
  18. b.left = d;
  19. b.right = e;
  20. c.left = f;
  21. c.right = g;

跟节点应该好理解

  1. 叶子节点:下边没有其他节点
  2. 节点:既不是根节点,也不是叶子节点的普通节点

满二叉树:
1.所有的叶子节点都在最底层
2.每个非叶子节点都有两个子节点

在这里插入图片描述

完全二叉树:
若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

国内定义

  1. 1.叶子节点都在最后一层或者倒数第二层
  2. 2.叶子节点都向左聚拢

国际定义

  1. 1.叶子节点都在最后一层或者倒数第二层
  2. 2.如果有叶子节点,就必然有两个叶子节点

画了一个二叉树,这是一个满的二叉树,接下来我们说遍历,遍历分为三种:

1.前序遍历
2.中序遍历
3.后序遍历

前序遍历:深度优先原则
先打印当前的,再打印左边的,再打印右边的
中序:先打印左边的,再打印当前的,再打印右边的
后序遍历:先打印左边的,再打印右边的,再打印当前的

总的来说:
专业的名词了解下:

前序遍历:先根次序遍历
中序遍历:中根次序遍历
后序遍历:后根次序遍历

前序遍历代码实现:

  1. //输出 前序遍历
  2. function f1(root){
  3. //判断
  4. if(root == null) return;
  5. console.log(root.value);
  6. f1(root.left);
  7. f1(root.right);
  8. }
  9. //调用
  10. f1(a);

中序遍历代码实现:

  1. //输出 中序遍历
  2. function f1(root) {
  3. //判断
  4. if (root == null) return;
  5. f1(root.left);
  6. console.log(root.value);
  7. f1(root.right);
  8. }
  9. //调用
  10. f1(a);

后序遍历代码实现:

  1. //输出 后序遍历
  2. function f1(root) {
  3. //判断
  4. if (root == null) return;
  5. f1(root.left);
  6. f1(root.right);
  7. console.log(root.value);
  8. }
  9. //调用
  10. f1(a);

二叉树的搜索,搜索肯定就分为两种搜了,应该很容易理解
深度优先
广度优先

深度搜索代码示例:

  1. // 深度搜索代码
  2. function dfsSearch(root,target){
  3. //判断 代码的严谨性 返回 true 或者 false
  4. if(root == null) return false;
  5. if(root.value == target) return true;
  6. //赋值
  7. var left = deepSearch(root.left,target);
  8. var right = deepSearch(root.right,target);
  9. //返回
  10. return left || right;
  11. }
  12. //调用 打印输出 搜索h节点是否存在
  13. console.log(dfsSearch(a,"h"));

广度搜索代码:

  1. // 广度搜索代码
  2. function bfsSearch(rootlist,target){
  3. //判断 代码的严谨性
  4. if(rootlist == null || rootlist.length == 0) return false;
  5. //创建存储空间
  6. var childlist = [];
  7. //循环存储信息
  8. for(var i = 0;i < rootlist.length;i++){
  9. //判断为false时是否继续
  10. if(!rootlist[i]) continue;
  11. //判断
  12. if(rootlist[i] != null && rootlist[i].value == target){
  13. return true;
  14. }else{
  15. //添加左子树
  16. childlist.push(rootlist[i].left);
  17. //添加右子树
  18. childlist.push(rootlist[i].right);
  19. }
  20. }
  21. //返回
  22. return bfsSearch(childlist,target);
  23. }
  24. //调用 打印输出 搜索h节点是否存在
  25. console.log(bfsSearch([a],"h"));

深搜代码,查找h是否存在,返回true或者false
代码里面都是用到了大量的递归,都是跟链表的逆置是一个思想的

小拓展:
二叉树的比较:判断两个二叉树是否相等

(1)首先,创建两个二叉树

  1. //二叉树结构
  2. function Rout(value) {
  3. this.value = value;
  4. this.left = null;
  5. this.right = null;
  6. }
  7. //第一个二叉树
  8. // 赋值
  9. var a = new Rout("a");
  10. var b = new Rout("b");
  11. var c = new Rout("c");
  12. var d = new Rout("d");
  13. var e = new Rout("e");
  14. var f = new Rout("f");
  15. var g = new Rout("g");
  16. // 结构图
  17. a.left = b;
  18. a.right = c;
  19. b.left = d;
  20. b.right = e;
  21. c.left = f;
  22. c.right = g;
  23. //第二个二叉树
  24. // 赋值
  25. var a1 = new Rout("a");
  26. var b1 = new Rout("b");
  27. var c1 = new Rout("c");
  28. var d1 = new Rout("d");
  29. var e1 = new Rout("e");
  30. var f1 = new Rout("f");
  31. var g1 = new Rout("g");
  32. // 结构图
  33. a1.left = b1;
  34. a1.right = c1;
  35. b1.left = d1;
  36. b1.right = e1;
  37. c1.left = g1;
  38. c1.right = f1;

(2)比较两个二叉树是否相等

  1. //比较是否相等
  2. function twiceOver(rootlist1, rootlist2) {
  3. //判断 代码的严谨性
  4. if (rootlist1 == rootlist2) return true; //为同一颗树
  5. if (rootlist1 == null && rootlist2 != null || rootlist1 != null && rootlist2 == null) return false; //其中一个二叉树结构不同时
  6. if (rootlist1.value != rootlist2.value) return false; //相同位置的值不相等时
  7. //赋值判断
  8. var twiceleft = twiceOver(rootlist1.left, rootlist2.left); //判断左子树是否相等
  9. var twiceright = twiceOver(rootlist1.right, rootlist2.right); //判断右子树是否相等
  10. //返回
  11. return twiceleft && twiceright; //只要左右子树都相等二叉树才相等
  12. }
  13. //调用
  14. console.log(twiceOver(a, a1));

面试中注意事项:
填空题和笔试题都有可能出现的
1.给出前序中序还原二叉树,要求写出后序遍历
2.给出后序中序还原二叉树,要求写出前序遍历
注意:必须要有中序遍历,没有中序遍历,不能实现还原二叉树

还原二叉树代码示例:

1.根据前序、中序遍历,还原二叉树,进行后序遍历

  1. //根据前序、中序遍历,还原二叉树,进行后序遍历
  2. var qian = ["a","b","d","e","c","f","g"];
  3. var zhong = ["d","b","e","a","f","c","g"];
  4. //构造函数
  5. function f2(qian,zhong){
  6. //判断 代码的严谨性
  7. if(qian == null || zhong == null || qian.length == 0 || zhong.length == 0 || qian.length != zhong.length) return null;
  8. //获取根节点
  9. var root = new Rout(qian[0]);
  10. //找到根节点中序遍历 中 的位置
  11. var index = zhong.indexOf(root.value);
  12. //分离前序遍历
  13. //前序遍历的左子树
  14. var qianleft = qian.slice(1,index + 1);
  15. //前序遍历的右子树
  16. var qianright = qian.slice(1 + index,qian.length);
  17. //分离中序遍历
  18. //中序遍历的左子树
  19. var zhongleft = zhong.slice(0,index);
  20. //中序遍历的右子树
  21. var zhongright = zhong.slice(1 + index,zhong.length);
  22. // 还原二叉树
  23. // 根据左子树还原二叉树的左子树
  24. root.left = f2(qianleft,zhongleft);
  25. // 根据右子树还原二叉树的右子树
  26. root.right = f2(qianright,zhongright);
  27. //返回
  28. return root;
  29. }
  30. // 输出 后序遍历
  31. var root = f2(qian,zhong);
  32. console.log(root.left);
  33. console.log(root.right);
  34. 后序遍历
  35. console.log(root.left.left.value);
  36. console.log(root.left.right.value);
  37. console.log(root.left.value);
  38. console.log(root.right.left.value);
  39. console.log(root.right.right.value);
  40. console.log(root.right.value);
  41. console.log(root.value);

2.根据后序、中序遍历,还原二叉树,进行前序遍历

  1. //根据后序、中序遍历,还原二叉树,进行前序遍历
  2. var hou = ["d", "e", "b", "f", "g", "c", "a"];
  3. var zhong = ["d", "b", "e", "a", "f", "c", "g"];
  4. //构造函数
  5. function f2(hou, zhong) {
  6. //判断 代码的严谨性
  7. if (hou == null || zhong == null || hou.length == 0 || zhong.length == 0 || hou.length != zhong.length) return null;
  8. //获取根节点
  9. var root = new Rout(hou[hou.length - 1]);
  10. //根据根节点获取中序遍历 中 的位置
  11. var index = zhong.indexOf(root.value);
  12. //分离后序遍历
  13. //后序遍历的左子树
  14. var houleft = hou.slice(0, index);
  15. //后序遍历的右子树
  16. var houright = hou.slice(index, hou.length - 1);
  17. //分离中序遍历
  18. //中序遍历的左子树
  19. var zhongleft = zhong.slice(0, index);
  20. //中序遍历的右子树
  21. var zhongright = zhong.slice(index + 1, zhong.length);
  22. //还原二叉树
  23. //根据左子树还原二叉树的左子树
  24. root.left = f2(houleft, zhongleft);
  25. // 根据右子树还原二叉树的右子树
  26. root.right = f2(houright, zhongright);
  27. //返回
  28. return root;
  29. }
  30. // 输出
  31. var root = f2(hou, zhong);
  32. console.log(root.left);
  33. console.log(root.right);
  34. // 前序遍历
  35. console.log(root.value);
  36. console.log(root.left.value);
  37. console.log(root.left.left.value);
  38. console.log(root.left.right.value);
  39. console.log(root.right.value);
  40. console.log(root.right.left.value);
  41. console.log(root.right.right.value);

发表评论

表情:
评论列表 (有 0 条评论,119人围观)

还没有评论,来说两句吧...

相关阅读