堆和堆排序【数据结构】

目录

  • 一、堆
    • 1. 堆的存储定义
    • 2. 初始化堆
    • 3. 销毁堆
    • 4. 堆的插入
      • 向上调整算法
    • 5. 堆的删除
      • 向下调整算法
    • 6. 获取堆顶数据
    • 7. 获取堆的数据个数
    • 8. 堆的判空
  • 二、Gif演示
  • 三、 堆排序
    • 1. 堆排序
      • (1) 建大堆
      • (2) 排序
    • 2.Topk问题
  • 四、完整代码
    • 1.堆的代码
      • Heap.c
      • Heap.h
      • test.c
    • 2. 堆排序的代码

前言:
什么是堆呢?
堆(Heap)是一种数据结构,它是 一种特殊的二叉树 ,其中父节点的键值总是大于或等于(或小于或等于)其任何一个子节点的键值。这意味着在堆中,根节点具有最大(或最小)键值。
堆:一般是数组数据看做一棵完全二叉树
完全二叉树的逻辑结构:
大堆01

  • 大堆: 任意一个父结点 大于等于 子结点
    大堆02

  • 小堆: 任意一个父结点 小于等于 子结点
    小堆
    数组存储完全二叉树
    在这里插入图片描述

一、堆

1. 堆的存储定义

因为存储结构,这里使用动态数组的形式来存放数据。但是也要注意其中的逻辑结构是完全二叉树。定义一个指针指向动态数组,定义存储堆的容量capacity,记录堆中的数据的个数size

代码

typedef int HPDataType;
typedef struct Heap
{HPDataType* a;	//指向动态数组int capacity;	//堆的容量int size;		//堆中数据个数
}Heap;

2. 初始化堆

类似顺序表的初始化

代码

//初始化堆
void InitHeap(Heap* hp) 
{assert(hp);hp->a = NULL;hp->capacity = 0;hp->size = 0;
}

3. 销毁堆

避免内存泄漏

代码

//销毁堆
void DestroyHeap(Heap* hp) 
{assert(hp);free(hp->a);hp->a = NULL;hp->capacity = hp->size = 0;	
}

4. 堆的插入

重点:
在堆的插入前,我们需要注意的就是,首先判断其容量,然后使用realloc给数组分配空间
分配空间后,把数据插入堆。但是数据在插入堆时,由于堆一般分为大根堆和小根堆,所以这里使用的大根堆。 大堆:父结点的值大于等于其孩子结点的值
但是数据的值不能确定,这个时候就需要我们使用 堆的向上调整算法

向上调整算法

在数组的末端插入元素,进行与其父结点进行比较,大堆的情况下,如果其孩子结点的值大于父亲结点的值时,把插入的数据向上调整,向上调整的方法是:把插入的数据与其父结点进行交换,交换后继续判断是否还需要向上调整。(使用向上调整算法的条件是前面结点的树是构成堆的)

这里是使用的是数组,所以当插入元素时,在数组的末端进行插入数据

物理存储:
在这里插入图片描述
逻辑存储情况:
在这里插入图片描述

在插入的数据时,我们就需要考虑一下,
1. 当插入的孩子结点的值大于其父亲结点的值时,就向上调整
思路:
首先是根据孩子结的下标找父结点的下标,(孩子结点下标-1)/2 == 父结点下标,因为可能调整所以将判断条件放到循环里面(当然也可以用递归),在循环里面切记一定要及时更新当前孩子结点的下标和父结点的下标,孩子结点的值大于父结点的值就向上调整,否则就跳出循环。当孩子结点的下标到0时,向上调整完成,循环结束。
在这里插入图片描述
2. 当小于等于时,不需要调整
在这里插入图片描述
代码

//向上调整
void AdjustUp(HPDataType * a,int child) 
{//先找到父结点的下标int parent = (child - 1) / 2;while (child > 0)	//child等于0时,说明已经调整ok了{if (a[child] > a[parent]){swap(&a[child], &a[parent]);//可能会向上调整多次child = parent;parent = (parent - 1) / 2;}else {break;}}
}//堆的插入
void PushHeap(Heap* hp, HPDataType x)
{assert(hp);//堆满判断if (hp->capacity == hp->size) {int newcapacity = hp->capacity == 0 ? 4 : 2 * hp->capacity;HPDataType* tmp = (HPDataType*)realloc(hp->a,sizeof(HPDataType)*newcapacity);if (tmp == NULL){perror("realloc fail");exit(-1);}hp->a = tmp;hp->capacity = newcapacity;}//堆元素的插入hp->a[hp->size] = x;hp->size++;//堆的向上调整AdjustUp(hp->a,hp->size-1);
}

