Delphi程序和AI大模型交互

使用 Delphi 写AI大模型的 Agent

简单的概念解释

所谓的 Agent 是执行在我自己本地电脑上的一个程序。这个程序可以让大模型来调用,在本地电脑上执行一些代码,然后把代码执行结果给大模型,并且大模型还能够理解代码的执行结果。

如何实现的思考

AI 大模型的输入和输出都是字符串。在聊天方式下,人脑当然可以阅读理解AI输出的内容。如果我们使用 Delphi 来写程序,如何知道 AI 想要调用哪个函数?如何让 Delphi 程序去执行这个函数?

Delphi 内置的 WebService 框架

WebService 的底层是 SOAP 调用,而 SOAP 调用的底层通讯是 XML 字符串!

尝试

首先,用 Delphi 创建一个 WebService 服务器端程序用于测试。

构造一个 WebService 服务器端程序

我使用 Delphi 创建了一个 WebService 服务器端程序,它输出给客户端调用的接口定义代码:

type TMyArrayInt = Array Of Integer; { Invokable interfaces must derive from IInvokable } IIMyTest = interface(IInvokable) ['{10981E31-3C5C-4611-BB68-5964025D690F}'] { Methods of Invokable interface must not use the default } { calling convention; stdcall is recommended } function Hello(const S: string): string; stdcall; procedure HelloWord(const S: string; var MyResult: string); stdcall; function TestArray(A: TIntegerSOAPArray ): TIntegerSOAPArray ; stdcall; function XPlusY(const X, Y: Integer): Integer; stdcall; end; 

这里,我们聚焦到 function XPlusY(const X, Y: Integer): Integer; stdcall; 上,它的实现代码是:

function TIMyTest.XPlusY(const X, Y: Integer): Integer; begin Result := X + Y; end; 

WebService 验证客户端

同样,使用 Delphi 创建一个标准的 WebService 客户端程序,去调用服务器的 XPlusY 函数,代码如下:

procedure TFmMain.Button3Click(Sender: TObject); var Intf: IIMyTest; X, Y, Z: Integer; begin Intf := HTTPRIO1 as IIMyTest; X := 10; Y := 33; Z := Intf.XPlusY(X, Y); ShowMessage(Z.ToString); end; 

运行服务器端程序和客户端程序,客户端程序上的 Button3 我点它一下,确实收到服务器端的返回,弹出消息框显示43,成功。

获得 Delphi 的 WebService 客户端程序向服务器发起函数调用的通讯内容

因为客户端是使用 HTTPRIO1 这个控件去调用服务器端,因此,我们在 HTTPRIO1.OnBeforeExecute 事件里面写代码拦截,代码如下:

procedure TFmMain.HTTPRIO1BeforeExecute(const MethodName: string; SOAPRequest: TStream); var S: TStringStream; SS: string; begin S := TStringStream.Create; try SoapRequest.Position := 0; S.CopyFrom(SoapRequest); S.Position := 0; SS := S.ReadString(S.Size); Log(SS); finally S.Free; end; end; 

上述代码中,Log 方法的代码如下:

procedure TFmMain.Log(const S: string); begin TThread.Synchronize(nil, procedure begin Memo1.Lines.Add(S); end ); end; 

也就是说,把 HTTPRIO1 向服务器发送的函数调用的请求内容,写到 Memo1 里面,让我可以看见。
接下来再次使用这个客户端程序,执行一次对服务器端 XPlusY 函数的调用,HTTPRIO1 发送的内容如下:

<?xml version="1.0"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body xmlns:NS1="urn:IMyTestIntf-IIMyTest" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><NS1:XPlusY><X xsi:type="xsd:int">10</X><Y xsi:type="xsd:int">33</Y></NS1:XPlusY></SOAP-ENV:Body></SOAP-ENV:Envelope> 

使用 HTTP Post 直接发送这个 XML 的内容给服务器

创建一个新的 Delphi 程序,在里面放三个控件:

  • Button1;
  • Memo1;
  • IdHTTP1
    IdHTTP1 用于向服务器发起 http 访问。对于 SOAP 来说,这里应该发起 http 的 Post 而不是 http 的 Get

把上面我们从 WebService 客户端程序抓到的 XML 保存为文件,文件名:XML_1.txt,然后使用 IdHTTP1 把它 Post 给 WebService 服务器端,代码如下:

