二叉树是面试中常考的数据结构,因为涉及大量指针操作,因此可以考察思维的严谨性和灵活性。但是校招中的二叉树题规律性很强,因此需要总结一下。

各种常见的二叉树概念

二叉树:每个结点最多有两个子树(左子树和右子树)的树结构。

节点的层次:一个结点的层次直观上来说就是其所在的行,其中根结点层次为1。

二叉树的深度:二叉树的深度指二叉树的最大叶子结点所在的层。二叉树的深度求解可用递归方式实现,等于max(左子树深度,右子树深度)+1。

结点的度:二叉树结点的度指该结点分支的个数,取值为0、1或2。

结点种类:

  • 根结点:第一层的结点
  • 叶子结点:度为0的结点
  • 分支结点:度不为0的结点
  • 孩子结点:结点的子树的根称为该结点的孩子结点
  • 兄弟结点:同一双亲的孩子结点
  • 祖先结点:从根到该结点上所经分支的所有结点
  • 子孙节点:以某结点为根的子树中任一结点都称为该结点的子孙节点

建立一棵二叉树

class Node:"""节点类"""def __init__(self, value=None, left=None, right=None):self.val = valueself.left = leftself.right = rightclass Tree:"""树类"""def __init__(self):self.root = Node()self.queue = []def add(self, val):"""为树添加节点"""node = Node(value=val)if self.root.val is None:  # 如果树是空的,则对根节点赋值self.root = nodeself.queue.append(self.root)else:treeNode = self.queue[0]  # 此节点的子树还没有齐if treeNode.left is None:treeNode.left = nodeself.queue.append(treeNode.left)else:treeNode.right = nodeself.queue.append(treeNode.right)self.queue.pop(0)  # 如果该节点存在左右子树,将此节点丢弃if __name__ == '__main__':vals = range(10)  # 生成十个数据作为树节点tree = Tree()  # 新建一个树对象for val in vals:tree.add(val)  # 逐个添加树的节点

代码构造的二叉树

二叉树的分类

满二叉树:除叶结点外每一个结点都有左右子结点并且叶子结点都处在最底层的二叉树。

完全二叉树:除最后一层外,其他各层的结点数都达到最大,最后一层的叶子结点都是从左往右依次排布。

二叉排序树(BST):或者是一棵空树,或者具有如下性质:(1)若左子树不为空,则左子树上所有结点的值均小于它的根结点的值;(2)若右子树不为空,则右子树上所有结点的值均大于它的根结点的值;(3)左右子树也分别为二叉排序树;(4)没有值相等的结点。

平衡二叉树(AVL):一种二叉排序树,其中每个结点的左子树和右子树的高度差至多等于1。要么它是一棵空树,要么它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。

二叉树的遍历

二叉树最重要的是四种遍历算法:前序遍历(递归和非递归)、中序遍历(递归和非递归)、后序遍历(递归和非递归)和层次遍历。

前序遍历(根左右)

先访问根结点,然后访问左子树,再访问右子树。

递归算法:

def pre_order(root):if root:print(root.val, end=" ")pre_order(root.left)pre_order(root.right)

非递归算法:

使用栈来临时存储节点:(1)打印根结点数据;(2)把根结点的right入栈,遍历左子树;(3)遍历完左子树返回时,栈顶元素应为right,出栈,遍历以该结点为根的子树

def pre_order_stack(root):p = roots = []  # stackwhile p or s:while p:print(p.val, end=" ")s.append(p.right)p = p.leftif s:  # 注意这里是if,不是whilep = s.pop(-1)

中序遍历(左根右)

递归算法:

def in_order(root):if root:in_order(root.left)print(root.val, end=" ")in_order(root.right)

非递归算法:

使用栈来存储临时节点,(1)先将根节点入栈,遍历左子树;(2)遍历完左子树返回时,栈顶元素应为根节点,此时出栈,并打印节点数据;(3)再中序遍历右子树。

def in_order_stack(root):p = roots = []  # stackwhile p or s:while p:s.append(p)p = p.leftif s:p = s.pop(-1)print(p.val, end=" ")p = p.right

后序遍历(左右根)

递归算法:

def post_order(root):if root:post_order(root.left)post_order(root.right)print(root.val, end=" ")

非递归算法:

使用栈来存储临时节点,使用哈希表来记录状态。

假设root时遍历树的根指针,后序遍历要求在遍历完左、右子树后再访问根,需要判断根结点的左、右子树是否均遍历过。使用标记法,节点入栈时,将该结点存入哈希表,值为0表示遍历左子树前的现场保护,值为1表示遍历右子树前的现场保护。

