二叉树是很重要的数据结构,在面试还是日常开发中都是很重要的角色。

首先是建立树的过程,对比C或是C++的实现来讲,其涉及到了较为复杂的指针操作,但是在面向对象的语言中,就不需要考虑指针, 内存等。首先我们需要定义一个树节点, 我们采用基于链表设计的节点, 首先定义一个数据域, 其次就是左孩子和右孩子。如下定义:

  1. # 树节点的定义
  2. class Node:
  3. def __init__(self, data=-1, lchild=None, rchild=None):
  4. self.lchild = lchild # 表示左子树
  5. self.rchild = rchild # 表示右子树
  6. self.data = data # 表示数据域

建立树的实现有两种,遍历建树与层次建树,这两种分别是基于堆栈和队列来实现的,先来看看最基本的递归建树。
递归建树的过程无非就是一路走到底,但是需要将节点的左右孩子节点对其余的节点相关联起来。因此,我们可以如此来实现:

  1. def traversal_create(self, root):
  2. data = input()
  3. if data is "#":
  4. return None
  5. else:
  6. root.data = data
  7. root.lchild = self.traversal_create(root.lchild)
  8. root.rchild = self.traversal_create(root.rchild)
  9. return root

首先我们传入的参数是一个默认的节点,其data数据域为-1,然后我们接受输入的数据,赋值给节点数据域,然后就是递归了,将左右孩子节点关联起来。总体来讲,应该不难理解。

下面看看层次建树的实现,所谓层次建树其实就是基于队列的操作,利用队列先进先出的特点,每次我们访问一个节点的时候,将其存入队列中,待遍历玩当前节点的左右孩子节点,队列就弹出一个节点,之后的操作都是一样的。看看代码:

  1. def add(self, elem):
  2. node = Node(elem)
  3. # 根节点
  4. if self.root.data == -1:
  5. self.root = node
  6. self.myQueue.append(self.root)
  7. else:
  8. treeNode = self.myQueue[0] # 记录结点
  9. if treeNode.lchild is None:
  10. treeNode.lchild = node
  11. self.myQueue.append(treeNode.lchild)
  12. else:
  13. treeNode.rchild = node
  14. self.myQueue.append(treeNode.rchild)
  15. self.myQueue.popleft() # 弹出已经处理好左右子树的父结点

我们输入一个数据,然后根据数据初始化一个节点,放入队列中,随后就是访问的操作了。

树的三序遍历就不用说了,基于递归的,很好理解,那么基于队列以及堆栈的的遍历呢?
对比下基于队列的建树,我们完全可以写出基于队列的遍历, 也是使用队列来存储节点,然后输出左右孩子的数据:

  1. # 层次遍历 使用队列
  2. def queue_tarversal(self, root):
  3. if root is None:
  4. return
  5. q = deque()
  6. q.append(root)
  7. while q:
  8. node = q.pop()
  9. print(node.data)
  10. if node.lchild is not None:
  11. q.append(node.lchild)
  12. else:
  13. q.append(node.rchild)

基于堆栈的呢?联想下堆栈的特点,我们一路沿着左子树遍历下去,同时使用堆栈来存储元素,然后在弹出遍历右孩子节点:

  1. # 使用堆栈来遍历
  2. def stack_traversal(self, root):
  3. if root is None:
  4. return
  5. mystack = []
  6. node = root
  7. while node or mystack:
  8. while node:
  9. print(node.data)
  10. mystack.append(node)
  11. node = node.lchild
  12. node = mystack.pop()
  13. node = node.rchild

数据结构是难点也是基础,不管怎么样都应该好好学习。

完整代码:

  1. ''' 二叉树的建立及实现 (递归与非递归) '''
  2. from collections import deque
  3.  
  4. # 树节点的定义
  5. class Node:
  6. def __init__(self, data=-1, lchild=None, rchild=None):
  7. self.lchild = lchild # 表示左子树
  8. self.rchild = rchild # 表示右子树
  9. self.data = data # 表示数据域
  10.  
  11. class Create_Tree:
  12. def __init__(self):
  13. self.root = Node() # 表示结点
  14. self.myQueue = deque() # 使用队列不会有太多的内存开销
  15.  
  16. # 按层次生成树
  17. def add(self, elem):
  18. node = Node(elem)
  19. # 根节点
  20. if self.root.data == -1:
  21. self.root = node
  22. self.myQueue.append(self.root)
  23. else:
  24. treeNode = self.myQueue[0] # 记录结点
  25. if treeNode.lchild is None:
  26. treeNode.lchild = node
  27. self.myQueue.append(treeNode.lchild)
  28. else:
  29. treeNode.rchild = node
  30. self.myQueue.append(treeNode.rchild)
  31. self.myQueue.popleft() # 弹出已经处理好左右子树的父结点
  32.  
  33. # 递归建树
  34. def traversal_create(self, root):
  35. data = input()
  36. if data is "#":
  37. return None
  38. else:
  39. root.data = data
  40. root.lchild = self.traversal_create(root.lchild)
  41. root.rchild = self.traversal_create(root.rchild)
  42. return root
  43.  
  44. # 前序遍历输出
  45. def digui(self, root):
  46. if root is None:
  47. return
  48. print(root.data)
  49. self.digui(root.lchild)
  50. self.digui(root.rchild)
  51.  
  52. # 使用堆栈来遍历
  53. def stack_traversal(self, root):
  54. if root is None:
  55. return
  56. mystack = []
  57. node = root
  58. while node or mystack:
  59. while node:
  60. print(node.data)
  61. mystack.append(node)
  62. node = node.lchild
  63. node = mystack.pop()
  64. node = node.rchild
  65.  
  66. # 层次遍历 使用队列
  67. def queue_tarversal(self, root):
  68. if root is None:
  69. return
  70. q = deque()
  71. q.append(root)
  72. while q:
  73. node = q.pop()
  74. print(node.data)
  75. if node.lchild is not None:
  76. q.append(node.lchild)
  77. else:
  78. q.append(node.rchild)
  79.  
  80. if __name__ == "__main__":
  81. elems = range(10)
  82. tree = Create_Tree()
  83. for i in elems:
  84. # 非递归建树,主要就是根据 队列FIFO的特点以及广度遍历的思路
  85. tree.add(i)
  86.  
  87. # 递归建树
  88. # tree.traversal_create(tree.root)
  89.  
  90. # 递归遍历
  91. tree.digui(tree.root)
  92. # 栈遍历
  93. # tree.stack_traversal(tree.root)