procedure TFmMain.Button1Click(Sender: TObject); var S, URL: string; begin Memo1.Lines.Clear; URL := 'http://localhost:8080/soap/IIMyTest'; S := IdHTTP1.Post(URL,'XML_2.txt'); //成功 Memo1.Lines.Add(S); end; 

运行这个程序,点击 Button1,能够从 Memo1 上看到来自 WebService 服务器的返回。返回数据是:

<?xml version="1.0"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:NS1="urn:IMyTestIntf-IIMyTest"><NS1:XPlusYResponse><return xsi:type="xsd:int">43</return></NS1:XPlusYResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> 

上面这段 XML 表明,服务器正确执行了 XPlusY 函数,返回了 43 这个正确的结果。

AI 怎么玩?

这里作为测试,我使用了 DeepSeek 的网页版本。我通过聊天的方式,告诉 DeepSeek:

你是一个能够理解 SOAP 调用的专家,我给你一个 SOAP 服务器的调用规范,你能够理解并创建客户端调用这个 SOAP 服务器的 XML 代码吗? 

AI 回答:

当然可以!我是理解 SOAP 协议和 XML 结构的专家,您只需提供 SOAP 服务的调用规范(例如 WSDL 地址、操作名称、命名空间、请求参数等),我就能为您生成对应的客户端调用 XML 代码。请提供详细信息,我会尽力帮您构建正确的 SOAP 请求。 

然后我把服务器的 WSDL 在聊天页面里面发送给 AI,WSDL 如下:

# 理解并调用 WebService ## 以下是指定的 WebService 服务器端能够提供的服务的 WSDL: <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:ns1="http://www.borland.com/namespaces/Types" name="IIMyTestservice" targetNamespace="http://tempuri.org/"> <types> <xs:schema xmlns="http://www.borland.com/namespaces/Types" targetNamespace="http://www.borland.com/namespaces/Types"> <xs:complexType name="TIntegerSOAPArray"> <xs:complexContent> <xs:restriction base="soapenc:Array"> <sequence xmlns="http://www.w3.org/2001/XMLSchema"/> <xs:attribute xmlns:n1="http://schemas.xmlsoap.org/wsdl/" ref="soapenc:arrayType" n1:arrayType="xs:int[]"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:schema> </types> <message name="Hello0Request"> <part name="S" type="xs:string"/> </message> <message name="Hello0Response"> <part name="return" type="xs:string"/> </message> <message name="HelloWord1Request"> <part name="S" type="xs:string"/> <part name="MyResult" type="xs:string"/> </message> <message name="HelloWord1Response"> <part name="MyResult" type="xs:string"/> </message> <message name="TestArray2Request"> <part name="A" type="ns1:TIntegerSOAPArray"/> </message> <message name="TestArray2Response"> <part name="return" type="ns1:TIntegerSOAPArray"/> </message> <message name="XPlusY3Request"> <part name="X" type="xs:int"/> <part name="Y" type="xs:int"/> </message> <message name="XPlusY3Response"> <part name="return" type="xs:int"/> </message> <portType name="IIMyTest"> <operation name="Hello"> <input message="tns:Hello0Request"/> <output message="tns:Hello0Response"/> </operation> <operation name="HelloWord"> <input message="tns:HelloWord1Request"/> <output message="tns:HelloWord1Response"/> </operation> <operation name="TestArray"> <input message="tns:TestArray2Request"/> <output message="tns:TestArray2Response"/> </operation> <operation name="XPlusY"> <input message="tns:XPlusY3Request"/> <output message="tns:XPlusY3Response"/> </operation> </portType> <binding name="IIMyTestbinding" type="tns:IIMyTest"> <binding xmlns="http://schemas.xmlsoap.org/wsdl/soap/" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="Hello"> <operation xmlns="http://schemas.xmlsoap.org/wsdl/soap/" soapAction="urn:IMyTestIntf-IIMyTest#Hello"/> <input> <body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/> </input> <output> <body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/> </output> </operation> <operation name="HelloWord"> <operation xmlns="http://schemas.xmlsoap.org/wsdl/soap/" soapAction="urn:IMyTestIntf-IIMyTest#HelloWord"/> <input> <body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/> </input> <output> <body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/> </output> </operation> <operation name="TestArray"> <operation xmlns="http://schemas.xmlsoap.org/wsdl/soap/" soapAction="urn:IMyTestIntf-IIMyTest#TestArray"/> <input> <body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/> </input> <output> <body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/> </output> </operation> <operation name="XPlusY"> <operation xmlns="http://schemas.xmlsoap.org/wsdl/soap/" soapAction="urn:IMyTestIntf-IIMyTest#XPlusY"/> <input> <body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/> </input> <output> <body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/> </output> </operation> </binding> <service name="IIMyTestservice"> <port name="IIMyTestPort" binding="tns:IIMyTestbinding"> <address xmlns="http://schemas.xmlsoap.org/wsdl/soap/" location="http://localhost:8080/soap/IIMyTest"/> </port> </service> </definitions> 

