前言
结合leetcode效果更佳:
一、基本概念
1.1 树的基本概念
- 根结点:非空树处理最上层的唯一节点,其余节点都是它的子孙后代;
- 节点的度:节点具有的孩子节点个数;
- 叶子节点:度为0的节点;
- 父子节点:直接相连的一对节点,处于上层的是父节点,处于下层的是子节点
- 兄弟节点:由同一个父节点生出的不同节点互称兄弟节点;
- 节点深度:节点所在的层次数,由根开始记为1层;
- 树的深度:树的最大层次数;
- 节点高度:以节点为根的自述的深度;
- 有序(无序)树:以兄弟节点为根的子树交换位置得到的新树视作为与原理啊的树不同(相同)的树;
1.2 二叉树
每个节点度都不大于2的树。其中每个节点的子节点有左右之分且左右子节点所在的子树不可以交换位置。二叉树是一棵有序树。
满二叉树:所有叶子节点在最底层,所有非叶子节点度都是2的树。从上到校、从左到右进行编号。具有如下性质:
- 编号为i的节点:父节点编号[i/2],左子节点编号为2i,右子节点编号为2I+1;
- 记满二叉树高度为 h h h,节点总数为 n = 2 h − 1 n=2^h-1 n=2h−1,第 k k k层节点总数为 2 k − 1 2^{k-1} 2k−1;
完全二叉树:额叉树的高度为 h h h,从上到下、从左到右进行编号,如果所有节点的编号与高度为 h h h的二叉树中同样位置的节点编号一致,则改二叉树是一棵完全二叉树。具有如下性质:
- 编号大于[n/2]的节点必然是叶子节点;
- n为技术,每个非叶子节点都有两个子集诶单;n为偶数,则n/2个节点必为非叶子节点,且只有做节点没有右子节点;
二、树的基本操作
2.1 数的存储结构
顺序存储结构:父节点表示法,子节点表示法实现
链式存储结构:
# Define for singly-linked list.
class ListNode:
def __init__(self,val=0,next=None):
self.val=val
self.nex=next
# Definition for a Node.
class Node:
def __init__(self,val=None,children=None):
self.val=val
self.children=children if children is not None else []
2.2 树的增删改查
访问:程序与节点产生交互或者在节点进行某些操作;
进入:程序来到了某个节点,并未与该节点产生任何交互。对于同一个节点的“进入”次数可能有多次,但“访问”只会发生一次。多次“进入”一次“访问”。
2.3 二叉树的深度优先搜索(DFS)
深度优先搜索在“进入”借点钱有一下约定俗成的要求:
(1)必须以根节点为搜索起始节点并“进入”;
(2)优先“进入”当前节点的左子节点,其次“进入”当前节点的右子节点;
(3)如果当前节点为空节点或者左右子节点都被“进入”过,则再次”进入“父节点;
def dfs(TreeNode root):
if not root:
return
# 深度优先搜索先左再右
dfs(root.left)
dfs(root.right)
return
三种不同的访问顺序:
- 先序遍历:中左右;
- 中序遍历:左中右;
- 后序遍历:左右中。
2.4 二叉树的广度优先搜索(BFS)
从根节点开始,按层次从上到下,同层次内从左到右“访问”每一个节点也佳作层次遍历,每个节点只会“进入”一次,要实现二叉树的广度优先搜索,需要借助队列。
(1)对头结点出队并设置为当前节点;
(2)对当前节点进行访问;
(3)如果当前节点左节点存在则将左节点入队;
(4)如果当前节点右节点存在则将右节点入队;
def bfs(self,root:Optional[TreeNode]):
q=[]
q.append(root)
while len(q) and q[0]:
size=len(q) #当前层中节点的总数
for i in range(size): #控制同一层内节点级别操作
cur=q.pop()
print(cur.val)
if root.left:
q.append(root.left)
if root.right:
q.append(root.right)
return