当前位置: 首页 > news >正文

[C/C++] -- 二叉树

1.简介

二叉树是一种每个节点最多有两个子节点的树结构,通常包括:根节点、左子树、右子树。

  • 满二叉树:

如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。深度为k,有2^k - 1个节点。

  • 完全二叉树

除了最底层节点可能没填满外,其余每层节点数都达到最大值,且最下面一层节点都集中在该层最左边若干位置。若最底层为k层,则该层包含1~2^(k-1)个节点。

优先级队列其实是一个堆,堆就是一棵完全二叉树,同时保证父子节点的顺序关系。

  • 二叉搜索树

二叉搜索树有数值,是一个有序树。

若左子树不空,则左子树上所有节点值均小于根节点值。

若右子树不空,则右子树上所有节点值均大于根节点值。

左右子树分别为二叉搜索树

  • 平衡二叉搜索树

任意节点的左子树和右子树高度差不超过1,空树仅有一个节点,也是一种平衡二叉搜索树

C++种map、set、multimap、multiset的底层实现是平衡二叉搜索树(红黑树),所以增删时间复杂度O(logn),unordered_map、unordered_set底层实现是哈希表,理想情况具有O(1)的增删时间复杂度,最坏情况O(n)。

  • 二叉树存储方式

链式存储(指针)、顺序存储(数组)

二叉树定义:

#include <iostream>// 定义二叉树节点结构
struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};int main() {// 创建二叉树节点TreeNode* root = new TreeNode(1);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->left = new TreeNode(4);root->left->right = new TreeNode(5);// 访问二叉树节点的数值std::cout << "The value of the root node is: " << root->val << std::endl;std::cout << "The value of the left child of the root is: " << root->left->val << std::endl;// 释放二叉树节点的内存delete root->left->left;delete root->left->right;delete root->left;delete root->right;delete root;return 0;
}

2.二叉树遍历

常用于图论:

深度优先遍历:先往深走、遇到叶子节点再往回走。(前序、中序、后续遍历:递归法、迭代法)

广度优先遍历:一层一层的去遍历。(层次遍历:迭代法)

前中后指的是中间节点遍历顺序

前序:中左右          5 4 1 2 6 7 8

中序:左中右          1 4 2 5 7 6 8

后序:左右中          1 2 4 7 8 6 5

递归法: 

 前序遍历:

class Solution {public:void traversal(TreeNode* cur, vector<int>& vec) {if (cur == NULL) return;vec.push_back(cur->val);traversal(cur->left,vec);        traversal(cur->right,vec);}vector<int> preorderTraversal(TreeNode* root) {vector<int> result;traversal(root, result);return result;}
};

中序遍历:

class Solution {public:void traversal(TreeNode* cur, vector<int>& vec) {if (cur == NULL) return;traversal(cur->left,vec);vec.push_back(cur->val);        traversal(cur->right,vec);}vector<int> preorderTraversal(TreeNode* root) {vector<int> result;traversal(root, result);return result;}
};

后序遍历:

class Solution {public:void traversal(TreeNode* cur, vector<int>& vec) {if (cur == NULL) return;traversal(cur->left,vec);        traversal(cur->right,vec);vec.push_back(cur->val);}vector<int> preorderTraversal(TreeNode* root) {vector<int> result;traversal(root, result);return result;}
};

迭代法:

前序遍历

class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {stack<TreeNode*> st;vector<int> result;st.push(root);while (!st.empty()){TreeNode* node = st.top();st.pop();result.push_back(node->val);if (node->right) st.push(node->right);if (node->left) st.push(node->left);}return result;}
};

中序遍历

class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {stack<TreeNode*> st;vector<int> result;TreeNode* cur = root;while (cur != NULL || !st.empty()){if (cur != NULL){st.push(cur);cur = cur->left;}else{cur = st.top();st.pop();result.push_back(cur->val);cur = cur->right;}}return result;}
};

后序遍历

class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {stack<TreeNode*> st;vector<int> result;if (root == NULL) return result;st.push(root);while (!st.empty()){TreeNode* node = st.top();st.pop();result.push_back(node->val);if (node->left) st.push(node->left);if (node->right) st.push(node->right);}reverse(result.begin(),result. End());return result;}
};

3.例题

示例 1:

