代码算法训练营day14 | 理论基础、递归遍历

news2025/1/10 17:12:01

day14:

  • 理论基础
    • 二叉树的分类:
    • 二叉树的种类:
      • 满二叉树
      • 完全二叉树
      • 二叉搜索树
      • 平衡二叉搜索树
    • 二叉树的存储方式:
      • 链式存储
      • 顺序存储
    • 二叉树的遍历方式:
      • 深度优先和广度优先遍历实现方式
    • 二叉树的定义:
  • 递归遍历
    • 递归三要素:
    • 举例子:
    • 前序遍历:
    • 中序遍历:
    • 后序遍历:

理论基础

二叉树的分类:

二叉树分类

二叉树的种类:

满二叉树

满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
满二叉树
这棵二叉树为满二叉树,也可以说深度为k,有2^k-1个节点的二叉树。(k从1开始)

完全二叉树

完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层(h从1开始),则该层包含 1~ 2^(h-1) 个节点。
完全二叉树
之前我们刚刚讲过优先级队列其实是一个堆,堆就是一棵完全二叉树,同时保证父子节点的顺序关系。

二叉搜索树

前面介绍的树,都没有数值的,而二叉搜索树是有数值的了,二叉搜索树是一个有序树。

若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉排序树
在这里插入图片描述

平衡二叉搜索树

平衡二叉搜索树:又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
在这里插入图片描述
最后一棵 不是平衡二叉树,因为它的左右两个子树的高度差的绝对值超过了1。

C++中map、set、multimap,multiset的底层实现都是平衡二叉搜索树,所以map、set的增删操作时间时间复杂度是logn,注意我这里没有说unordered_map、unordered_set,unordered_map、unordered_set底层实现是哈希表。

二叉树的存储方式:

二叉树可以链式存储,也可以顺序存储。
那么链式存储方式就用指针, 顺序存储的方式就是用数组。
顾名思义就是顺序存储的元素在内存是连续分布的,而链式存储则是通过指针把分布在各个地址的节点串联一起。

链式存储

在这里插入图片描述

顺序存储

在这里插入图片描述
如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。
但是用链式表示的二叉树,更有利于我们理解,所以一般我们都是用链式存储二叉树。

所以大家要了解,用数组依然可以表示二叉树。

二叉树的遍历方式:

二叉树主要有两种遍历方式:

  1. 深度优先遍历:先往深走,遇到叶子节点再往回走。
  2. 广度优先遍历:一层一层的去遍历。

这两种遍历是图论中最基本的两种遍历方式。
深度优先遍历
3. 前序遍历(递归法,迭代法)
4. 中序遍历(递归法,迭代法)
5. 后序遍历(递归法,迭代法)
广度优先遍历
6. 层次遍历(迭代法)

这里前中后序,其实指的就是中间节点的遍历顺序,只要大家记住 前中后序指的就是中间节点的位置就可以了。
看如下中间节点的顺序,就可以发现,中间节点的顺序就是所谓的遍历方式:

  • 前序遍历:中左右
  • 中序遍历:左中右
  • 后序遍历:左右中
    在这里插入图片描述

深度优先和广度优先遍历实现方式

我们做二叉树相关题目,经常会使用递归的方式来实现深度优先遍历,也就是实现前中后序遍历,使用递归是比较方便的。
之前我们讲栈与队列的时候,就说过栈其实就是递归的一种实现结构,也就说前中后序遍历的逻辑其实都是可以借助栈使用递归的方式来实现的。
而广度优先遍历的实现一般使用队列来实现,这也是队列先进先出的特点所决定的,因为需要先进先出的结构,才能一层一层的来遍历二叉树。

二叉树的定义:

我们来看看链式存储的二叉树节点的定义方式:

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

大家会发现二叉树的定义 和链表是差不多的,相对于链表 ,二叉树的节点里多了一个指针, 有两个指针,指向左右孩子。
TreeNode(int x) : val(x), left(NULL), right(NULL) {}的意思是创建一个新的TreeNode对象,其值为x,并且它的左右子节点都被初始化为NULL。


递归遍历

递归三要素:

介绍前后中序的递归写法,要通过简单题目把方法论确定下来,有了方法论,后面才能应付复杂的递归。
这里确定下来递归算法的三个要素。每次写递归,都按照这三要素来写:

  1. 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
  2. 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
  3. 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。

举例子:

以前序遍历为例:(中左右)
4. 确定递归函数的参数和返回值: 因为要打印出前序遍历节点的数值,所以参数里需要传入vector数组来放节点的数值,还要再放一个根节点,除此之外就不需要再处理什么数据了也不需要有返回值,所以递归函数返回类型就是void,代码如下:

