二叉树的存储方式和遍历方式详解
创作时间:
作者:
@小白创作中心
二叉树的存储方式和遍历方式详解
引用
CSDN
1.
https://blog.csdn.net/qq_51352130/article/details/143312785
二叉树是数据结构中一种重要的树形结构,其存储和遍历方式是算法学习中的基础内容。本文将详细介绍二叉树的两种存储方式(链式存储和顺序存储)以及三种主要的遍历方式(深度优先搜索DFS和广度优先搜索BFS)。通过具体的代码示例,帮助读者深入理解二叉树的存储和遍历方法。
二叉树的存储方式
二叉树的存储方式主要有两种:链式存储和顺序存储。
链式存储
链式存储通过指针将分布在各个地址的节点串联起来。每个节点包含数据域和两个指针域,分别指向其左右子节点。
链式存储的二叉树节点定义方式如下:
public class TreeNode {
int val;
TreeNode left; //表示左子节点的引用,类型为TreeNode
TreeNode right;
TreeNode() {}
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
顺序存储
顺序存储是将二叉树的节点按照某种顺序存储在数组中。如果父节点的数组下标是 i
,那么它的左孩子就是 2i + 1
,右孩子是 2i + 2
,孩子的父节点为 (i-1)/2
。
二叉树的遍历方式
二叉树的遍历方式主要有两种:深度优先搜索(DFS)和广度优先搜索(BFS)。
深度优先搜索(DFS)
深度优先搜索可以分为前序遍历、中序遍历和后序遍历。每种遍历方式都可以通过递归和迭代两种方法实现。
DFS-递归遍历
前序遍历
前序遍历的顺序是:根节点 -> 左子树 -> 右子树。
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<Integer>();
preorder(root, result);
return result;
}
public void preorder(TreeNode root, List<Integer> result) {
if (root == null) {
return;
}
result.add(root.val);
preorder(root.left, result);
preorder(root.right, result);
}
}
中序遍历
中序遍历的顺序是:左子树 -> 根节点 -> 右子树。
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
inorder(root, res);
return res;
}
void inorder(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
inorder(root.left, list);
list.add(root.val);
inorder(root.right, list);
}
}
后序遍历
后序遍历的顺序是:左子树 -> 右子树 -> 根节点。
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
postorder(root, res);
return res;
}
void postorder(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
postorder(root.left, list);
postorder(root.right, list);
list.add(root.val);
}
}
DFS-迭代遍历
迭代遍历通常使用栈来辅助实现。
前序遍历
前序遍历的顺序是:中-左-右,入栈顺序是:中-右-左。
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
result.add(node.val);
if (node.right != null){
stack.push(node.right);
}
if (node.left != null){
stack.push(node.left);
}
}
return result;
}
}
中序遍历
中序遍历的顺序是:左-中-右,入栈顺序是:左-右。
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(cur != null || !stack.isEmpty()){
if(cur != null){
stack.push(cur);
cur = cur.left;
}
else{
cur = stack.pop();
result.add(cur.val);
cur = cur.right;
}
}
return result;
}
}
后序遍历
后序遍历的顺序是:左-右-中,可以通过先实现前序遍历(中-右-左),然后反转结果集来实现。
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
result.add(node.val);
if (node.left != null){
stack.push(node.left);
}
if (node.right != null){
stack.push(node.right);
}
}
Collections.reverse(result);
return result;
}
}
广度优先搜索(BFS)
广度优先搜索通常用于层次遍历,即按层访问二叉树的节点。
BFS-层次遍历
层次遍历可以使用队列来辅助实现。
迭代方式
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> resList = new ArrayList<>();
if (root == null) {
return resList;
}
Queue<TreeNode> que = new LinkedList<>();
que.offer(root);
while(!que.isEmpty()){
List<Integer> itemList = new ArrayList<>();
int levelSize = que.size();
for (int i = 0; i < levelSize; i++) {
TreeNode tmpNode = que.poll();
itemList.add(tmpNode.val);
if(tmpNode.left != null){
que.offer(tmpNode.left);
}
if(tmpNode.right != null){
que.offer(tmpNode.right);
}
}
resList.add(itemList);
}
return resList;
}
}
递归方式
class Solution {
List<List<Integer>> resList = new ArrayList<>();
public List<List<Integer>> levelOrder(TreeNode root) {
checkFun01(root, 0);
return resList;
}
public void checkFun01(TreeNode node, int deep) {
if (node == null) {
return;
}
deep++;
if (resList.size() < deep) {
resList.add(new ArrayList<Integer>());
}
resList.get(deep - 1).add(node.val);
checkFun01(node.left, deep);
checkFun01(node.right, deep);
}
}
对于自底向上的层次遍历,可以在最后将结果集翻转:Collections.reverse(resList);
热门推荐
红糖姜枣茶的功效与作用与禁忌
大学绩点有什么用?对毕业有影响吗?
如何评估黄金的重量单位及其价值?不同重量单位的黄金价值如何换算?
如何选择适合的高端住宅?高端住宅的标准是什么?
校园霸凌的可怕真相:多数孩子不敢告诉父母,6大信号常被忽视!
盘点名著里的疯狂爱情:从《呼啸山庄》到《霍乱时期的爱情》
镝灯(HMI)在影视创作、工业照明领域应用广泛 我国供应能力不断增强
全球热榜第一的《鱿鱼游戏2》,为何跌落神坛?
上海楼市高热度背后:买家加速入场 一二手房走出独立行情
口腔溃疡可以按揉什么穴位
小宝爱抠脚?难道是天生的?
心脏超声-EF-计算公式及评估方法
汽车兵的"飞驰人生"!
疼痛拜拜:牙髓炎属于几级疼痛?4-7级疼痛!可服用药物/冰敷等减轻疼痛!
认识国防动员的基本内涵
焊接知识——“屈服强度”详解
全球金融科技中心TOP5城市差距缩小,人工智能等金融科技B端应用成为“新胜负手”
揭秘主板BIOS:功能详解与故障解决指南
福建南平:解锁稻烟协同的生态密码
科学家用全身分子图谱显示为什么运动对你的健康有益
“抱歉鲁迅先生,这真不是人为的”,北方校园雕塑被“大雪”玩坏
狗狗可以吃鹰嘴豆吗?营养与风险全解析
岁月传承谱写运河文化新章!《北上》今晚CCTV-1黄金档开播
评今年的金棕榈电影《阿诺拉》
印度"硅谷"班加罗尔面临缺水危机,科技企业另觅他处
欧洲古典柱式:多立克、爱奥尼、科林斯、塔司干、复合柱式
深蹲跳的好处(深蹲瘦腿还是粗腿)
汇率决定理论解析:影响汇率变动的关键因素
央企红利、国企红利、民企红利三只红利指数的简单对比分析
智齿疼和牙龈疼有什么区别?怎么判断智齿疼还是牙龈疼?