《数据结构》学习系列——树

news2024/11/23 13:43:01

系列文章目录

目录

  • 树的基本概念
  • 树的定义
  • 树的特点
  • 树的相关术语
  • 层数
  • 高度
  • 路径
  • 二叉树
  • 定义
  • 特点
  • 定理
  • 满二叉树
  • 定义
  • 特点
  • 完全二叉树
  • 定义
  • 特点
  • 二叉树的存储结构
  • 顺序存储
  • 结点结构
  • 优点缺点 
  • 链式存储 
  • 结点结构
  • 三叉链表表示法
  • 算法
  • 搜索结点的父结点
  • 搜索符合数据域条件的结点
  • 删除给定结点及其左右子树
  •  二叉树遍历
  • 先根遍历

树的基本概念

  • 树结构在客观世界中大量存在,例如家谱、行政组织机构都可用树结构形象地表示
  • 树在计算机领域中也有着广泛的应用,例如在编译程序中,用树来表示源程序的语法结构;在数据库系统中,可用树来组织信息;在分析算法的行为时,可用树来描述其执行过程

 

树的定义

  •  (递归定义)定义:一个(或树形)就是一个有限非空的结点集合T,其中:

    • 有一个特别标出的被称为该树(或树形)之root(T)的结点

    • 其余结点 (根除外)被分成m≥0个不相交的集合T1,T2,...,Tm,且T1,T2,...,Tm又都是树(或树形)。树(或树形)T1,T2,...,Tm被称作root(T)的子树(或子树形

  • (非递归定义)定义:树是包含n(n≥1)个结点且满足如下条件的有限集合

    • 存在一个唯一的结点v0,它没有前驱结点,称为树的根(或根结点)

    • 任何非根结点都有且仅有前驱节点,称为该节点的父结点

    • 任何结点都可能有多个(≤n-1)后继结点,称之为该结点的子结点;若某结点没有后继结点,则称之为叶结点

    • 任一非根结点vk都有且仅有一条从v0到该结点序列(或路径)v0 → v1 → ...→ vk,其中vi是vi-1(1≤i≤k)的子结点

  • 其他定义:t是有一个有限元素的集合,其中一个元素为根,余下的元素(如果有的话)组成t的子树(subtree)。层次中最高层的元素为根,其下一级的元素是余下元素所构成的子树的根

例:

下图为一颗由根结点A发出的树,其中

  • A有三个子结点B、C和D(换句话说A是B、C和D的父结点)
  • B有一个子结点E
  • E有一个子结点F
  • C有两个子结点G和H;D有一个子结点I;F、G、H、I是叶子结点,因为它们没有子结点

  •  若断掉一个结点与其父结点的连接,把该结点和它的子孙们单独拿出,就是一棵以该结点为根结点的树,称之为“子树”。


树的特点

  •  树中任一结点都可以有零个或多个直接后继(即子结点),但至多只能有一个直接前驱(即父结点)
  • 树中只有根结点无前驱,它是始结点;叶结点无后继,它们是终结点
  • 树中某些结点之间具有父子关系或者祖先、子孙关系,祖先、子孙关系是对父子关系的扩展,一些结点之间,如兄弟结点(同一个父亲的诸子结点被称为兄弟结点)之间就没有这种关系

  • 有一个树根
  • 没有分枝相交
  • 树有层次

树的相关术语

  • 结点的度
    • 一个结点的子结点的数目,称为该结点的或者次数。一棵树的度为maxi=1,...,nD(i),其中n为树中结点总数,i指树中的第i个结点,D(i)表示结点i的度
  • 树的度
    • 树中各结点的最大值
  • 示例:
    • B有一个子结点E,度为1;A有三个子结点B、C和D(换言之,A是B、C和D的父结
      点),度为3,这棵树的度也为3

层数

  • 结点的层数:树形T中结点的层数递归定义如下
    • root(T)层数为0
    • 其余结点的层数为其前驱结点的层数加一

高度

  • 树的高度为maxi=1,...,nNL(i),其中n为树中结点总数,i指数中第i个结点,NL(i)之值为结点i的层数

  • 树的高度是指树中结点的最大层数

路径

  • 树形中结点间的连线被称为边。若树形T中存在结点序列vm→vm+1→...→vm+k,1≤k≤T的最大层数满足vi+1是vi;(m≤i≤m+k-1)的子结点,则称此结点序列为vm到vm+k的路径,该路径所经历的边数k被称为路度径长
  • 子孙结点、祖宗结点
    • 一棵树中若存在结点vm到vn的路径,则称vn为vm的子孙结点,vm为vn的祖宗结点
    • 一个结点到它某个子孙结点有且仅有条路径

二叉树

定义

二叉树(形)是结点的有限集合,它或者是空集,或者由一个根及两个不相交的,称为这个根的左、右子树形的二叉树组成

特点

  • 二叉树每个结点最多有两个子结点
  • 二叉树的子树有左右之分

  • 树与二叉树的主要区别
    • 二叉树每个结点最多有两个子结点,树则没有限制
    • 二叉树中结点的子树分成左子树和右子树,即使某结点只有一颗子树,也要指明该子树是左子树还是右子树,就是说二叉树是有序的
  • 含有三个结点的不同二叉树


定理

  • 二叉树中层数为i的结点至多有2^i个,i≥0
    • 证明:
      • 当i=0时,仅有一个根结点,其层数为0,因此i=0时引理成立
      • 假定当i=j(j≥0)时,引理成立,即第j层上至多有2个结点
      • 对于二叉树的任意结点,其子结点个数最大为2,故第j+1层上至多有2*
        2^j=2^(j+1)个结点,因此当i=j+1时,引理成立
      • 由数学归纳法可知,对于所有的i≥0,均有“第i层上至多有2^i个结点,证毕。

  • 高度为k(k≥0)的二叉树中至少有k+1个结点,含有k(k≥1)个结点的二叉树高度至多为k-1

例:

  •  高度为k的二叉树中至多有2^(k+1)-1(k≧0)个结点
    • 证明
      • 第0层上至多有2^0个结点
      • 第1层上至多有2^1个结点
      • 第2层上至多有2^2个结点
      • ......
      • 第k层上至多有2^k个结点
      • 因此,高度为k的二叉树中至多有2^0+2^1+...+2^k=2^(k+1)-1个结点

  • 设T是由m个结点构成的二叉树,其中度为2的结点个数为n2,度为0(叶结点)的个数为n0,则n0=n2+1
    • 证明:
      • 若度为1的结点个数为n1,总结点个数为n,则n=n0+n1+n2
      • 所有度为2结点的子结点总数的结点总数为2*n2,同理度为1结点的子结点总数为1*n1,度为0结点的子结点总数为0,则n=2*n2+n1+1(加上树的根)
      • n0+n1+n2 = 2*n2+n1+1
      • n0=n2+1

满二叉树

定义

一棵非空高度为k(k≥0)的满二叉树,是有2^(k+1)-1个结点的二叉树

特点

  • 高度为k(非空)二叉树至多有2^(k+1)-1个结点
  • 满二叉树的特点是:
    • 叶结点都在第k层上
    • 每个分支结点都有两个子结点
    • 叶结点的个数等于非叶结点个数加1
    • 除叶结点外,其他结点的度均为2

完全二叉树

定义

  • 一棵有n个结点、高为k的二叉树T,一棵高为k的满二叉树T*,用正整数按层次顺序分别编号T和T*的所有结点,如果T之所有结点恰好对应于T*的前n个结点,则称T为完全二叉树
  • 层次顺序:按从上至下,即从第0至第k层,每层由左到右的次序

特点

  • 具有n个结点高度为k的完全二叉树具有如下特点

    • 树中只有最下面两层结点的度可以小于2 
    • 树中最下面一层的结点都集中在该层最左边的若干位置上(满二叉树意义上)
    • 树中叶结点只能在层数最大的两层上出现,即存在一个非负整数k使得树中每个叶结点或在第k层或第k+1层上
    • 对树中所有结点,按层次顺序,用自然数从1开始编号,仅仅编号最大的非叶结点可以没有右孩子,其余非叶结点都有两个孩子结点
  • 若将一棵具有n个结点的完全二叉树按层次次序从1开始编号,则对编号为i(1≤i≤n)的结点有
    • 若i≠1,则编号为i的结点的父节点的编号为i/2
    • 若2i≤n,则编号为i的结点的左孩子的编号为2i,否则i无左孩子
    • 若2i+1≤n,则编号为i的结点的右孩子的编号为2i+1,否则i无右孩子
  • 仅仅编号最大的非叶结点可无右孩子,但必须有左孩子,其余非叶结点都有两个孩子结点

  • 用归纳法证明
  • 若i=1,如果n≥2,则左孩子的编号显然为2
  • 假定对所有j(1≤j≤i,2i≤n),有j的左孩子编号为2j
  • 那么对于结点i+1,证明其左孩子编号为2(i+1)
  • 如果2(i+1)≤n,则由层次次序得知,i+1的左孩子之前的两个结点就是i的左孩子和右孩子,因为i的左孩子编号为2i(归纳假设),故i的右孩子编号为2i+1,从而i+1的左孩子编号为2i+2=2(i+1)
  • 证毕

  • 具有n个结点的完全二叉树的高度是\log_2n
    • 设二叉树高度为k,由定义知,完全二叉树的结点个数介于高度为k-1和高度为k的满二叉树的结点数之间,即有:2^k-1<n≤2^(k+1)-1
    • 从而有2^k≤n<2^(k+1),即k≤log2n<k+1,因为k为整数,故有k=log2n

二叉树的存储结构

要存储一棵二叉树,需存储其所有结点的数据信息,以及其左、右孩子的地址

通常有两种存储方式:

  • 顺序存储
  • 链接存储

顺序存储

指将二叉树的所有结点按照层次顺序存放在一块地址连续的存储空间中,同时要反映二叉树中的结点间的逻辑顺序

结点结构

  • 完全二叉树顺序存储方式:按照层次顺序
    • 结点编号恰好反映了结点间的逻辑关系
  • 示例:一维数组A存储二叉树
    • A[1]存储二叉树的根结点,A[i]存储二叉树中编号为i的结点,并且结点A[i]的左孩子(若存在)存放在A[2i]处,而A[i]的右孩子(若存在)存放在A[2i+1]处

优点缺点 

  • 顺序存储的完全二叉树
    • 优点:简单、节省空间
    • 只存储结点信息域、未存储其左孩子和右孩子。通过计算可找到它的左孩子、右孩子和父节点,寻找子孙结点和祖先结点也非常方便 
  • 顺序存储存储非完全二叉树
    • 编号不能与结点一一对应
    • 解决方案:先加入若干虚结点将其转化成一棵“完全二叉树”,然后再将对原来的结点和虚结点统一编号,最后完成顺序存储。但这增加了用于存储虚结点的空间


链式存储 

二叉树各结点随机存放在内存空间中,结点之间的关系用指针标识

  • 有一个指向根节点的指针,称为根指针root,二叉树通过根指针来访问,二叉树为空,即root = NULL
  • 若某结点左孩子或右孩子不存在,则对应指针为NULL
  • 包含n个结点的二叉树用链式存储表示,需要2n个指针域,其中n-1个用来表示结点的左右孩子,其余n+1个指针域为空

结点结构

二叉树结点应包含三个域:数据域data指针域left(左指针)和指针域right(右指针),其中左、右指针分别指向该结点的左、右子树的根结点

三叉链表表示法

结点包括三个指针域,parent域中的指针指向其父结点


算法

搜索结点的父结点

#include <iostream>

using namespace std;

class Tree
{
    protected:
        int data;
        Tree *left;
        Tree *right;
    public:
        Tree(int d)  // 构造函数,创建树的节点
        {
            data = d;
            left = NULL;
            right = NULL;
        }
        Tree* Left()  // 返回左子树
        {
            return left;
        }
        Tree* Right() // 返回右子树
        {
            return right;
        }
        int Data()   // 返回节点数据
        {
            return data;
        }

        void setLeft(Tree *l) // 设置左子树
        {
            left = l;
        }

        void setRight(Tree *r) // 设置右子树
        {
            right = r;
        }
};

// Father 函数用于查找某个节点的父节点
void Father(Tree* t, Tree* p, Tree*& q)  // 通过引用传递 q
{
    if (t == NULL || t == p)
    {
        q = NULL;
        return;
    }
    if (t->Left() == p || t->Right() == p) // 找到父节点
    {
        q = t;
        return;
    }
    Father(t->Left(), p, q);  // 递归搜索左子树
    if (q == NULL)
    {
        Father(t->Right(), p, q);  // 递归搜索右子树
    }
    return; 
}

int main()
{
    // 创建树节点
    Tree *t = new Tree(1);
    t->setLeft(new Tree(2));
    t->setRight(new Tree(3));
    t->Left()->setLeft(new Tree(4));
    t->Left()->setRight(new Tree(5));
    t->Right()->setLeft(new Tree(6));
    t->Right()->setRight(new Tree(7));

    // 查找节点 t->Left()->Left()(也就是节点 4)的父节点
    Tree *p = t->Left()->Left();
    Tree *q = NULL;
    Father(t, p, q);

    // 输出父节点的数据,如果父节点存在
    if (q != NULL)
    {
        cout << q->Data() << endl;
    }
    else
    {
        cout << "NULL" << endl;
    }

    return 0;
}

搜索符合数据域条件的结点

// Find 函数用于查找某个节点
Tree* Find(Tree* t,int data,Tree*& q)  // 通过引用传递 q
{
    if(t==NULL)
    {
        q=NULL;
        return q;
    }
    if(t->Data()==data)
    {
        q=t;
        return q;
    }
    q=Find(t->Left(),data,q);
    if(q==NULL)
    {
        q=Find(t->Right(),data,q);
    }
    return q;
}

int main()
{
    // 创建树节点
    Tree *t = new Tree(1);
    t->setLeft(new Tree(2));
    t->setRight(new Tree(3));
    t->Left()->setLeft(new Tree(4));
    t->Left()->setRight(new Tree(5));
    t->Right()->setLeft(new Tree(6));
    t->Right()->setRight(new Tree(7));

    // 查找节点 t->Left()->Left()(也就是节点 4)值为4
    Tree *p = t->Left()->Left();
    Tree *q = NULL;
    q = Find(t,p->Data(),q);

    // 输出找到结点的值
    if (q != NULL)
    {
        cout << q->Data() << endl;
    }
    else
    {
        cout << "NULL" << endl;
    }

    return 0;
}

删除给定结点及其左右子树

// 递归删除给定节点及其左右子树
void Del(Tree* root)
{
    if (root == NULL)
        return;
    // 递归删除左子树和右子树
    Del(root->Left());
    Del(root->Right());

    delete root;
}



// 查找并删除树中的某个节点及其左右子树
void DeleteNode(Tree* root, Tree* target)
{
    if (target == NULL) return;
    if (target == root)
    {
        Del(root);
        root = NULL;
        return;
    }
    Tree* parent = NULL;
    // 查找目标节点的父节点
    Father(root, target, parent);
    if (parent->Left() == target) parent->setLeft(NULL);
    if (parent->Right() == target) parent->setRight(NULL);
    Del(target);
    target = NULL;
    return;
}

int main()
{
    // 创建二叉树
    Tree* t = new Tree(10);
    t->setLeft(new Tree(5));
    t->setRight(new Tree(15));
    t->Left()->setLeft(new Tree(3));
    t->Left()->setRight(new Tree(7));
    t->Right()->setLeft(new Tree(12));
    t->Right()->setRight(new Tree(18));

    // 目标节点为 t->Left()(节点 5),我们要删除它及其左右子树
    Tree* target = t->Left();
    DeleteNode(t, target);

    return 0;
}

 二叉树遍历

二叉树为空则什么都不做;否则遍历分三步进行

例子:

  •  先根遍历得到的结点序列:x+AB+x-CDEF
  • 中根遍历得到的结点序列:A+BxC-DxE+F
  • 后根遍历得到的结点序列:AB+CD-ExF+X

  • 对于给定的一棵二叉树,可给出在先根序、中根序和后根序下的唯一结点排列
  • 三种遍历序列的叶结点间的相对次序是相同的,叶结点都是按着从左到右的次序排列,区别仅在于非叶结点间的次序以及非叶结点和叶结点间的次序有所不同

先根遍历

  • 若二叉树为空,则空操作
  • 否则
    • 访问根节点
    • 先根遍历左子树
    • 先根遍历右子树

Preorder(t)

{

        if t !=NULL;

        {

                print(data(t));

                Perorder(Left(t));

                Perorder(Right(t));

        }
}

其他遍历方法即是将 print(data(t));Perorder(Left(t));Perorder(Right(t));三者顺序调换

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

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

相关文章

【Python】物流行业数据分析与可视化案例

一&#xff0c;前言 在本文中&#xff0c;我将使用python语言基于Jupyter notebook对这一份物流行业数据集进行多维度数据分析&#xff0c;文章内容参考自b站马士兵《数据分析五大经典实战项目》教学视频&#xff0c;并对其中一些操作做出优化。 数据集下载地址&#xff1a;物流…

数组与集合的应用-数组演练

1、获取一维数组最小值 1.1 实例说明 一维数组常用于保存线性数据&#xff0c;例如数据库中的单行数据就可以使用一维数组保存。本实例接收用户在文本框中输入的单行数据&#xff0c;其中数据都是整数数字&#xff0c;以不同数量的空格分割数字&#xff0c;如图1所示。这个先行…

【英语】5. 作文的高级表达

文章目录 前言一、作用二、主干内容三、使用步骤总结参考文献 前言 高中时总结的[1]&#xff0c;现在接着用 一、作用 在各种考试的作文中使用&#xff0c;减少过于直白、没有 “文采” 的表达 二、主干内容 file:///C/Users/[username]/Desktop/Engs.txt[2023/6/15 23:47:4…

一些关于PID双闭环控制的思考

最近搭建了一个LCL型滤波器的三相逆变器&#xff0c;使用了双闭环控制&#xff0c;但是查到了几种不同的控制策略&#xff0c;比如外环可以是输出电压&#xff0c;也可以是输出电流&#xff0c;内环可以是三相桥侧电感&#xff0c;也可以是电容电流&#xff0c;而不管哪种内外环…

利士策分享,旅游是否要舟车劳顿才能尽兴?

利士策分享&#xff0c;旅游是否要舟车劳顿才能尽兴&#xff1f; 国庆假期&#xff0c;当夜幕降临&#xff0c;城市灯火阑珊&#xff0c;一场关于美食与等待的较量悄然上演。 李女士在北京天坛公园附近餐厅的等位经历——前方1053桌的壮观景象&#xff0c;不仅让人咋舌&#xf…

OpenAI预计明年将推出“代理”系统

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Kubernetes系列之一快速部署一套K8s集群(kubeadm方式)

最近本人在重温云原生相关的技术&#xff0c;说到云原生&#xff0c;必然绕不开Kubernetes&#xff0c;今天想跟大家聊的就是大名顶顶的Kubernetes。相信很多朋友在学习和使用Kubernetes的过程遇到各式各样不同的问题。我将从一个初学者的角度来给大家讲解一下Kubernete从安装、…

1006每日一题

2 https://leetcode.cn/problems/maximize-the-topmost-element-after-k-moves/ 如果真的是堆的话&#xff0c;没有任何思路 如果是栈的话&#xff0c;先去找最大值所在的索引m&#xff0c;判断与k的关系 如果m>k&#xff0c;说明删k个也无法到当前的最大值或者到了也没法再…

分享7款AI学术论文生成器!一键实现论文生成器chat在线生成

在当今的学术研究和写作领域&#xff0c;AI论文写作工具的出现极大地提高了写作效率和质量。这些工具不仅能够帮助研究人员快速生成论文草稿&#xff0c;还能进行内容优化、查重和排版等操作。以下是七款值得推荐的AI学术论文生成器&#xff0c;它们通过一键生成的方式&#xf…

2024年4款PDF编辑工具分享,一起来看看

在日常的工作和生活中&#xff0c;PDF文档可以说是无处不在。它们既方便又稳定&#xff0c;但有时候&#xff0c;我们总需要对这些PDF文档进行一些修改或编辑。今天&#xff0c;我就从一个普通人的角度&#xff0c;来聊聊我用过的几款PDF编辑器在编辑PDF文档时的表现如何。 一、…

python写的window小工具-一键设置ip自动获取ip

最近有个需求,笔记本在公司上网需要设置固定ip&#xff0c;拿回家之后又要设置自动获取ip&#xff0c;有些美女同事根本就不知道怎么设置&#xff0c;所以我打算开发一个一键设置的小软件供大家使用。 但是不会c&#xff0c;也不会c#&#xff0c;更加不会vb&#xff0c;不可能…

东方仙盟——软件终端架构思维———未来之窗行业应用跨平台架构

一、创生.前世今生 在当今的数字化时代&#xff0c;我们的服务覆盖全球&#xff0c;拥有数亿客户。然而&#xff0c;这庞大的用户规模也带来了巨大的挑战。安全问题至关重要&#xff0c;任何一处的漏洞都可能引发严重的数据泄露危机。网络带宽时刻面临考验&#xff0c;稍有不足…

产品经理内容分享:产品经理必背面试题(一)

目录 1、互联网领域你最崇拜的人是谁?为什么? 2、公司会有多个产品经理&#xff0c;请问你们的分工是怎样的&#xff1f; 3、举例分析你知道的几种商业模式? 4、一份PRD文档通常应包含什么内容? 5、请你说一下产品的需求来源有哪些&#xff1f; 6、产品经理如何进行商…

【韩顺平Java笔记】第8章:面向对象编程(中级部分)【262-271】

文章目录 262. 回顾上一章内容263. IDEA介绍263.1 IDEA 介绍263.2 Eclipse 介绍 264. IDEA下载265. IDEA使用1257. IDEA使用2268. IDEA使用3268. 269. 270. IDEA快捷键1,2,3271. IDEA模板 262. 回顾上一章内容 看视频 263. IDEA介绍 263.1 IDEA 介绍 IDEA 全称 IntelliJ ID…

台湾高雄三维倾斜摄影模型3DTiles样例数据介绍

台湾一直是国内研究的重点方向&#xff0c;最主要的原因是祖国统一大业尚未完成&#xff0c;加上当前国际局势比较复杂&#xff0c;台湾及周边有众多不稳定因素&#xff0c;美国、日本等国家与台湾地区当局一直保持着紧密关系&#xff0c;成为祖国统一进程的一大阻碍。在国内众…

LSTM模型实现电力数据预测

关于深度实战社区 我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 社区特色&a…

【c语言——指针详解(4)】

文章目录 一、回调函数是什么&#xff1f;二、qsort的使⽤1、使⽤qsort函数排序整型数据2、使⽤qsort排序结构数据 三、qsort函数的模拟实现 作者主页 一、回调函数是什么&#xff1f; 回调函数就是⼀个通过函数指针调⽤的函数。 如果你把函数的指针&#xff08;地址&#xf…

旅游管理自动化:SpringBoot系统设计与实现

第二章 相关技术简介 2.1 JAVA技术 本次系统开发采用的是面向对象的Java作为软件编程语言&#xff0c;Java表面上很像C&#xff0c;但是Java仅仅是继承了C的某些优点&#xff0c;程序员很少使用的C语言的特征在Java设计中去掉了。Java编程语言并没有什么结构&#xff0c;它把数…

HLS协议

HTTP Live Streaming&#xff08;缩写是 HLS&#xff09;是一个由苹果公司提出的基于 HTTP 的流媒体网络传输协议。它的工作原理是把整个流分成一个个小的基于 HTTP 的文件来下载&#xff0c;每次只下载一些。当媒体流正在播放时&#xff0c;客户端可以选择从许多不同的备用源中…

自然语言处理:第五十一章 LangChain面经

写在前面: 笔者更新不易&#xff0c;希望走过路过点个关注和赞&#xff0c;笔芯!!! 写在前面: 笔者更新不易&#xff0c;希望走过路过点个关注和赞&#xff0c;笔芯!!! 写在前面: 笔者更新不易&#xff0c;希望走过路过点个关注和赞&#xff0c;笔芯!!! 一. 什么是 LangChain…