数据结构可以说是编程的内功心法,掌握好数据结构真的非常重要。
目前基本上流行的数据结构都是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来实现一下各种操作!!!
 #一个节点的数据类型,包含左子孩子节点指针 右孩子节点指针 和值
class Node(object):
def __init__(self , item):
self.left = None #指向左子节点
self.right = None #指向右子节点
self.item = item #保存值 #树的类
class Tree(object):
def __init__(self):
self.root = None #保存树根所在位置
#添加节点方法,按照层次由低到高,优先靠左的思想添加
def add(self , item ):
node = Node(item) #首先创建一个节点
#如果树还没有树根
if self.root is None:
self.root = node
else :
# 这里需要用到广度优先遍历的思想来找第一个可以添加节点的位置
# 开一个队列用于广度优先搜索 先把树根放进去
queue = [ self.root ]
#循环操作:
# 出队一个节点,如果它没有左海子,为它添加左孩子 退出 否则 左孩子入队列
# 如果他没有右孩子,为它添加右孩子 退出 否则 右孩子如队列
#如果队列里面有元素我们就一直操作。队列空了就退出来(这个只是保险条件,一般队列还没空就找到空位创建节点然后退出了)
while queue :
#取出队节点
temp = queue.pop(0)
#如果没有左孩子 我们 添加左孩子后退出
if temp.left is None:
temp.left = node
return
#如果有左孩子 我们把左孩子入队列
else:
queue.append(temp.left) #如果没有右孩子 我们添加右孩子 然后退出
if temp.right is None:
temp.right = node
return
# 如果有右孩子 我们把右孩子入队列
else :
queue.append( temp.right )
# 广度优先遍历
def breadth_travel(self):
#开启一个队列 把树根放进去
queue=[ self.root ]
#循环操作:从对头取出节点,把值输出后 把他们的左孩子右孩子添加到队列里,一直到队列空了,说明遍历结束
# 只要队列不是空的 我们就一直遍历
while queue :
#从队列头取出一个元素
temp = queue.pop(0)
#输出节点的值
print( temp.item,end=" " )
#如果节点有左孩子 就把左孩子追加到队列
if temp.left is not None:
queue.append( temp.left )
#如果节点有右孩子 就把右孩子追加到队列
if temp.right is not None:
queue.append(temp.right)
#最后来一个换行
print()
#先序遍历 按照 根 左 右 进行遍历
# 把当前子树的树根传进去做参数
def preOder(self , node):
#如果传进来的十个None,说明上一个节点 没有左孩子或者右孩子 传进来一个None 那就不遍历这个节点
if not node:
return
#先把根的值输出来
print(node.item,end=" ")
#然后对左孩子进行遍历
self.preOder( node.left )
#然后对右孩子遍历
self.preOder( node.right )
#中序遍历 按照 左 根 右 的顺序进行遍历
# 传入当前要遍历的子树的根
def inOrder(self, node):
#当传入的子树是None 说明上一个节点没有这个子树 传进来了None 此时不用遍历它了
if not node:
return None
#先对左子树进行遍历
self.inOrder( node.left )
#再输出自己的数值
print( node.item,end=" " )
#最后对右子树进行遍历
self.inOrder(node.right)
#后序遍历 按照 左 右 根 的顺序进行遍历
# 把当前子树的树根传进去做参数
def postOrder(self,node):
#如果传进来一个None 说明上一个节点没有这可子树,这时候不用遍历
if not node :
return
#先对左子树进行遍历
self.postOrder(node.left)
#再对右子树进行遍历
self.postOrder(node.right)
#最后输出自己的值
print( node.item,end=" " ) #我们再封装一下,在外部调用自己的三个深度优先遍历可以不传入自己的根
def preOrder_travel(self):
self.preOder(self.root)
def inOrder_travel(self):
self.inOrder( self.root )
def postOrder_travel(self):
self.postOrder(self.root) if __name__ == '__main__':
tree = Tree()
tree.add(1)
tree.add(2)
tree.add(3)
tree.add(4)
tree.add(5)
tree.add(6)
tree.add(7)
tree.breadth_travel() # 1 2 3 4 5 6 7
tree.preOrder_travel() #1 2 4 5 3 6 7
print()# 回车换行
tree.inOrder_travel() #4 2 5 1 6 3 7
print()# 回车换行
tree.postOrder_travel() #4 5 2 6 7 3 1