调试,查看一下数据存储情况
在这里插入图片描述

5. 堆的删除

堆中元素的删除,发现直接删除尾结点是简单的(size减一即可),但是,一般堆,删除元素都是删除的头结点。
直接删除头结点时:发现逻辑结构上变成了两棵树,这样直接删除头结点的方法不推荐。
在这里插入图片描述
交换结点再删除
头尾结点交换后,再删除尾结点,然后头结点使用堆的向下调整算法,调堆。
使用前提就是,当进行交换的时候,保证左右仍是堆。第一个结点与最后一个结点的值交换后,向下调整。

向下调整算法

这里调的堆是大堆(根结点的值大于左右孩子结点的值)

  • 第一步,找到第一个根结点的孩子结点,这里使用假设法,先让左孩子的值最大,再进行判断左孩子还是右孩子的值是最大的,找出大的。
  • 第二步与根结点进行比较,大于根结点就交换。
  • 及时更新父结点和孩子结点的下标
  • 注意当孩子结点值都小于父亲结点值就跳出循环;循环结束条件:孩子结点的下标大于数组最大的下标(就是孩子下标<数组的个数,child<size,大于等于时说明循环就结束了)。

过程:
在这里插入图片描述
调整后
在这里插入图片描述
这样就完成堆头结点的删除。
还需要注意的就是:
在这里插入图片描述

代码

//向下调整
void AdjustDown(HPDataType* a, int size, int parent)
{//先去找根结点的较大的孩子结点int child = 2 * parent + 1;//可能会向下调整多次while (child<size) {//这里使用假设法,先假设左孩子的值最大//如果不对就进行更新if ((child+1 < size)&&a[child] < a[child+1]) {child++;}//根结点与其孩子结点中的较大的一个进行交换if(a[child] > a[parent]) {swap(&a[child],&a[parent]);//更新下标parent = child;child = 2 * parent + 1;}else {break; //调完堆}}
}
//堆的删除
void PopHeap(Heap* hp)
{assert(hp);assert(hp->size>0);//头尾交换swap(&hp->a[0],&hp->a[hp->size-1]);hp->size--;//向下调整AdjustDown(hp->a,hp->size,0);
}

调试一下:
在这里插入图片描述
上图中指向下标6其实有数据65的,但是数组的下标有效范围在0-5

6. 获取堆顶数据

前提:堆得有数据
代码

//获取堆顶数据
HPDataType TopHeap(Heap* hp) 
{assert(hp);assert(hp->size>0);return hp->a[0];
}

7. 获取堆的数据个数

代码

//获取堆的数据个数
int SizeHeap(Heap* hp)
{assert(hp);return hp->size;
}

8. 堆的判空

代码

//堆的判空
bool EmptyHeap(Heap* hp) 
{assert(hp);return hp->size == 0;
}

二、Gif演示

调堆演示
堆动图gif

三、 堆排序

堆排序是一种选择排序。
堆排序:可以从小到大进行排序(使用大堆)。Top k 问题:取出最大的前k个值。

1. 堆排序

堆排序(Heap Sort)是一种基于完全二叉树的排序算法,它通过将待排序的元素建成一个二叉堆。堆排序的时间复杂度为O(nlogn),它是不稳定排序算法。

堆排序的思路如下:

  1. 升序排序为例,先建立一个大堆(父节点的值大于子节点的值),将待排序的元素都插入堆中。
  2. 将堆顶元素(最大值)与堆末尾元素交换,然后将堆的大小减1。
  3. 对堆顶元素向下调整操作,使得堆重新满足最大堆的性质。
  4. 重复2-3步,直到堆的大小为1。排序完成。

(1) 建大堆

使用 向下 调整算法来向上建堆:使用向下调整算法,把数组调成大堆
因为堆本身是一个完全二叉树,假设一共有h层,我们从第h-1层(即不是叶子结点的那一层开始)
因为是大堆,根结点的值大于孩子结点的值,从最下方使用向下调整来不断把较大的值来调到根节点。
注意:虽然使用的是向下调整算法,其实还是不断往上调整(把大的值调到上面)。
如图:
在这里插入图片描述
直到调整到第一层为止
建堆时间复杂度:O(N)