请详细分析上述 WSDL,仔细思考,给出这个 WebService 服务器提供了多少个函数,给出一个函数列表,包括每个函数的参数。

 AI回答如下: 根据提供的 WSDL 文件分析,该 WebService 服务器提供了 4 个函数,每个函数对应一个操作(operation)。以下是详细的函数列表及参数说明: 1. Hello 描述:简单的问候函数,接收一个字符串并返回一个字符串。 输入参数: S (string):输入的字符串。 输出参数: return (string):返回的字符串。 2. HelloWord 描述:接收两个字符串参数,并返回一个字符串(注意:输入参数中包含 MyResult,与输出参数同名,但属于不同的消息部分)。 输入参数: S (string):第一个输入字符串。 MyResult (string):第二个输入字符串。 输出参数: MyResult (string):返回的字符串。 3. TestArray 描述:接收一个整数数组,并返回一个整数数组。 输入参数: A (TIntegerSOAPArray):整数数组,类型为自定义的 SOAP 数组。 输出参数: return (TIntegerSOAPArray):整数数组。 4. XPlusY 描述:接收两个整数,返回它们的和。 输入参数: X (int):第一个整数。 Y (int):第二个整数。 输出参数: return (int):两数之和。 补充说明 所有操作均采用 RPC 编码风格(style="rpc"),并使用 SOAP 1.1 编码(encodingStyle="http://schemas.xmlsoap.org/soap/encoding/")。 服务地址为:http://localhost:8080/soap/IIMyTest(需根据实际部署修改)。 SOAP Action 格式为:urn:IMyTestIntf-IIMyTest#操作名,例如 Hello 的 SOAP Action 为 urn:IMyTestIntf-IIMyTest#Hello。 消息体使用的命名空间为:urn:IMyTestIntf-IIMyTest。 如果需要生成具体的 SOAP 请求 XML 示例,请告知要调用的函数及参数值。 

我在网页聊天窗口继续输入:

# 调用 XPlusY 函数 现在你需要作为一个 WebService 客户端,调用服务器提供的 XPlusY 函数,你必须生成调用 XPlusY 函数的完整的符合SOAP协议的XML给服务器端。 调用 XPlusY 函数的两个参数分别是:X=12; Y=22; 请深入思考后输出符合规范的XML 

AI 输出作为 WebService 客户端调用服务器端函数的 XML 如下:

<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <XPlusY xmlns="urn:IMyTestIntf-IIMyTest"> <X xsi:type="xsd:int">12</X> <Y xsi:type="xsd:int">22</Y> </XPlusY> </soap:Body> </soap:Envelope> 

上述 XML 看起来和 Delphi 的客户端调用服务器端函数的 XML 有点不一样,但主要内容是相同的。我使用这个 XML 能不能成功调用 Delphi 写的 WebService 服务器端程序呢?把上述 XML 保存为 XML_0.TXT 然后用 IdHTTP1 去 POST 给服务器端程序,然后看到成功的返回内容,看起来服务器端正确理解了这个XML并执行了 XPlusY 这个函数。服务器返回的 XML 如下:

<?xml version="1.0"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:NS1="urn:IMyTestIntf-IIMyTest"><NS1:XPlusYResponse><return xsi:type="xsd:int">34</return></NS1:XPlusYResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> 

那么,我的服务器端程序返回的 XML,AI 能不能正确理解呢?我把服务器返回的 XML 复制粘贴到 AI 的聊天框里面,输出Delphi写的服务器程序的返回值给AI,