输入:root = [1,7,0,7,-8,null,null]
输出:2
解释:
第 1 层各元素之和为 1,
第 2 层各元素之和为 7 + 0 = 7,
第 3 层各元素之和为 7 + -8 = -1,
所以我们返回第 2 层的层号,它的层内元素之和最大。

示例 2:

输入:root = [989,null,10250,98693,-89388,null,null,null,-32127]
输出:2
  • 深度优先搜索 

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {vector<int> sum;void dfs(TreeNode* node,int level){if(sum.size() == level){sum.push_back(node->val);}else{sum[level]+=node->val;}if(node->left){dfs(node->left,level+1);}if(node->right){dfs(node->right,level+1);}}public:int maxLevelSum(TreeNode* root) {dfs(root,0);int ans = 0;for(int i = 0;i<sum.size();i++){if(sum[i]>sum[ans]){ans = i;}}return ans+1;}
};
  • 广度优先搜索
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:int maxLevelSum(TreeNode* root) {int ans = 1,maxSum = root->val;vector<TreeNode*q> = {root};for(int level = 1;!q.empty();++level){vector<TreeNode*> nq;int sum = 0;for (auto node:q) {sum +=node->val;if (node->left){//用于在容器尾部直接构造一个新元素,可以避免额外的拷贝或移动操作。nq.emplace_back(node->left);}if(node->right){nq.emplace_back(node->right);}}if (sum > maxSum) {maxSum = sum;ans = level;}//通过 move(nq),我们将 nq 的所有权(ownership)转移给 q。//这意味着实际上并不会进行元素的复制,而是直接将 nq 中的元素转移到 q 中,同时 nq 被置为空。q = move(nq);}return ans;}
};

相关文章:

  • VUE 视图不刷新解决方法
  • kvm虚拟机迁移--来自gpt
  • docker 部署 nali 开源 IP 地理信息归属查询软件
  • 【教程】Kotlin语言学习笔记(五)——Lambda表达式与条件控制
  • 是谁?写的Java神作一出版就获Jolt图书大奖【抽奖赠书】
  • java数组与集合框架(一) -- 数据结构,数组
  • 15.Python访问数据库
  • Springboot整合Milvus向量库
  • hcip-datacom英文词汇积累简述1
  • Python PyQt5——QPainter 绘图用法与代码示例
  • 【Web】NSSCTF Round#20 Basic 两道0解题的赛后谈
  • 39.基于SpringBoot + Vue实现的前后端分离-无人智慧超市管理系统(项目 + 论文PPT)
  • CSS 实现伸缩导航仪表板侧边栏菜单
  • PHP教程_如何向PHP5中的数组(Array)插入元素
  • 前端跨页面通信方案介绍
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • 【跃迁之路】【444天】程序员高效学习方法论探索系列(实验阶段201-2018.04.25)...
  • Android优雅地处理按钮重复点击
  • C# 免费离线人脸识别 2.0 Demo
  • Iterator 和 for...of 循环
  • Java 最常见的 200+ 面试题:面试必备
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • JavaScript异步流程控制的前世今生
  • learning koa2.x
  • Python socket服务器端、客户端传送信息
  • 成为一名优秀的Developer的书单
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 力扣(LeetCode)965
  • 前端相关框架总和
  • 什么是Javascript函数节流?
  • 听说你叫Java(二)–Servlet请求
  • 一份游戏开发学习路线
  • ​io --- 处理流的核心工具​
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • (C#)获取字符编码的类
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (pojstep1.1.2)2654(直叙式模拟)
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (排序详解之 堆排序)
  • .NET Core日志内容详解,详解不同日志级别的区别和有关日志记录的实用工具和第三方库详解与示例
  • .NET 中创建支持集合初始化器的类型
  • .Net6支持的操作系统版本(.net8已来,你还在用.netframework4.5吗)
  • .NET简谈设计模式之(单件模式)
  • .sh文件怎么运行_创建优化的Go镜像文件以及踩过的坑
  • :“Failed to access IIS metabase”解决方法
  • @autowired注解作用_Spring Boot进阶教程——注解大全(建议收藏!)
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • @TableLogic注解说明,以及对增删改查的影响
  • [ solr入门 ] - 利用solrJ进行检索
  • [20171101]rman to destination.txt
  • [20171113]修改表结构删除列相关问题4.txt
  • [AIGC] 如何建立和优化你的工作流?
  • [C++]:for循环for(int num : nums)