//堆排序
void HeapSort(int* arr, int n) 
{int i = 0;//使用向下调整算法向上调整,把大的值调到上方。for (i = (n - 1 - 1) / 2; i >= 0;i--){//先找到数组最后端的父结点的下标//父结点的下标减一就是另一个//使用向下调整算法进行调整AdjustDown(arr,n,i);}
}

当然也可以用向上算法进行向上建堆。

思路:先让一个独自成堆,然后尾插一个结点,再进行与根结点进行比较,大于根结点的值就交换。
但是这个使用向上调整算法向上建堆的时间复杂度为:O(Nlog(N))

//向上调整算法进行堆排序
void HeapSort(int* arr, int n)
{int i = 0;//先让第一个结点独自成堆//再一次尾增结点进行向上调整for (i = 1; i < n; i++) {AdjustUp(arr,i);}
}

(2) 排序

因为建成大堆后,将堆顶元素(最大值)与堆末尾元素交换

	//注意end 是从n-1开始的(数组最后一个元素的下标)int end = n-1;while (end > 0) {//swap end = n-1 这表示下标swap(&arr[0],&arr[end]);//adjustdown 函数里面的end是元素的个数,所以不是先--end//所以AdjustDown(arr,end,0);end--;}

注意这里的end–,上述是从数组最后一个元素下标n-1 开始。堆的首元素与尾元素交换完后,接着就是堆的个数减1,然后下进行向下调整。这里的end–放在了最后。因为AdjustDown中的第二个参数是传的是堆的大小,正好数组下标n-1 , 堆由n减一也是 n -1。

下方给出了 end 从n 开始的优化,但是可读性就会下降

void HeapSort(int* arr, int n)
{int i = 0;//先建成一个大堆for (i = (n - 1 - 1) / 2; i >= 0;--i) {AdjustDown(arr,n,i);}//堆顶元素与堆尾元素进行交换,进而把大的元素放到后面int end = n;while (end > 0) {swap(&arr[--end],&arr[0]);AdjustDown(arr,end,0);}
}

2.Topk问题

topk问题,例如:在10000个数据排名中找出前10;或者在10000个数中找出最大的前10个

这里我们就以在10000个数中找出最大的前10(k = 10)个为例

首先应先准备数据,随机生成10000个数(注意srand函数只能生成30000多个随机数)
核心思想: 建一个可以存储k个数据的小堆。先把文件数据前10个数据读取到小堆中(进行向下调成小堆),然后再把文件中的其他数据一个一个读出与小堆的根结点的值进行比较,如果大于小堆的根结点,就进放入堆中,然后进行向下调堆。