首先将root,遍历左子树;返回后,修改哈希表中该结点的值为1,遍历右子树,最后访问根节点。

def post_order_stack(root):p = roots = []  # stackd = {}while p or s:while p:s.append(p)d[p] = 0p = p.leftif s:p = s[-1]if d[p] == 1: # 如果该结点的右子树遍历过了,则打印该结点的值print(p.val, end=" ")s.pop(-1)p = Noneelse:d[p] = 1p = p.right

层次遍历

层次遍历需要使用一个辅助队列,初始元素是根结点。当队列不为空时,每次打印队列最前端结点的值,然后判断该结点左子结点是否存在,存在就压入队列;再判断该结点右子节点是否存在,存在就压入队列。

def level_order(root):if root is None:return Nonemy_queue = [root]node = rootwhile my_queue:node = my_queue.pop(0)print(node.val, end=" ")if node.left:my_queue.append(node.left)if node.right:my_queue.append(node.right)

二叉树遍历的应用

分层打印二叉树

在层次遍历的基础上,使用两个额外的变量分别保存当前层需要打印的结点数和下一层的结点数。

def level_print(root):if root is None:return Nonemy_queue = [root]node = rootto_be_printed = 1next_level = 0while my_queue:node = my_queue.pop(0)if to_be_printed:print(node.val, end=" ")to_be_printed -= 1else:to_be_printed = next_levelnext_level = 0print()print(node.val, end=" ")to_be_printed -= 1if node.left:my_queue.append(node.left)next_level += 1if node.right:my_queue.append(node.right)next_level += 1

之字形打印二叉树

def level_print2(root):"""之字形打印二叉树,在分行打印的基础上添加一个记录本层顺序的值,之前打印的地方换成压到一个列表"""if root is None:return Nonemy_queue = []node = rootmy_queue.append(node)to_be_printed = 1next_level_num = 0all = [[], ]level_num = 0while my_queue:node = my_queue.pop(0)if to_be_printed > 0:# print(node.elem, end=" ")all[level_num].append(node.val)to_be_printed -= 1else:print()to_be_printed = next_level_numnext_level_num = 0level_num += 1all.append([])all[level_num].append(node.val)to_be_printed -= 1if node.left is not None:my_queue.append(node.left)next_level_num += 1if node.right is not None:my_queue.append(node.right)next_level_num += 1for i in range(len(all)):if i % 2 == 0:for j in all[i]:print(j, end=" ")if i != len(all) - 1:print()else:all[i].reverse()for j in all[i]:print(j, end=" ")if i != len(all) - 1:print()

判断二叉树是否为完全二叉树

算法:

  1. 如果为空树,直接返回True;
  2. 采用层次遍历,使用一个变量leaf(默认为0);
  3. 如果当前结点有右孩子,且没有左孩子,直接返回False;
  4. 如果当前结点没有两个孩子,那么leaf=1,之后的节点必须都为叶节点,即不能有孩子,否则返回False;
  5. 遍历结束后没有返回,那么返回True。
def is_complete_binary_tree(root):if not root:return Truemy_queue = [root]node = rootleaf = 0while my_queue:node = my_queue.pop(0)if node.left is None and node.right is not None:  # 没有左孩子,但有右孩子return Falseif leaf == 1 and (node.left is not None or node.right is not None): # 不应该有孩子的结点有孩子存在return Falseif leaf == 0 and node.left is not None and node.right is not None:my_queue.append(node.left)my_queue.append(node.right)elif leaf == 0 and node.left is not None and node.right is None:my_queue.append(node.left)leaf = 1elif leaf == 0 and node.left is None and node.right is None:leaf = 1return True