AI 的回答是:
从 SOAP 调用的角度来看,服务器返回的 XML 是一个标准的 SOAP 1.1 响应,表明对 XPlusY 函数的调用已成功执行,并返回了计算结果。以下是详细解释:

  1. 响应整体结构
    xml

<?xml version="1.0"?>

<SOAP-ENV:Envelope
xmlns:SOAP-ENV=“http://schemas.xmlsoap.org/soap/envelope/”
xmlns:xsd=“http://www.w3.org/2001/XMLSchema”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xmlns:SOAP-ENC=“http://schemas.xmlsoap.org/soap/encoding/”>
<SOAP-ENV:Body SOAP-ENV:encodingStyle=“http://schemas.xmlsoap.org/soap/encoding/”
xmlns:NS1=“urn:IMyTestIntf-IIMyTest”>
NS1:XPlusYResponse
34
</NS1:XPlusYResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
2. 关键元素和属性解释
SOAP-ENV:Envelope:根元素,声明了 SOAP 必需的命名空间:

xmlns:SOAP-ENV=“http://schemas.xmlsoap.org/soap/envelope/”:SOAP 信封命名空间。

xmlns:xsd 和 xmlns:xsi:XML Schema 命名空间,用于数据类型声明。

xmlns:SOAP-ENC=“http://schemas.xmlsoap.org/soap/encoding/”:SOAP 编码命名空间,表示使用了 SOAP 1.1 编码规则。

SOAP-ENV:Body:消息体,包含实际的响应内容。

SOAP-ENV:encodingStyle=“http://schemas.xmlsoap.org/soap/encoding/”:明确指定了消息体采用 SOAP 编码风格,与 WSDL 中定义的 use=“encoded” 一致。

xmlns:NS1=“urn:IMyTestIntf-IIMyTest”:在 Body 上声明了命名空间前缀 NS1,其值为操作的命名空间 urn:IMyTestIntf-IIMyTest。

NS1:XPlusYResponse:响应元素,命名空间前缀 NS1 指向 urn:IMyTestIntf-IIMyTest,元素名 XPlusYResponse 遵循 RPC 响应的命名惯例(方法名 + “Response”)。它包含一个子元素 return。

return:输出参数元素,表示函数的返回值。

xsi:type=“xsd:int”:通过 xsi:type 显式声明了数据类型为整数(xsd:int),符合 SOAP 编码规范中对数据类型的描述。

元素内容为 34,即计算结果(12 + 22 = 34)。

  1. 与请求的对应关系
    请求中我们发送了 XPlusY 操作,参数 X=12 和 Y=22。

服务器正确处理了请求,计算两数之和,并将结果包装在标准响应结构中返回。

响应中的命名空间和编码风格与请求完全匹配,体现了 RPC/encoded 模式的服务交互。

  1. 结论
    该响应表明:

调用 成功(无 SOAP Fault)。

返回值为 34,验证了 XPlusY 函数的正确性。

服务器遵循了 WSDL 定义的绑定,使用了 RPC/encoded 风格,并正确序列化了返回数据。

因此,您的客户端调用已成功执行,并得到了预期的结果。

结论

经过上述测试,发现 DeepSeek 确实可以在明确要求 SOAP 调用的指示下,自己创建 SOAP 调用的 XML,并且能成功让 WebService 服务器程序执行相关的函数,也能正确理解函数执行的返回结果。

虽然AI和WebService服务器程序的通讯,是我在中间人肉中转的,但验证了 AI 可以调用 WebService 程序。

如果我写一个程序,直接使用 AI 的 API 接口,我的程序就可以自动将 WebService 的 WSDL 发送给 AI,然后自动接收 AI 传过来的 XML,然后我的程序可以把这个 XML 发送给服务器,达到调用服务器的函数或者方法的目的,并且可以把函数调用结果返回给 AI,AI 也能正确理解返回结果,因此 AI 也可以决定接下来可以做什么。这样一来,技术上,我就可以使用 Delphi 来实现一个 AI agent 了。

Read more

七大排序算法深度解析:从原理到代码实现

七大排序算法深度解析:从原理到代码实现