void traversal(TreeNode* cur, vector<int>& vec)
  1. 确定终止条件: 在递归的过程中,如何算是递归结束了呢,当然是当前遍历的节点是空了,那么本层递归就要结束了,所以如果当前遍历的这个节点是空,就直接return,返回到上一层的递归中,代码如下:
if (cur == NULL) return;

确定单层递归的逻辑: 前序遍历是中左右的循序,所以在单层递归的逻辑,是要先取中节点的数值,再取左节点的数值,最后取右节点的数值。代码如下:

vec.push_back(cur->val);    // 中
traversal(cur->left, vec);  // 左
traversal(cur->right, vec); // 右

单层递归的逻辑就是按照中左右的顺序来处理的,这样二叉树的前序遍历,基本就写完了。

前序遍历:

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;
    }
};

中序遍历:

void traversal(TreeNode* cur, vector<int>& vec) {
    if (cur == NULL) return;
    traversal(cur->left, vec);  // 左
    vec.push_back(cur->val);    // 中
    traversal(cur->right, vec); // 右
}

后序遍历:

void traversal(TreeNode* cur, vector<int>& vec) {
    if (cur == NULL) return;
    traversal(cur->left, vec);  // 左
    traversal(cur->right, vec); // 右
    vec.push_back(cur->val);    // 中
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1580439.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【攻防世界】web2(逆向解密)

进入题目环境&#xff0c;查看页面信息&#xff1a; <?php $miwen"a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";function encode($str){$_ostrrev($str);// echo $_o;for($_00;$_0<strlen($_o);$_0){$_csubstr($_o,$_0,1);$__ord($_c)1;…

磁盘管理与文件管理

文章目录 一、磁盘结构二、MBR与磁盘分区分区的优势与缺点分区的方式文件系统分区工具挂载与解挂载 一、磁盘结构 1.硬盘结构 硬盘分类&#xff1a; 1.机械硬盘&#xff1a;靠磁头转动找数据 慢 便宜 2.固态硬盘&#xff1a;靠芯片去找数据 快 贵 硬盘的数据结构&#xff1a;…

重温OKHTTP源码

本文基于OkHttp4.12.0源码分析 官方地址 概括 本篇主要是对okhttp开源库的一个详细解析&#xff0c;包含详细的请求流程分析、各大拦截器的解读等。 使用方法 同步请求&#xff1a;创建一个OKHttpClient对象&#xff0c;一个Request对象&#xff0c;然后利用它们创建一个Ca…

动态代理

动态代理 动态代理和静态代理角色一致。 代理类是动态生成的&#xff0c;不是我们直接写好的。 动态代理分为俩大类&#xff1a;基于接口的动态代理、基于类的动态代理 基于接口&#xff1a;JDK动态代理&#xff08;以下示例就是这个&#xff09; 基于类&#xff1a;cglib jav…

微机原理——绪论

本篇文章是我在观看网课时记录的笔记。如有错误欢迎批评指正。 微机原理————绪论 我们在使用计算机时&#xff0c;最重要最核心的就是计算机的CPU(中央处理器)&#xff0c;决定了计算机的计算速度&#xff0c;但是CPU无法直接读取外界的温度、湿度、压力之类的物理量&…

MSTP/RSTP的保护功能

目录 原理概述 实验目的 实验内容 实验拓扑 1.配置RSTP/MSTP 2.配置BPDU保护 3.配置根保护 4.配置环路保护 5.配置TC-BPDU保护 原理概述 在RSTP或MSTP交换网络中&#xff0c;为了防止恶意攻击或临时环路的产生&#xff0c;可配置保护功能来增强网络的健壮性和安全性。…

VSCode配置AI自动补全插件Tabnine

面向软件开发人员的 AI 助手 使用 AI 代码完成更快地编写代码 什么是Tabnine Tabnine 是一款 AI 代码助手&#xff0c;可让您成为更好的开发人员。Tabnine 将通过所有最流行的编码语言和 IDE 的实时代码完成、聊天和代码生成来提高您的开发速度。 无论您将其称为 IntelliSens…

【网络捉鬼记】微信可以部分网页可以,其它网页打不开提示无法找到NDS地址

蹭网蹭得好好的&#xff0c;为啥突然这样呢&#xff1f; 发现微信可以&#xff0c;百度搜索网页可以打开但图片出不来&#xff0c;再点一个新闻进去又是上图的样子。 问AI&#xff01;却发现连质谱清言也打不开&#xff01;用自己热点问&#xff1a; 至于win10怎么更换DNS&…

免费幻兽帕鲁游戏云服务器领取及搭建教程

幻兽帕鲁是一款多人在线游戏&#xff0c;为了获得更好的游戏体验&#xff0c;许多玩家会选择自行搭建游戏联机服务器&#xff0c;但是游戏云服务器一般配置较高&#xff0c;价格自然也比较高&#xff0c;本文将为大家分享免费幻兽帕鲁游戏云服务器领取及搭建教程。 雨云是一家国…

16.事件标志组

一、简介 事件标志组与信号量一样属于任务间同步的机制&#xff0c;但是信号量一般用于任务间的单事件同 步&#xff0c;对于任务间的多事件同步&#xff0c;仅使用信号量就显得力不从心了。FreeRTOS 提供的事件标志组 可以很好的处理多事件情况下的任务同步。 1. 事件标志 …

C语言文件操作2

1.二进制读写函数 在上一章我们介绍了字符读写函数、文本读写函数和格式化输入输出函数&#xff0c;这张我们继续为大家介绍剩下的一组读写函数——二进制读写函数&#xff1a;fread函数和fwrite函数。 ⚀fread函数 &#x1f7e1;函数作用 以二进制的方式从指定流中读取数据 …

Nuxt3 实战 (三):使用 release-it 自动管理版本号和生成 CHANGELOG

release-it 能做什么&#xff1f; 增加版本号并提交 Git生成变更日志&#xff08;Changelog&#xff09;并提交到 Git创建 Git 标签并推送到远程仓库发布到 npm 等软件仓库在 GitHub、GitLab 等平台创建发行版 前置知识 在看这篇文章之前&#xff0c;我们有必要了解一下 Sem…

Java 那些诗一般的 数据类型 (下篇)

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人能接…

SpringBoot整合RabbitMQ-应答模式

一、应答模式 RabbitMQ 中的消息应答模式主要包括两种&#xff1a;自动应答&#xff08;Automatic Acknowledgement&#xff09;和手动应答&#xff08;Manual Acknowledgement&#xff09;。&#xff08;一般交换机发送消息&#xff0c;RabbitMQ只有在接收到消费者的确认后才…

【鸿蒙开发】ArkTS和组件

1. 初识ArkTS语言 ArkTS是HarmonyOS优选的主力应用开发语言。ArkTS围绕应用开发在TypeScript生态基础上做了进一步扩展&#xff0c;继承了TS的所有特性。 当前&#xff0c;ArkTS在TS的基础上主要扩展了如下能力&#xff1a; 基本语法&#xff1a;ArkTS定义了声明式UI描述、自…

终端进程“CWindowsSystem32WindowsPowerShellv1.0powershell.exe”已终止,退出代码 2。

终端进程“C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe”已终止&#xff0c;退出代码: 2。 今天安装了最新版的VScode&#xff0c;果然&#xff0c;出毛病了 在我每次运行终端运行vue3项目时&#xff0c;只要主动CtrlC退出&#xff0c;终端就会闪退&#xff…

2024洗地机哪个牌子好?六大避坑攻略总结

洗地机就像是吸尘器和电动拖把的结合体&#xff0c;对于每天要做家务的人来说&#xff0c;可以一次性解决多种类型的垃圾&#xff0c;省时省心省力。但是面对种类繁重的洗地机市场&#xff0c;大家时常会无从下手&#xff0c;今天笔者就给大家总结了六大洗地机避坑指南。 洗地…

购买了Hostease的企业邮箱服务后如何启用

最近有遇到客户购买了Hostease的企业邮箱后不知道该如何去启用的问题&#xff0c;这里我们简单分享一下Hostease的企业邮箱购买到使用的操作。 Hostease提供了两种邮箱服务套餐选择&#xff0c;OX App Suite和OX App Suite Productivity&#xff0c;OX App Suite Productivi…

Agent——客服机器人(大模型+本地数据/话术+在线数据库)

我们先来介绍一下&#xff0c;这个客服机器人的特点&#xff0c;根据本地资料&#xff0c;回答用户问题&#xff0c;告别传统机器人的答非所问&#xff0c;同时根据用户回答&#xff0c;判断用户意向度&#xff0c;并询问感兴趣用户的个人信息&#xff0c;获得后&#xff0c;保…

【面试题】如何在级别用户中检查用户名是否存在?

前言 不知道大家有没有留意过&#xff0c;在使用一些app或者网站注册的时候&#xff0c;提示你用户名已经被占用了&#xff0c;比如我们熟知的《英雄联盟》有些人不知道取啥名字&#xff0c;干脆就叫“不知道取啥名”。 但是有这样困惑的可不止他一个&#xff0c;于是就出现了…