//创建数据
void Createdata() 
{int n = 10000;srand((unsigned)time(0));const char* file = "data.txt";FILE* fin = fopen(file,"w");if (fin == NULL){perror("fopen error");return;}for (int i = 0; i < n;i++){int x = (rand() + i) % 100000;//把随机生成的数据写到fin文件中去fprintf(fin,"%d\n",x);}fclose(fin);
}
void PrintTopK(int k) 
{//从文件中读出数据const char* file = "data.txt";FILE* fout = fopen(file,"r");if (fout == NULL){perror("fout error");return;}//将数据读出到容量为k的动态数组中int* arr = (int*)malloc(sizeof(int)*k);if (arr == NULL){perror("malloc error");exit(-1);}//先把前k个数据放入数组中for (int i = 0; i < k; i++){//将数据读到数组中fscanf(fout,"%d",&arr[i]);//放数据的同时进行建堆AdjustUp(arr,i);}int x = 0;//当文件里面的数据读完后会返回EOFwhile (fscanf(fout, "%d", &x) != EOF) {//当从文件拿出的数据大于小堆中的数据时//将数据放到小堆中//并使用向下调整//这样每次来的比较大的数据就可以放到小堆中if (x > arr[0]) {arr[0] = x;AdjustDown(arr,k,0);}}//打印数据for (int i = 0; i < k;i++) {printf("%d ",arr[i]);}fclose(fout);}

在这里插入图片描述

四、完整代码

1.堆的代码

Heap.c

#include "Heap.h"//初始化堆
void InitHeap(Heap* hp) 
{assert(hp);hp->a = NULL;hp->capacity = 0;hp->size = 0;
}//销毁堆
void DestroyHeap(Heap* hp) 
{assert(hp);free(hp->a);hp->a = NULL;hp->capacity = hp->size = 0;	
}//交换两个数
void swap(HPDataType* s1,HPDataType* s2) 
{HPDataType tmp = *s1;*s1 = *s2;*s2 = tmp;
}
//向上调整
void AdjustUp(HPDataType * a,int child) 
{//先找到父结点的下标int parent = (child - 1) / 2;while (child > 0)	//child等于0时,说明已经调整ok了{if (a[child] > a[parent]){swap(&a[child], &a[parent]);//可能会向上调整多次child = parent;parent = (parent - 1) / 2;}else {break;}}
}//堆的插入
void PushHeap(Heap* hp, HPDataType x)
{assert(hp);//堆满判断if (hp->capacity == hp->size) {int newcapacity = hp->capacity == 0 ? 4 : 2 * hp->capacity;HPDataType* tmp = (HPDataType*)realloc(hp->a,sizeof(HPDataType)*newcapacity);if (tmp == NULL){perror("realloc fail");exit(-1);}hp->a = tmp;hp->capacity = newcapacity;}//堆元素的插入hp->a[hp->size] = x;hp->size++;//堆的向上调整AdjustUp(hp->a,hp->size-1);
}//向下调整
void AdjustDown(HPDataType* a, int size, int parent)
{//先去找根结点的较大的孩子结点int child = 2 * parent + 1;//可能会向下调整多次while (child<size) {//这里使用假设法,先假设左孩子的值最大//如果不对就进行更新if ((child+1 < size)&&a[child] < a[child+1]) {child++;}//根结点与其孩子结点中的较大的一个进行交换if(a[child] > a[parent]) {swap(&a[child],&a[parent]);//更新下标parent = child;child = 2 * parent + 1;}else {break; //调完堆}}
}
//堆的删除
void PopHeap(Heap* hp)
{assert(hp);assert(hp->size>0);//头尾交换swap(&hp->a[0],&hp->a[hp->size-1]);hp->size--;//向下调整AdjustDown(hp->a,hp->size,0);
}//获取堆顶数据
HPDataType TopHeap(Heap* hp) 
{assert(hp);assert(hp->size>0);return hp->a[0];
}//获取堆的数据个数
int SizeHeap(Heap* hp)
{assert(hp);return hp->size;
}//堆的判空
bool EmptyHeap(Heap* hp) 
{assert(hp);return hp->size == 0;
}

Heap.h

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int HPDataType;
typedef struct Heap
{HPDataType* a;	//指向动态数组int capacity;	//堆的容量int size;		//堆中数据个数
}Heap;//初始化堆
void InitHeap(Heap* hp);//销毁堆
void DestroyHeap(Heap* hp);//堆的插入
void PushHeap(Heap* hp, HPDataType x);//堆的删除
void PopHeap(Heap*hp);//获取堆顶数据
HPDataType TopHeap(Heap* hp);//获取堆的数据个数
int SizeHeap(Heap* hp);//堆的判空
bool EmptyHeap(Heap* hp);

test.c

#include "Heap.h"void Test1() 
{Heap hp;InitHeap(&hp);PushHeap(&hp,49);PushHeap(&hp,65);PushHeap(&hp,34);PushHeap(&hp,25);PushHeap(&hp,37);PushHeap(&hp,27);PushHeap(&hp,19);//删除65PopHeap(&hp);//printf("堆的个数:%d\n",SizeHeap(&hp));//while (!EmptyHeap(&hp)) //{//	printf("%d-", TopHeap(&hp));//	PopHeap(&hp);//}DestroyHeap(&hp);//27,19,34,65,49,25,37
}
int main() 
{Test1();return 0;
}

2. 堆排序的代码

//堆排序
void HeapSort(int* arr, int n) 
{int i = 0;//使用向下调整算法向上调整,把大的值调到上方。for (i = (n - 1 - 1) / 2; i >= 0;i--){//先找到数组最后端的父结点的下标//父结点的下标减一就是另一个//使用向下调整算法进行调整AdjustDown(arr,n,i);}//进行排序//因为是大堆,所以根结点的值是最值//把最值与堆的最后一个结点进行交换//再把交换后的根节点进行向下调整//然后堆的大小减一//注意end 是从n-1开始的(数组最后一个元素的下标)int end = n-1;while (end > 0) {//swap end = n-1 这表示下标swap(&arr[0],&arr[end]);//adjustdown 函数里面的end是元素的个数,所以不是先--end//所以AdjustDown(arr,end,0);end--;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最新IE跳转Edge浏览器解决办法(2024.2.26)

最新IE跳转Edge浏览器解决办法&#xff08;2024.2.26&#xff09; 1. IE跳转原因1.1. 原先解决办法1.2. 最新解决办法1.3. 最后 1. IE跳转原因 关于IE跳转问题是由于在2023年2月14日&#xff0c;微软正式告别IE浏览器&#xff0c;导致很多使用Windows10系统的电脑在打开IE浏览…

树莓派 关闭低电压闪电报警和文字报警

关闭低电压闪电图标报警 方法&#xff1a; sudo nano /boot/config.txt在末尾加上 avoid_warnings1重启就可以了 关闭文字报警 方法&#xff1a; sudo apt remove lxplug-ptbatt然后重启就可以了

【论文阅读】基于人工智能目标检测与跟踪技术的过冷流沸腾气泡特征提取

Bubble feature extraction in subcooled flow boiling using AI-based object detection and tracking techniques 基于人工智能目标检测与跟踪技术的过冷流沸腾气泡特征提取 期刊信息&#xff1a;International Journal of Heat and Mass Transfer 2024 级别&#xff1a;EI检…

SpringCloud-Gateway解决跨域问题

Spring Cloud Gateway是一个基于Spring Framework的微服务网关&#xff0c;用于构建可扩展的分布式系统。在处理跨域问题时&#xff0c;可以通过配置网关来实现跨域资源共享&#xff08;CORS&#xff09;。要解决跨域问题&#xff0c;首先需要在网关的配置文件中添加相关的跨域…

SNMP简介

定义 简单网络管理协议SNMP&#xff08;Simple Network Management Protocol&#xff09;是广泛应用于TCP/IP网络的网络管理标准协议。SNMP提供了一种通过运行网络管理软件的中心计算机&#xff08;即网络管理工作站&#xff09;来管理设备的方法。SNMP的特点如下&#xff1a;…

Python爬虫获取淘宝商品详情页数据|实现自动化采集商品信息

要实现自动化采集淘宝商品详情页数据&#xff0c;可以使用Python的第三方库如requests和BeautifulSoup。以下是一个简单的示例&#xff1a; Taobao.item_get-获得淘宝商品详情数据接口返回值说明 1.请求方式:HTTP POST &#xff1b;复制Taobaoapi2014获取APISDK文件。 2.请求…

如何让网页APP化 渐进式Web应用(PWA)

前言 大家上网应该发现有的网页说可以安装对应应用&#xff0c;结果这个应用好像就是个web&#xff0c;不像是应用&#xff0c;因为这里采用了PWA相关技术。 PWA&#xff0c;全称为渐进式Web应用&#xff08;Progressive Web Apps&#xff09;&#xff0c;是一种可以提供类似…

pytest如何在类的方法之间共享变量?

在pytest中&#xff0c;setup_class是一个特殊的方法&#xff0c;它用于在类级别的测试开始之前设置一些初始化的状态。这个方法会在类中的任何测试方法执行之前只运行一次。 当你在setup_class中使用self来修改类属性时&#xff0c;你实际上是在修改类的一个实例属性。在Pyth…

开源现场总线协议栈(ethercat、ethernet/ip、opc ua、profinet、canopen、modbus)

ecat主站及其相关&#xff1a; 1.soem&#xff1a;GitHub - OpenEtherCATsociety/SOEM: Simple Open Source EtherCAT MasterSimple Open Source EtherCAT Master. Contribute to OpenEtherCATsociety/SOEM development by creating an account on GitHub.https://github.com/…

Rust升级慢,使用国内镜像进行加速

背景 rustup 是 Rust 官方的跨平台 Rust 安装工具&#xff0c;国内用户使用rustup update的时候&#xff0c;网速非常慢&#xff0c;可以使用国内的阿里云镜像源来进行加速 0x01 配置方法 1. Linux与Mac OS用户配置环境变量 修改~/.bash_profile文件添加如下内容&#xff1…

科技论文编写思路

科技论文编写思路 1.基本框架2.课题可行性评估1.研究目标和意义2.研究方法和技术3.可行性和可操作性4.风险和不确定性5.经济性和资源投入6.成果预期和评估 3.写作思路4.利用AI读论文5.实验流程 1.基本框架 IntroductionRelated worksMethodExperiment and analysisDiscussionC…

【Git教程】(五)分支 —— 并行式开发,分支相关操作(创建、切换、删除)~

Git教程 分支 1️⃣ 并行式开发2️⃣ 修复旧版本中的 bug3️⃣ 分支4️⃣ 当前活跃分支5️⃣ 重置分支指针6️⃣ 删除分支7️⃣ 清理提交对象&#x1f33e; 总结 对于版本提交为什么不能依次进行&#xff0c;以便形成一条直线型的提交历史记录&#xff0c;我们认为有 以下两个…

swagger-ui.html报错404,解决办法

swagger-ui.html报错404,解决办法&#xff01;现在后端开发项目中&#xff0c;为了节省时间&#xff0c;使用swagger插件&#xff0c;可以方便的快捷生成接口文档。但是如果你在请求前端页面路径比如&#xff1a;http://127.0.0.1:7777/swagger-ui.html。找不到。那是因为你的配…

深度学习基础(一)神经网络基本原理

之前的章节我们初步介绍了机器学习相关基础知识&#xff0c;目录如下&#xff1a; 机器学习基础&#xff08;一&#xff09;理解机器学习的本质-CSDN博客 机器学习基础&#xff08;二&#xff09;监督与非监督学习-CSDN博客 机器学习基础&#xff08;四&#xff09;非监督学…

Netty入门指南:从零开始的异步网络通信

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Netty入门指南&#xff1a;从零开始的异步网络通信 前言Netty简介由来&#xff1a;发展历程&#xff1a;异步、事件驱动的编程模型&#xff1a; 核心组件解析通信协议高性能特性异步编程范式性能优化与…

探索AI视频模型的无限可能:OpenAI的Sora引领创新浪潮

文章目录 &#x1f4d1;前言一、技术解析二、应用场景三、未来展望四、伦理与创意五、用户体验与互动&#x1f324;️总结 &#x1f4d1;前言 随着人工智能技术的蓬勃发展&#xff0c;AI视频模型正逐渐成为科技领域的新宠。在这个变革的浪潮中&#xff0c;OpenAI推出的首个AI视…

ESP8266智能家居(1)——开发环境的搭建

1.前期介绍 本次打算使用esp8266的开发板——NodeMCU&#xff0c;进行物联网相关项目的学习。开发环境使用Arduino软件。 NodeMCU实物图为&#xff1a; 开发环境截图为&#xff1a; 2.软件下载 我使用的arduino版本为1.8.5&#xff0c;其安装包如下&#xff1a; 【免费】ar…

自动驾驶框架:自动驾驶汽车定位-感知-规划-决策-控制概述,按照我的架构图理解:决策决定的是速度,规划决定的是路径(架构理解推荐)

1.按照我的架构图理解&#xff1a;决策决定的是速度&#xff0c;规划决定的是路径 参考链接&#xff1a;【自动驾驶】运动规划丨速度规划丨自动驾驶速度规划及状态协调方法 2.下面是参考别人的理解&#xff1a; 自动驾驶汽车定位-感知-规划-决策-控制概述 规划-决策-控制知…

Lua速成(2)

一、流程控制 Lua 编程语言流程控制语句通过程序设定一个或多个条件语句来设定。在条件为 true 时执行指定程序代码&#xff0c;在条件为 false 时执行其他指定代码。 控制结构的条件表达式结果可以是任何值&#xff0c;Lua认为false和nil为假&#xff0c;true和非nil为真。 …

ChatGPT学习第三周

&#x1f4d6; 学习目标 ChatGPT在各行各业的应用 探索ChatGPT在不同领域&#xff08;如教育、客户服务等&#xff09;的实际应用案例。 ChatGPT的局限性和挑战 讨论ChatGPT面临的挑战&#xff0c;包括偏见、误解及其限制。 ✍️ 学习活动 学习资料 《人工智能通用大模型(…