1.排序 排序算法是计算机科学中最基础的技能之一,无论你是编程新手还是经验丰富的开发者,理解这些算法都能显著提升代码效率。本文将用最简单的方式,带你快速掌握七大经典排序算法的核心原理与实现。 1.1排序概念及其运用 排序是指将一组数据按照特定规则(如升序或降序)重新排列的过程。排序是计算机科学中最基础且重要的操作之一,广泛用于优化数据检索、提高算法效率以及简化复杂问题的处理。 排序的主要应用场景 1. 数据库查询:加速数据检索(如索引排序)。 2. 搜索算法:二分查找要求数据有序。 3. 数据分析:统计、去重、Top-K问题(如排行榜)。 4. 任务调度:按优先级处理任务。 5. 文件系统:按文件名、日期排序文件。 1.2常见排序算法 本次将系统介绍7种经典排序算法,重点从时间复杂度、空间复杂度、稳定性三个维度展开分析,时间复杂度和空间复杂度的概念在之前博客中有所讲解,现在来说明一下排序算法稳定性的概念。 稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,

By Ne0inhk
数据结构:单链表(1)

数据结构:单链表(1)

目录 前言  一.单链表的概念 介绍 二.单链表的结构 介绍 链表的打印 核心逻辑解析 链表的销毁 三、实现单链表 1.单链表的尾插 结点的创建 2.单链表的头插 3.单链表的尾删 4.单链表的头删 代码   总结 前言    最近学校事务较多,我又正巧经历社团换届,所以耽误了几天时间,但好在所有投入都有了温暖的回应,留任成功了(虽然是小社团哈),接下来,我将继续更新博客,与大家分享知识。 本篇文章将讲解单链表的知识,包括:单链表的概念,单链表的结构、实现单链表、链表的分类、单链表算法题知识的相关内容,为5大模块,其中为本章节知识的内容。 一.单链表的概念 介绍   在之前我们学习了逻辑结构和物理结构都是线性的顺序表,但是我们会发现顺序表有以下3个比较明显的缺陷:中间/头部的插入删除,

By Ne0inhk
【动态规划】01背包与完全背包问题详解,LeetCode零钱兑换II秒解,轻松解力扣

【动态规划】01背包与完全背包问题详解,LeetCode零钱兑换II秒解,轻松解力扣

👨‍💻程序员三明治:个人主页 🔥 个人专栏: 《设计模式精解》《重学数据结构》 🤞先做到 再看见! 目录 * 01背包题目分析 * 01背包解决方法 * 完全背包题目分析 * 完全背包解决方法 * LeetCode 518.零钱兑换II * 思路 * 代码实现 01背包题目分析 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。 每一件物品其实只有两个状态,取或者不取,所以可以使用回溯法搜索出所有的情况,那么时间复杂度就是O(2^n),这里的n表示物品数量。 所以暴力的解法是指数级别的时间复杂度。进而才需要动态规划的解法来进行优化! 在下面的讲解,我举一个例子: 物品为: 重量价值物品0115物品1320物品2430 01背包解决方法 递归五部曲: 1. 确定dp数组以及下标的含义:dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,

By Ne0inhk
数据结构 | 深度解析二叉树的基本原理

数据结构 | 深度解析二叉树的基本原理

个人主页-爱因斯晨 文章专栏-数据结构 二叉树是计算机科学中最基础也最常用的数据结构之一,它不仅是理解更复杂树结构(如 AVL 树、红黑树)的基础,也广泛应用于表达式解析、 Huffman 编码、数据库索引等领域。本文将从二叉树的基本概念出发,深入探讨其存储结构、核心操作及实际应用,并通过 C 语言代码示例帮助读者掌握这一重要数据结构。 二叉树的基本概念 二叉树是一种每个节点最多有两个子节点的树状结构,这两个子节点分别被称为左孩子(left child)和右孩子(right child)。根据节点的分布情况,二叉树可以分为以下几种特殊类型: * 满二叉树:除叶子节点外,每个节点都有两个子节点,且所有叶子节点都在同一层 * 完全二叉树:除最后一层外,其余层都是满的,且最后一层的节点都靠左排列 * 平衡二叉树:左右两个子树的高度差不超过 1 的二叉搜索树 二叉树具有一个重要性质:在非空二叉树中,第 i 层最多有 2^(i-1) 个节点;深度为

By Ne0inhk