zoukankan      html  css  js  c++  java
  • python、java实现二叉树,细说二叉树添加节点、深度优先(先序、中序、后续)遍历 、广度优先 遍历算法

    数据结构可以说是编程的内功心法,掌握好数据结构真的非常重要。
    目前基本上流行的数据结构都是c和c++版本的,
    我最近在学习python,尝试着用python实现了二叉树的基本操作。
    写下一篇博文,总结一下,希望能够对其他好伙伴带来一点借鉴价值~~

    温馨提示:学习算法要先懂思想,后学代码。思想学会才是自己的。背下来代码,容易忘。

    代码捉襟见肘,欢迎批评指正 ^.^


    先谈一下二叉树:

    二叉树是常用的存储数据的方式。除了根节点之外,每个节点都有一个父节点,最多有两个子节点,左孩子和右孩子
    对于二叉树有如下操作:

    1 添加节点: 按层次添加,优先选择层次最小的,并且优先靠左添加节点
    2 树的遍历: 分为 深度优先 和 广度优先

    构造一个二叉树当作例子 根是1 左孩子2 右孩子3 ......

    1
    2 3
    4 5 6 7

    广度优先遍历: 按照层次由低到高,先左后右的顺序 1 2 3 4 5 6 7
    编程实现的思想: 开启一个队列 queue(队列是数据结构中先进先出的实现,队列的朋友需要再看一看数据结构链表的知识)
    1 把 树根 1 放进队列 队列变成 1
    2 重复执行:从队列取一个队头出队一个节点,如果它有左孩子,把左孩子放入队列,如果他有右孩子把右孩子放入队列。输出当前节点的数值
    一直到队列空了为止
    2.1 从队头取出1 把1输出,把1的左孩子和右孩子添加到队列 队列变成: 2 3
    2.2 从对头取出2 把2输出,把2的左孩子和右孩子添加到队列 队列变成: 3 4 5
    2.3 从对头取出3 把3输出, 把3的左孩子右孩子添加到队列, 队列变成: 4 5 6 7
    2.4 从对头取出4 把4输出,它没有左孩子和右孩子 不用入队列
    2.5 从对头取出5 把5输出, 它没有左孩子右孩子 不用入队列
    2.6 从对头取出6 把6输出, 它没有左孩子右孩子 不用入队列
    2.7 从对头取出7 把7输出, 它没有左孩子右孩子 不用入队列
    2.8 队列空了,结束

    深度优先遍历:又分为三种:先序 中序 后序

    先序遍历(先输出根): 按照 根 左 右 的顺序 遍历结果:1 2 4 5 3 6 7
    1 对于树根1,先输出1,然后再遍历它的左子树和右子树
    1.1 对于左子树2是树根先输出2,再遍历它的左子树和右子树
    1.1.1 对于左子树4 树根4输出,没有左右子树 不用向下遍历
    1.1.2 对于右子树5 树根5输出 没有左右子树 不用向下遍历
    1.2 对于右子树3树根3 输出3, 在遍历它的左子树和右子树
    1.2.1 对于左子树6 输出根6 没有左右子树 不用向下遍历
    1.2.2 对于右子树7 输出根7 没有左右子树 不用向下遍历
    总结:先输出根,然后对左子树当成新树遍历,然后对右子树当成新树遍历,循环遍历到没有子树


    中序遍历(中间输出根):按照 左 根 右 的顺序 遍历结果:4 2 5 1 6 3 7
    1 对于树1 先对左子树遍历 再输出根 最后对右子树遍历
    1.1 对于左子树2 先对左子树遍历 再输出根 最后对右子树遍历
    1.1.1 对于左子树4,没有孩子了 输出树根 4
    1.1.2 遍历完左子树了 输出根 2 再遍历右子树
    1.1.3 对于右子树5,没有孩子了 输出树根 5
    1.2 左子树2遍历完了 输出根 1 再遍历右子树 3
    1.3 对于右子树3 先对左子树遍历 再输出根 最后对右子树遍历
    1.3.1 对左子树6 没有孩子了 输出根6
    1.3.2 左子树6遍历完了 输出根 3 再遍历右子树7
    1.3.3 对于右子树7 没有孩子 输出根 7


    后序遍历(最后输出根):按照 左 右 根 的顺序 遍历结果:4 5 2 6 7 3 1
    1 对于树 先遍历左子树 再遍历右子树 最后输出根
    1.1 对于左子树2 先遍历左子树 再遍历右子树 最后输出根
    1.1.1对于左子树4 没有孩子了 输出根 4
    1.1.2对于右子树5 没有孩子了 输出根 5
    1.1.3左子树 右子树遍历完了输出根 2
    1.2 对于右子树3 先遍历左子树 再遍历右子树 最后输出根
    1.2.1 对于左子树6 没有孩子了 输出根 6
    1.2.2 对于右子树7 没有孩子了 输出根 7
    1.2.3 左右子树遍历完了 最后输出根 3
    1。3 左右子树遍历完了 最后输出根 1


    接下来 我们用python来实现一下各种操作!!!

      1 #一个节点的数据类型,包含左子孩子节点指针 右孩子节点指针 和值
      2 class Node(object):
      3     def __init__(self , item):
      4         self.left = None    #指向左子节点
      5         self.right = None   #指向右子节点
      6         self.item = item    #保存值
      7 
      8 #树的类
      9 class Tree(object):
     10     def __init__(self):
     11         self.root = None #保存树根所在位置
     12     #添加节点方法,按照层次由低到高,优先靠左的思想添加
     13     def add(self , item ):
     14         node = Node(item) #首先创建一个节点
     15         #如果树还没有树根
     16         if self.root is None:
     17             self.root = node
     18         else :
     19             # 这里需要用到广度优先遍历的思想来找第一个可以添加节点的位置
     20             # 开一个队列用于广度优先搜索 先把树根放进去
     21             queue = [ self.root ]
     22             #循环操作:
     23             # 出队一个节点,如果它没有左海子,为它添加左孩子 退出  否则 左孩子入队列
     24             #            如果他没有右孩子,为它添加右孩子 退出  否则 右孩子如队列
     25             #如果队列里面有元素我们就一直操作。队列空了就退出来(这个只是保险条件,一般队列还没空就找到空位创建节点然后退出了)
     26             while queue :
     27                 #取出队节点
     28                 temp = queue.pop(0)
     29                 #如果没有左孩子 我们 添加左孩子后退出
     30                 if temp.left is None:
     31                     temp.left = node
     32                     return
     33                 #如果有左孩子 我们把左孩子入队列
     34                 else:
     35                     queue.append(temp.left)
     36 
     37                 #如果没有右孩子 我们添加右孩子 然后退出
     38                 if temp.right is None:
     39                     temp.right = node
     40                     return
     41                 # 如果有右孩子 我们把右孩子入队列
     42                 else :
     43                     queue.append( temp.right )
     44     # 广度优先遍历
     45     def breadth_travel(self):
     46         #开启一个队列 把树根放进去
     47         queue=[ self.root ]
     48         #循环操作:从对头取出节点,把值输出后 把他们的左孩子右孩子添加到队列里,一直到队列空了,说明遍历结束
     49         # 只要队列不是空的 我们就一直遍历
     50         while queue :
     51             #从队列头取出一个元素
     52             temp = queue.pop(0)
     53             #输出节点的值
     54             print( temp.item,end=" " )
     55             #如果节点有左孩子 就把左孩子追加到队列
     56             if temp.left is not None:
     57                 queue.append( temp.left )
     58             #如果节点有右孩子 就把右孩子追加到队列
     59             if temp.right is not None:
     60                 queue.append(temp.right)
     61         #最后来一个换行
     62         print()
     63     #先序遍历  按照 根 左 右 进行遍历
     64     # 把当前子树的树根传进去做参数
     65     def preOder(self , node):
     66         #如果传进来的十个None,说明上一个节点 没有左孩子或者右孩子 传进来一个None 那就不遍历这个节点
     67         if not node:
     68             return
     69         #先把根的值输出来
     70         print(node.item,end=" ")
     71         #然后对左孩子进行遍历
     72         self.preOder( node.left )
     73         #然后对右孩子遍历
     74         self.preOder( node.right )
     75     #中序遍历 按照 左 根 右 的顺序进行遍历
     76     # 传入当前要遍历的子树的根
     77     def inOrder(self, node):
     78         #当传入的子树是None 说明上一个节点没有这个子树 传进来了None 此时不用遍历它了
     79         if not node:
     80             return None
     81         #先对左子树进行遍历
     82         self.inOrder( node.left )
     83         #再输出自己的数值
     84         print( node.item,end=" " )
     85         #最后对右子树进行遍历
     86         self.inOrder(node.right)
     87     #后序遍历 按照 左 右 根 的顺序进行遍历
     88     # 把当前子树的树根传进去做参数
     89     def postOrder(self,node):
     90         #如果传进来一个None 说明上一个节点没有这可子树,这时候不用遍历
     91         if not node :
     92             return
     93         #先对左子树进行遍历
     94         self.postOrder(node.left)
     95         #再对右子树进行遍历
     96         self.postOrder(node.right)
     97         #最后输出自己的值
     98         print( node.item,end=" " )
     99 
    100     #我们再封装一下,在外部调用自己的三个深度优先遍历可以不传入自己的根
    101     def preOrder_travel(self):
    102         self.preOder(self.root)
    103     def inOrder_travel(self):
    104         self.inOrder( self.root )
    105     def postOrder_travel(self):
    106         self.postOrder(self.root)
    107 
    108 
    109 
    110 if __name__ == '__main__':
    111     tree = Tree()
    112     tree.add(1)
    113     tree.add(2)
    114     tree.add(3)
    115     tree.add(4)
    116     tree.add(5)
    117     tree.add(6)
    118     tree.add(7)
    119     tree.breadth_travel() # 1 2 3 4 5 6 7
    120     tree.preOrder_travel() #1 2 4 5 3 6 7
    121     print()# 回车换行
    122     tree.inOrder_travel() #4 2 5 1 6 3 7
    123     print()# 回车换行
    124     tree.postOrder_travel() #4 5 2 6 7 3 1

     

    java实现:

      1 import java.util.LinkedList;
      2 import java.util.Queue;
      3 //二叉树的实现
      4 class Main {
      5     public static void main(String[] args) {
      6         Tree tree = new Tree();
      7         tree.append(1);
      8         tree.append(2);
      9         tree.append(3);
     10         tree.append(4);
     11         tree.append(5);
     12         tree.append(6);
     13         tree.append(7);
     14         tree.breadth();
     15         tree.preOrder_travel();
     16         tree.inOrder_travel();
     17         tree.postOrder_travel();
     18     }
     19 
     20 }
     21 //一棵树的叶子节点
     22 class Node{
     23     int value;
     24     Node left = null;
     25     Node right = null;
     26     public Node(int value){
     27         this.value = value;
     28     }
     29 }
     30 
     31 public class Tree{
     32     private Node root = null;
     33     public Node getRoot(){
     34         return this.root;
     35     }
     36     //添加叶子节点方法
     37     public void append( int value ){
     38         Node node = new Node(value);
     39         //如果根节点是空的,就添加根节点
     40         if( this.root == null ){
     41             this.root = node;
     42         //根节点不是空的 按层次遍历 找到最浅层次最靠左的位置把节点放进去
     43         }else{
     44             Queue<Node> queue = new LinkedList<Node>();
     45             queue.offer(this.root);
     46             while( ! queue.isEmpty() ){
     47                 Node cur = queue.poll();
     48                 if( cur.left == null ){
     49                     cur.left = node;
     50                     break;
     51                 }else{
     52                     queue.add(cur.left);
     53                 }
     54                 if( cur.right == null ){
     55                     cur.right = node;
     56                     break;
     57                 }else{
     58                     queue.add(cur.right);
     59                 }
     60             }    
     61         }    
     62     }
     63     //广度优先遍历
     64     public void breadth( ){
     65         Queue<Node> queue = new LinkedList<Node>();
     66         queue.add(this.root);
     67         while( !queue.isEmpty() ){
     68             Node cur = queue.poll();
     69             System.out.print(cur.value+" ");
     70             if(cur.left!=null){
     71                 queue.add(cur.left);
     72             }
     73             if(cur.right!= null){
     74                 queue.add(cur.right);
     75             }
     76         }
     77         System.out.println();
     78     }
     79     //深度优先遍历
     80     //先序遍历
     81     public void preOrder_travel(){
     82         preOrder(this.root);
     83         System.out.println();
     84     }
     85     private void preOrder(Node root){
     86         if(root == null){
     87             return;
     88         }
     89         System.out.print( root.value + " " );
     90         preOrder(root.left);
     91         preOrder(root.right);
     92     }
     93     //中序遍历
     94     public void inOrder_travel(){
     95         inOrder(this.root);
     96         System.out.println();
     97     }
     98     private void inOrder(Node root){
     99         if(root == null){
    100             return;
    101         }
    102         inOrder(root.left);
    103         System.out.print( root.value + " " );
    104         inOrder(root.right);
    105     }
    106     //后序遍历
    107     public void postOrder_travel(){
    108         postOrder(this.root);
    109         System.out.println();
    110     }
    111     private void postOrder(Node root){
    112         if(root == null){
    113             return;
    114         }
    115         postOrder(root.left);
    116         postOrder(root.right);
    117         System.out.print( root.value + " " );
    118     }
    119 }

    对于初学者来说,二叉树的遍历可能有点难,不过没有关系,认真理解算法思想,一点一点来,总会理解的!

    对于算法的实现,不同的人实现方式多少有些不一样,如果有好伙伴有更好的方案,也欢迎沟通交流~~

  • 相关阅读:
    visual c++ 动态链接库调用总结
    机器学习 Support Vector Machines 1
    机器学习 Generative Learning Algorithm (B)
    机器学习 线性回归
    机器学习 矩阵的基本运算
    OpenCV——百叶窗
    机器学习 Generative Learning Algorithm (A)
    OpenCV——非线性滤波器
    机器学习 Logistic Regression
    机器学习 从矩阵和概率的角度解释最小均方误差函数
  • 原文地址:https://www.cnblogs.com/Lin-Yi/p/7324670.html
Copyright © 2011-2022 走看看