c++编写算法判断二叉树是否为完全二叉树_[校招-算法题] 二叉树基础算法1相关推荐

  1. 采用邻接表存储有向图,设计算法判断任意两个顶点间是否存在路径。设计算法,将一个无向图的邻接矩阵转换为邻接表。

    采用邻接表存储有向图,设计算法判断任意两个顶点间是否存在路径.设计算法,将一个无向图的邻接矩阵转换为邻接表. 采用邻接表存储有向图,设计算法判断任意两个顶点间是否存在路径. 设计算法,将一个无向图的邻 ...

  2. c++编写算法判断二叉树是否为完全二叉树_字节面试官:连这90道LeetCode算法题都不会也来面试?...

    面试大厂必刷:LeetCode算法90题 1. 买股票的最佳时机 难度级别:简单 题目: 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 如果你最多只允许完成一笔交易(即买入和卖出一 ...

  3. 编写算法判别给定二叉树是否为完全二叉树_推荐一位实力超强的平安前端算法大佬:瓶子君...

    今天给大家推荐一位平安大佬:前端瓶子君,一个专注于前端开发的小瓶子,五年大厂开发经验,掘金优秀作者. 「前端进阶算法」系列是她4月初发起的活动,从 0 到 1 构建完整的前端数据结构与算法体系.这是一 ...

  4. 编写算法判别给定二叉树是否为完全二叉树_别找了,链表和二叉树相关面试题以及解答,我都给你们找好了...

    来源公众号:苦逼的码农 作者:帅地 无论是在面试还是在平时的做题中,链表相关算法题以及二叉树相关算法题,可以说是考的非常非常多的.我在 2019 的秋招面试中,也是遇到了好几次.为此,我总结了 9 道 ...

  5. 判断是否是完全二叉树_【数据结构】二叉树高频考试题目【代码模板】!

    本文来自公众号程序员小乐(study_tech) 作者:IOExceptioner 编辑:www.jianshu.com/p/0190985635eb 先上二叉树的数据结构: class TreeNo ...

  6. java算法判断链表有没有闭环_前端算法系列之二:数据结构链表、双向链表、闭环链表、有序链表...

    前言 上一次我们讲到了数据结构:栈和队列,并对他们的运用做了一些介绍和案例实践:我们也讲到了怎么简单的实现一个四则运算.怎么去判断标签是否闭合完全等等,anyway,今天接着和大家介绍一些数据结构: ...

  7. 二叉树 平衡二叉树 红黑树_迅捷树,二叉树

    二叉树 平衡二叉树 红黑树 In this tutorial, we'll be discussing the Data Structure Trees and implement it using ...

  8. python 用if判断一个数是不是整数_五天学会Python基础02(下)

    函数和模块的使用 在讲解本章节的内容之前,我们先来研究一道数学题,请说出下面的方程有多少组正整数解. 事实上,上面的问题等同于将8个苹果分成四组每组至少一个苹果有多少种方案.想到这一点问题的答案就呼之 ...

  9. java集合笔试编程题_Java 基础算法及编程笔试题集合

    1. 斯诺克台球共有15个一分球,2,3,4,5,6,7分球各一个,规则是先打一个最低分球,然后可以打一个其他分值的球,如此反复,如果台面还有更低分值的球,打入的高分球计分,同时拿出来放回原位置,要求 ...

最新文章

  1. 拜读及分析Element源码-alert组件篇
  2. mysql or优化_MySQL 语句优化
  3. 计算机图学测试题及答案,《计算机图形学》练习测试题及参考答案
  4. CVPR 2020 | 序列化的三维形状生成网络PQ-NET
  5. Linux内核内存管理(1):内存块 - memblock
  6. oracle,sqlserver,mysql区别
  7. intellij idea elixir 插件
  8. 计算机网络上机指导,计算机网络上机指导书.pdf
  9. Eth-Trunk(链路聚合)之LACP(二层)
  10. 西北大学计算机课表,西北大学课表_2
  11. 交通流特征工程小技巧与思考
  12. ltm4650_LTM4650IY-1APBF_代理全新进口【linear】现货商
  13. leedcode.21合并两个有序链表
  14. matlab pinv 实现_matlab:inv,pinv逆与伪逆
  15. 考研807程序设计C语言教程,中央财经大学
  16. 什么是 “好的“ 逻辑清楚
  17. linux0.11内存memory.c一些函数的简单的注释(一)
  18. 并购狂魔Oracle到底在做什么战略布局
  19. 2020-03-05-stm32 学习--Stm32F407 SPI1 全双工DMA 收发数据
  20. 【软件推荐系列第 3 篇】如何下载、设置时钟屏保

热门文章

  1. 加密锁 vs. 云授权
  2. PHP实例——获取文件的绝对路径
  3. C++箴言:理解inline化的介入和排除
  4. 【5】CCNA课堂第一天
  5. vue中 this.$set的用法
  6. 备份MySQL数据库的方法
  7. 从宝马与京东携手,透视汽车后市场变革
  8. 以太坊智能合约简介(Solidity)
  9. SSM框架-使用MyBatis Generator自动创建代码
  10. 携手Visa IBM Watson IoT加速互联设备转化为潜在销售点