二叉树的建立以及遍历的多种实现(python版)的更多相关文章

  1. C语言二叉树的建立与遍历

    二叉树的建立和遍历都要用到递归,先暂时保存一下代码,其中主要是理解递归的思想,其它的就都好理解了.这里是三种遍历方式,其实理解一种,其它的几个就都理解了,就是打印出来的顺序不一样而已.建立和遍历的方式 ...

  2. 一步一步写数据结构(二叉树的建立和遍历,c++)

    简述: 二叉树是十分重要的数据结构,主要用来存放数据,并且方便查找等操作,在很多地方有广泛的应用. 二叉树有很多种类,比如线索二叉树,二叉排序树,平衡二叉树等,本文写的是最基础最简单的二叉树. 思路: ...

  3. 二叉树的建立与遍历(c语言)入门

    树其实在本质上就是一对多,链表就是一对一. 二叉树的建立: 这里的代码采用的是最粗暴的创建方法,无实际用处.但初次学习二叉树可以通过这个创建方法更好的理解二叉树. 二叉树的遍历: 遍历在大体上分为递归 ...

  4. 二叉树的建立与遍历(山东理工OJ)

    题目描写叙述 已知一个按先序序列输入的字符序列,如abc,,de,g,,f,,,(当中逗号表示空节点).请建立二叉树并按中序和后序方式遍历二叉树,最后求出叶子节点个数和二叉树深度. 输入 输入一个长度 ...

  5. C语言实现二叉树的建立、遍历以及表达式的计算

    实现代码 #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <ctype ...

  6. python实现二叉树的建立以及遍历(递归前序、中序、后序遍历,队栈前序、中序、后序、层次遍历)

    #-*- coding:utf-8 -*- class Node: def __init__(self,data): self.data=data self.lchild=None self.rchi ...

  7. C++编程练习(8)----“二叉树的建立以及二叉树的三种遍历方式“(前序遍历、中序遍历、后续遍历)

    树 利用顺序存储和链式存储的特点,可以实现树的存储结构的表示,具体表示法有很多种. 1)双亲表示法:在每个结点中,附设一个指示器指示其双亲结点在数组中的位置. 2)孩子表示法:把每个结点的孩子排列起来 ...

  8. 数据结构代码整理(线性表,栈,队列,串,二叉树,图的建立和遍历stl,最小生成树prim算法)。。持续更新中。。。

    //归并排序递归方法实现 #include <iostream> #include <cstdio> using namespace std; #define maxn 100 ...

  9. 数据结构实习 - problem K 用前序中序建立二叉树并以层序遍历和后序遍历输出

    用前序中序建立二叉树并以层序遍历和后序遍历输出 writer:pprp 实现过程主要是通过递归,进行分解得到结果 代码如下: #include <iostream> #include &l ...

随机推荐

  1. java多线程的编程实例

    java中可有两种方式实现多线程: 一种是继承Thread类: 一种是实现Runnable接口: Thread类 是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的ru ...

  2. Android开发优化之——使用软引用和弱引用

    Java从JDK1.2版本开始,就把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引用和虚引用. 这里重点介绍一下软引用和弱引用. 如果 ...

  3. Hibernate配置文件current_session_context_class的意思

    转自:http://shuaigg-babysky.iteye.com/blog/563423 此设置的作用如下: What does sessionFactory.getCurrentSession ...

  4. linux常用的内核镜像格式

    linux常用的内核镜像格式 Linux内核有多种格式的镜像,包括vmlinux.Image.zImage等. 1.     Linux内核镜像格式 1.1 vmlinux vmlinuz是可引导的. ...

  5. linux内核中默认logo的具体位置

    /driver/logo/... 以下这个目录下对应的是logo的设置

  6. java linux ImageIO 验证码在一段时间以后出不来 问题总结

    最近在测试上布署的项目经常性的出现验证码过了一段时间以后出不来的情况,耐心找了一下,最后在上级的指导下发现了报错,其实说真的,我自己也找到了这个报错,只是没有当一回事.因为这个验证码的东西不是我写的, ...

  7. ubuntu 中 eclipse 的菜单栏 显示问题

    在新版ubuntu中装eclipse,很多人会遇到eclipse打开之后没有菜单栏, 其实就是缺一个环境变量UBUNTU_MENUPROXY. 在/etc/profile 里面新建这个变量并且把值写成 ...

  8. UNIX环境高级编程——无名管道和有名管道

    一.进程间通信 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2 ...

  9. Socket编程实践(3) --Socket API

    socket函数 #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, ...

  10. (四十五)Modal 模态窗口 -遮盖

    任何控制器都能通过Modal方式切换. Modal的默认效果是:新显示的控制器从屏幕底部向上,直到盖住之前的控制器为止. 假设有One和Two两个控制器: One到Two的Modal方法:presen ...