java实现:

 import java.util.LinkedList;
import java.util.Queue;
//二叉树的实现
class Main {
public static void main(String[] args) {
Tree tree = new Tree();
tree.append(1);
tree.append(2);
tree.append(3);
tree.append(4);
tree.append(5);
tree.append(6);
tree.append(7);
tree.breadth();
tree.preOrder_travel();
tree.inOrder_travel();
tree.postOrder_travel();
} }
//一棵树的叶子节点
class Node{
int value;
Node left = null;
Node right = null;
public Node(int value){
this.value = value;
}
} public class Tree{
private Node root = null;
public Node getRoot(){
return this.root;
}
//添加叶子节点方法
public void append( int value ){
Node node = new Node(value);
//如果根节点是空的,就添加根节点
if( this.root == null ){
this.root = node;
//根节点不是空的 按层次遍历 找到最浅层次最靠左的位置把节点放进去
}else{
Queue<Node> queue = new LinkedList<Node>();
queue.offer(this.root);
while( ! queue.isEmpty() ){
Node cur = queue.poll();
if( cur.left == null ){
cur.left = node;
break;
}else{
queue.add(cur.left);
}
if( cur.right == null ){
cur.right = node;
break;
}else{
queue.add(cur.right);
}
}
}
}
//广度优先遍历
public void breadth( ){
Queue<Node> queue = new LinkedList<Node>();
queue.add(this.root);
while( !queue.isEmpty() ){
Node cur = queue.poll();
System.out.print(cur.value+" ");
if(cur.left!=null){
queue.add(cur.left);
}
if(cur.right!= null){
queue.add(cur.right);
}
}
System.out.println();
}
//深度优先遍历
//先序遍历
public void preOrder_travel(){
preOrder(this.root);
System.out.println();
}
private void preOrder(Node root){
if(root == null){
return;
}
System.out.print( root.value + " " );
preOrder(root.left);
preOrder(root.right);
}
//中序遍历
public void inOrder_travel(){
inOrder(this.root);
System.out.println();
}
private void inOrder(Node root){
if(root == null){
return;
}
inOrder(root.left);
System.out.print( root.value + " " );
inOrder(root.right);
}
//后序遍历
public void postOrder_travel(){
postOrder(this.root);
System.out.println();
}
private void postOrder(Node root){
if(root == null){
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.print( root.value + " " );
}
}

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

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

python、java实现二叉树,细说二叉树添加节点、深度优先(先序、中序、后续)遍历 、广度优先 遍历算法的更多相关文章

  1. 二叉树 遍历 先序 中序 后序 深度 广度 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  2. 【IT笔试面试题整理】给定二叉树先序中序,建立二叉树的递归算法

    [试题描述]:  给定二叉树先序中序,建立二叉树的递归算法 其先序序列的第一个元素为根节点,接下来即为其左子树先序遍历序列,紧跟着是右子树先序遍历序列,固根节点已可从先序序列中分离.在中序序列中找到 ...

  3. SDUT-3343_数据结构实验之二叉树四:(先序中序)还原二叉树

    数据结构实验之二叉树四:(先序中序)还原二叉树 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 给定一棵二叉树的先序遍历 ...

  4. SDUT OJ 数据结构实验之二叉树四:(先序中序)还原二叉树

    数据结构实验之二叉树四:(先序中序)还原二叉树 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem ...

  5. Java 通过先序中序序列生成二叉树

    题目 二叉树的前序以及后续序列,以空格间隔每个元素,重构二叉树,最后输出二叉树的三种遍历方式的序列以验证. 输入: 1 2 3 4 5 6 7 8 9 10 3 2 5 4 1 7 8 6 10 9 ...

  6. 遍历二叉树 - 基于递归的DFS(前序,中序,后序)

    上节中已经学会了如何构建一个二叉搜索数,这次来学习下树的打印-基于递归的DFS,那什么是DFS呢? 有个概念就行,而它又分为前序.中序.后序三种遍历方式,这个也是在面试中经常会被问到的,下面来具体学习 ...

  7. 图的建立(邻接矩阵)+深度优先遍历+广度优先遍历+Prim算法构造最小生成树(Java语言描述)

    主要参考资料:数据结构(C语言版)严蔚敏   ,http://blog.chinaunix.net/uid-25324849-id-2182922.html   代码测试通过. package 图的建 ...

  8. UVa 二叉树重建(先序+中序求后序)

    题意是给出先序和中序,求出后序. 先序遍历先访问根结点,通过根结点可以在中序中把序列分为左子树部分和右子树部分,我建了一个栈,因为后序遍历最后访问根结点,所以把每次访问的根结点放入栈中.因为后序遍历先 ...

  9. 数据结构实验之二叉树四:(先序中序)还原二叉树 (SDUT 3343)

    #include <bits/stdc++.h> using namespace std; struct node { char data; struct node *lc, *rc; } ...

  10. java基础编程——重建二叉树

    题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7, ...

随机推荐

  1. 大数运算的算法设计和C++实现

    1.背景 工作中遇到过需要进行极大数据的存储和运算的场景,当时使用Python解决了这个问题,在Python中,整数没有位数限制,使用起来很方便.但是当程序主体使用C/C++实现时,就比较麻烦.所以考 ...

  2. java创建运行以及项目结构

    一 创建java project 再src下添加class,选择一个class添加main方法作为程序的入口 二.项目结构: src下添加不同的包,命名方法为com.jikexueyuan.hello ...

  3. java大数(BigInteger)

    JAVA之BigInteger 用Java来处理高精度问题,相信对很多ACMer来说都是一件很happy的事,简单易懂.用Java刷了一些题,感觉Java还不错,在处理高精度和进制转换中,调用库函数的 ...

  4. Explain

    explain关键字 explain关键字一般放在SELECT查询语句的前面,用于描述MySQL如何执行查询操作.以及MySQL成功返回结果集需要执行的行数.explain 可以帮助我们分析 sele ...

  5. Redis Setex命令

    Redis SETEX命令用于在Redis键中的指定超时,设置键的字符串值. 返回值 字符串,如果在键中设置了值则返回OK.如果值未设置则返回 Null. 语法 下面是Redis SETEX命令的基本 ...

  6. 【Python】 http客户端库requests & urllib2 以及ip地址处理IPy

    requests requests是个HTTPClient库,相比于urllib,urllib2等模块比更加简洁易用 ■ get请求 作为示例,讲一下关于requests如何发起并处理一个get请求 ...

  7. Redis --> Redis架构设计

    Redis架构设计 一.前言   Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件. 它支持多种类型的数据结构,如 字符串(strings), 散列 ...

  8. DB2开发系列之三——SQL函数

    1.内置函数分类(SYSIBM模式内) 1)标量函数:返回一个标量值的函数: 2)聚合函数:也叫列函数,也返回一个标量值,这个值是一组输入值的计算结果:3)表函数:向引用它的 SQL 语句返回一个表: ...

  9. C#编程语言之委托与事件(二)—— C#事件

    前面已经大致讲述了C#委托的一些基础知识点,本文接下来的内容是C#中的事件(Event),在此我提个建议,如果是刚接触C#的委托类型的朋友可以先看到这里,等熟悉了委托的使用之后(大约1-2天)再来了解 ...

  10. SuperMap iClient 查询成功后如何传递参数?

    一.iClient API文档中的接口描述 二.范例 //定义一个this对象 this.param = new SuperMap.LonLat(point.x, point.y); querySer ...