数据结构进阶篇 之 【二叉树顺序存储(堆)】的整体实现讲解(赋完整实现代码)

在这里插入图片描述

做人要谦虚,多听听别人的意见,然后记录下来,看看谁对你有意见

一、二叉树的顺序(堆)结构及实现

1.二叉树的顺序结构

2.堆的概念及结构

3.堆的实现

3.1 向下调整算法 AdJustDown

3.2 向上调整算法 AdJustUP

3.3 堆的创建

3.3.1 向上建堆
3.3.2 向下建堆
3.3.3 堆的初始化与销毁
3.3.4 堆的插入(压栈)
3.3.5 取堆顶的数据
3.3.6 堆的删除
3.3.7 堆的数据个数
3.3.8 堆的判空

二、堆的完整实现代码

三、完结撒❀

–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–

一、二叉树的顺序(堆)结构及实现

1.二叉树的顺序结构


物理结构:数组
逻辑结构:二叉树

顺序结构存储就是使用数组来存储普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费,而完全二叉树更适合使用顺序结构存储

可能有些同学不太清楚普通二叉树使用数组来存储为什么会造成空间上的浪费,这里给大家讲解一下:
我们使用数组进行二叉树的存储时,父子节点之间需要满足的关系为

parent = (child+1)/2;
leftchild = parent2-1;
rightchild = parent
2+2;
ps:parent指父节点在数组中的下标位置,leftchild指左子节点在数组中的下标位置,rightchild指右子节点在数组中的下标位置

那么对于满二叉树和完全二叉树,我们按照一层一层(层序)往数组中进行存储。
举例如下图所示,大家可以按照下图简单计算验证一下父子之间是否满足父子关系:
在这里插入图片描述

可以知道,对于满二叉树和完全二叉树进行层序存储在数组中,按照下标计算都是满足上面所述的父子关系。

而对于普通二叉树(非满二叉树,非完全二叉树),我们依然按照上面存储进行计算
在这里插入图片描述
可以发现不符合父子节点之间的关系,问题在于2节点的右节点为空,而在存储时对于空节点我们并没有在数组中进行存储记录,相当于在数组中少了一个位置,那么我们如果把空节点加上,如下图:
在这里插入图片描述
这样就满足了父子间的关系,但是对于下标为4的位置并没有存储数据,就造成了空间浪费。

所以,对于普通二叉树我们一般使用链式结构进行存储,避免空间浪费。

现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

2.堆的概念及结构

如果有一个关键码的集合K = {K0,K1,K2,…,Kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki<=K2i+1且Ki<=K2i+2(Ki>=K2i+1且Ki>=K2i+2)i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆的性质:

1.堆中某个节点的值总是不大于或不小于其父节点的值;
2.堆总是一棵完全二叉树;

在这里插入图片描述
堆的兄弟节点(同一父节点的子两个子节点)之间是不论大小的,而对于小堆其父节点的值一定小于子节点,对于大堆其父节点的值一定大于子节点。

3.堆的实现

堆初始化结构:

//堆初始化
void HPInit(HP* php)
{assert(php);php->a = NULL;php->capacity = php->size = 0;
}

在给定一个数组去实现成堆之前我们需要先了解内部实现的核心逻辑

3.1 向下调整算法 AdJustDown

现在我们给出一个数组,逻辑上看做一颗完全二叉树。

int arr[] = {27,15,19,18,28,34,65,49,25,37}

我们通过从根节点开始的向下调整算法可以把它调整成一个小堆
向下调整算法有一个前提:左右子树必须是一个堆,才能调整。
上面数组逻辑上的二叉树可画为:
在这里插入图片描述
可以看出来,根节点27影响了整体的小堆结构,那么我们如何将其转变为小堆呢?
在这里插入图片描述

(制作不是很好大家将就着看看就行)
按照上面图片显示的流程,我们在逻辑上就把之前的二叉树变成了小堆排序,而其逻辑实现思想就是向下调整。

向下调整

再强调一边:
向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

从根开始,比较其子节点的大小,如果为大堆排序就将父节点与子节点中较大的节点交换,如果为小堆就将父节点与子节点中较小的节点交换。交换完毕继续重复以上逻辑,直到父节点大于子节点(大堆)或是父节点小于子节点(小堆)即可完成堆排序。

代码实现:

void Swap(HPDataType* px, HPDataType* py)
{HPDataType tmp = *px;*px = *py;*py = tmp;
}//向下调整O(logN)
void AdJustDown(HPDataType* a, int n, int parent)
{//从左孩子开始,child为小孩子那个int child = parent * 2 + 1;while (child<n){if (child + 1 < n && a[child] > a[child + 1]){++child;}if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[parent], &a[child]);parent = child;child = child * 2 + 1;}else{break;}}
}

3.2 向上调整算法 AdJustUP

在一个二叉树的数组中如果我们尾插了一个数据,可能就导致结构不再是堆。

所以我们如果是在现有的一个堆里进行数据尾插存储,那么我们要保证数据插入后还是堆,这时一般使用向上调整算法。

下面我们给出一个数组,请画出其逻辑结构二叉树:

int arr[] = {10,15,56,25,30,70}

二叉树:

在这里插入图片描述
如果我将5尾插在数组当中,那么就相当于是将56节点的右孩子连了一个5节点:
在这里插入图片描述
这显然已经不是小堆了,调整逻辑如下:
在这里插入图片描述
这就是向上调整的整体逻辑:

如果是进行小堆排序,将尾节点值与其父节点的值进行比较,如果小于父节点就交换,如果进行大堆,那就判断子节点是否大于父节点,若是大于就交换。

代码实现:

void Swap(HPDataType* px, HPDataType* py)
{HPDataType tmp = *px;*px = *py;*py = tmp;
}//向上调整 O(logN)
void AdJustUP(HPDataType* a, int child)
{int parent = (child - 1) / 2;//while (1)严格来说不行while(child>0){if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[child], &a[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}

向下调整算法和向上调整算法的时间复杂度都为O(logN),大家感兴趣可以算一下。

3.3 堆的创建

向上调整和向下调整都是基于已经形成了堆上面,那么如果随便给一个本就不是堆的数组,我们该如何进行建堆呢?

3.3.1 向上建堆

下面我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个小堆,现在我们通过算法,把它构建成一个小堆。

int a[] = {536821};

根节点左右子树不是小堆,我们怎么调整呢?

这里我们从根的左孩子节点开始向上调整,根据数组存储顺序向后以此执行,直到最后一个节点为止。

其二叉树为:
在这里插入图片描述
调整逻辑:
在这里插入图片描述
从根节点的子节点开始,进行向上调整,一次调整完毕将子节点对应数组下标加1进入下一个节点进行向上调整,直到除了根的所有节点都调整完毕,二叉树便变成了堆。

代码实现:

//向上调整 O(logN)
void AdJustUP(HPDataType* a, int child)
{int parent = (child - 1) / 2;//while (1)严格来说不行while(child>0){if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[child], &a[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}//初始化建堆
void HPInitArray(HP* php, HPDataType* a, int n)
{assert(php);php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);if (php->a == NULL){perror("malloc fail");return;}memcpy(php->a, a, sizeof(HPDataType) * n);php->size = php->capacity = n;//向上建堆 O(N*logN)for (int i = 1; i < php->size; i++){AdjustUp(php->a, i);}
}
3.3.2 向下建堆

向下建堆就是根据向下调整的逻辑进行。

我们把二叉树分为其根和子树,再把子树分为其根和子树,将每一个分好的子树都进行向下调整,直到叶子节点为止。

我们还拿上面数组为例:

int a[] = {536821};

这里我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成小堆

调整逻辑:在这里插入图片描述
代码实现:

//向下调整O(logN)
void AdJustDown(HPDataType* a, int n, int parent)
{//从左孩子开始,child为小孩子那个int child = parent * 2 + 1;while (child<n){//假设法选出左右节点中大/小的节点if (child + 1 < n && a[child] > a[child + 1]){++child;}if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[parent], &a[child]);parent = child;child = child * 2 + 1;}else{break;}}
}//初始化建堆
void HPInitArray(HP* php, HPDataType* a, int n)
{assert(php);php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);if (php->a == NULL){perror("malloc fail");return;}memcpy(php->a, a, sizeof(HPDataType) * n);php->size = php->capacity = n;//向下建堆 O(N)for (int i = (php->size - 1 - 1) / 2; i >= 0; i--){AdJustDown(php->a, php->size, i);}
}

向上建堆和向下建堆的时间复杂度分别为O(N*logN),O(N)。
因为向下建堆的时间复杂度小,所以我们在实际工作中进行建堆一般是选择向下建堆

3.3.3 堆的初始化与销毁

在数据结构中,创建任何结构,都需要对其进行初始化和销毁。

代码实现:

//堆初始化
void HPInit(HP* php)
{assert(php);php->a = NULL;php->capacity = php->size = 0;
}//堆销毁
void HPDestory(HP* php)
{assert(php);free(php->a);php->a = NULL;php->capacity = php->size = 0;
}
3.3.4 堆的插入(压栈)

插入一个数到数组的尾上,再进行向上调整算法,直到满足堆。
代码实现:

//向上调整 O(logN)
void AdJustUP(HPDataType* a, int child)
{int parent = (child - 1) / 2;//while (1)严格来说不行while(child>0){if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[child], &a[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}//压栈 O(logN)
void HPPush(HP* php, HPDataType x)
{assert(php);//判断空间是否足够if (php->size == php->capacity){int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, newcapacity * sizeof(HPDataType));if (tmp == NULL){perror("realloc fail");return;}php->a = tmp;php->capacity = newcapacity;}php->a[php->size] = x;php->size++;//数据尾插向上调整AdJustUP(php->a, php->size-1);
}
3.3.5 取堆顶的数据

在建好的堆中返回其根部数据。
代码实现:

//返回根数据
HPDataType HPTop(HP* php)
{assert(php);assert(php->size);return php->a[0];
}
3.3.6 堆的删除

删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。

代码实现:

//向下调整O(logN)
void AdJustDown(HPDataType* a, int n, int parent)
{//从左孩子开始,child为小孩子那个int child = parent * 2 + 1;while (child<n){if (child + 1 < n && a[child] > a[child + 1]){++child;}if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[parent], &a[child]);parent = child;child = child * 2 + 1;}else{break;}}
}//删除根数据O(logN)
void HPPop(HP* php)
{assert(php);assert(php->size);//将根数据与最后一个子叶交换,再删除最后一个数据Swap(&php->a[0], &php->a[php->size-1]);php->size--;//向下调整AdJustDown(php->a, php->size, 0);
}
3.3.7 堆的数据个数

代码实现:

int HeapSize(HP* php)
{assert(php);return php->size;
}
3.3.8 堆的判空

代码实现:

//判断堆是否为空
bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}

二、堆的完整实现代码

Heap.h:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;//小堆//堆初始化
void HPInit(HP* php);
//初始化建堆
void HPInitArray(HP* php, HPDataType* a, int n);//堆销毁
void HPDestory(HP* php);//压栈
void HPPush(HP* php, HPDataType x);//返回根数据
HPDataType HPTop(HP* php);//删除根数据
void HPPop(HP* php);//堆的数据个数
int HPSize(HP* php);//判断堆是否为空
bool HPEmpty(HP* php);

Heap.c:

#include "Heap.h"//堆初始化
void HPInit(HP* php)
{assert(php);php->a = NULL;php->capacity = php->size = 0;
}//堆销毁
void HPDestory(HP* php)
{assert(php);free(php->a);php->a = NULL;php->capacity = php->size = 0;
}void Swap(HPDataType* px, HPDataType* py)
{HPDataType tmp = *px;*px = *py;*py = tmp;
}//向上调整 O(logN)
void AdJustUP(HPDataType* a, int child)
{int parent = (child - 1) / 2;//while (1)严格来说不行while(child>0){if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[child], &a[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}//压栈 O(logN)
void HPPush(HP* php, HPDataType x)
{assert(php);//判断空间是否足够if (php->size == php->capacity){int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, newcapacity * sizeof(HPDataType));if (tmp == NULL){perror("realloc fail");return;}php->a = tmp;php->capacity = newcapacity;}php->a[php->size] = x;php->size++;//数据尾插向上调整AdJustUP(php->a, php->size-1);
}//返回根数据
HPDataType HPTop(HP* php)
{assert(php);assert(php->size);return php->a[0];
}//向下调整O(logN)
void AdJustDown(HPDataType* a, int n, int parent)
{//从左孩子开始,child为小孩子那个int child = parent * 2 + 1;while (child < n){if (child + 1 < n && a[child] > a[child + 1]){++child;}if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[parent], &a[child]);parent = child;child = child * 2 + 1;}else{break;}}
}//删除根数据O(logN)
void HPPop(HP* php)
{assert(php);assert(php->size);//将根数据与最后一个子叶交换,再删除最后一个数据Swap(&php->a[0], &php->a[php->size-1]);php->size--;//向下调整AdJustDown(php->a, php->size, 0);
}int HeapSize(HP* php)
{assert(php);return php->size;
}//判断堆是否为空
bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}//初始化建堆
void HPInitArray(HP* php, HPDataType* a, int n)
{assert(php);php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);if (php->a == NULL){perror("malloc fail");return;}memcpy(php->a, a, sizeof(HPDataType) * n);php->size = php->capacity = n;//向上建堆 O(N*logN)/*for (int i = 1; i < php->size; i++){AdjustUp(php->a, i);}*///向下建堆 O(N)for (int i = (php->size - 1 - 1) / 2; i >= 0; i--){AdJustDown(php->a, php->size, i);}
}//建堆排序//排序
// 升序
//小堆时间复杂度太大O(N^2),用大堆进行排序O(N*logN)
//大堆//升序  大堆 O(N*logN)
//降序  小堆 O(N*logN)
void HeapSort(HPDataType* a, int n)
{//根据数组直接建堆 O(N)for (int i = (n - 1 - 1) / 2; i >= 0; --i){AdJustDown(a, n, i);}//交换根和尾的位置,删除尾,再向上调整 O(N*logN)int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdJustDown(a, end, 0);--end;}
}

三、完结撒❀

如果以上内容对你有帮助不妨点赞支持一下,以后还会分享更多编程知识,我们一起进步。
最后我想讲的是,据说点赞的都能找到漂亮女朋友❤
在这里插入图片描述

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

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

相关文章

AndroidStudio出现类似 Could not create task ‘:app:ToolOperatorDemo.main()‘. 错误

先看我们的报错 翻译过来大概意思是:无法创建任务:app:ToolOperatorDemo.main()。 没有找到名称为“main”的源集。 解决方法&#xff1a; 在.idea文件夹下的gradle.xml文件中 <GradleProjectSettings>标签下添加<option name"delegatedBuild" value"f…

这样使用ChatGPT,效率翻倍不是梦!四大秘诀公开

随着ChatGPT技术的不断革新&#xff0c;它在我们日常工作中扮演着越来越重要的角色。那么&#xff0c;我们该如何利用ChatGPT来解决工作难题呢&#xff1f; Q1&#xff1a;想要迅速获得ChatGPT的帮助&#xff0c;我们应如何提出问题&#xff1f; 以下是几条高效提问的建议&…

前端学习<二>CSS基础——11-CSS3属性详解(一)

前言 我们在上一篇文章中学习了CSS3的选择器&#xff0c;本文来学一下CSS3的一些属性。 本文主要内容&#xff1a; 文本 盒模型中的 box-sizing 属性 处理兼容性问题&#xff1a;私有前缀 边框 背景属性 渐变 文本 text-shadow&#xff1a;设置文本的阴影 格式举例&…

FPGA芯片在通信基站中的作用

基站作为移动通信系统的核心组成部分&#xff0c;承担着信号的发送和接收任务&#xff0c;包括天线、射频前端、数字信号处理和控制等功能。 随着通信技术不断进步和网络容量的提升&#xff0c;基站功能日益复杂&#xff0c;数量也在增加。 与此同时&#xff0c;FPGA芯片被广…

@EnableWebMvc 导致自定义序列化器失效

目录 前言 一. 自定义序列化器失效 1.1 EnableWebMvc 的作用 1.2 EnableWebMvc 带来了什么后果 1.3 原理分析 1.4 问题解决 二. 总结 前言 在使用Swagger的时候用 到了EnableWebMvc&#xff0c;发现之前为了解决Long类型、日期类型等自定义序列化器失效了 Configurati…

【送书福利第六期】:《AI绘画教程:Midjourney使用方法与技巧从入门到精通》

文章目录 一、《AI绘画教程&#xff1a;Midjourney使用方法与技巧从入门到精通》二、内容介绍三、作者介绍&#x1f324;️粉丝福利 一、《AI绘画教程&#xff1a;Midjourney使用方法与技巧从入门到精通》 一本书读懂Midjourney绘画&#xff0c;让创意更简单&#xff0c;让设计…

如何在Linux系统部署ONLYOFFICE协作办公利器并实现多人实时编辑文档

文章目录 1. 安装Docker2. 本地安装部署ONLYOFFICE3. 安装cpolar内网穿透4. 固定OnlyOffice公网地址 本篇文章讲解如何使用Docker在本地服务器上安装ONLYOFFICE&#xff0c;并结合cpolar内网穿透实现公网访问。 Community Edition允许您在本地服务器上安装ONLYOFFICE文档&…

Makefile:运行流程解析(五)

当输入make并且进行回车时&#xff0c;首先回去检查对应的目录下是否有Makefile或者makefile文件如果有文件那么执行指定的目标&#xff08;没有指定目标默认第一个目标为最终目标&#xff09;&#xff0c;如果没有对应的文件&#xff0c;报错执行结束对于最终的目标首选检查是…

【回溯与邻里交换】纸牌三角

1.回溯算法 旋转有3种可能&#xff0c;镜像有2种 所以最后次数&#xff1a;counts/3/2 #include<iostream> using namespace std;int num[9]; int counts0; bool bools[9];//默认为false int dfs(int step){if(step9){//索引 if((num[0]num[1]num[2]num[3]num[3]num[4]n…

【御控物联】JavaScript JSON结构转换(12):对象To数组——键值互换

文章目录 一、JSON结构转换是什么&#xff1f;二、核心构件之转换映射三、案例之《JSON对象 To JSON数组》四、代码实现五、在线转换工具六、技术资料 一、JSON结构转换是什么&#xff1f; JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换…

Java类与对象:从概念到实践的全景解析!

​ 个人主页&#xff1a;秋风起&#xff0c;再归来~ 文章专栏&#xff1a;javaSE的修炼之路 个人格言&#xff1a;悟已往之不谏&#xff0c;知来者犹可追 克心守己&#xff0c;律己则安&#xff01; 1、类的定义格式 在java中定义类时需要用到…

LabVIEW车载轴承振动监测系统

LabVIEW车载轴承振动监测系统 随着汽车工业的快速发展&#xff0c;车用轴承的稳定性和可靠性对保障车辆安全运行越来越重要。目前&#xff0c;大多数车用轴承工作在恶劣的环境下&#xff0c;容易出现各种故障。开发了一种基于LabVIEW的车载轴承振动监测系统&#xff0c;提高车…

941: 有序顺序表的合并操作的实现

学习版 【c语言】 1.顺序表元素类型 2.顺序表的初始化 3.顺序表的插入 4.顺序表的合并 #include <cstdio> #include <cstdlib> #include <iostream> #include <algorithm>typedef struct {int* data; // 数据数组的指针int length; // 当前顺序表…

学习平台的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读100套最新项目持续更新中..... 2024年计算机毕业论文&#xff08;设计&#xff09;学生选题参考合集推荐收藏&#xff08;包含Springboot、jsp、ssmvue等技术项目合集&#xff09; 1. 系统功能…

【Qt 学习笔记】Day1 | Qt 开发环境的搭建

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Day1 | Qt 开发环境的搭建 文章编号&#xff1a;Qt 学习笔记 / 02 文…

Redis命令-Set命令

基础篇Redis 4.7 Redis命令-Set命令 Redis的Set结构与Java中的HashSet类似&#xff0c;可以看做是一个value为null的HashMap。因为也是一个hash表&#xff0c;因此具备与HashSet类似的特征&#xff1a; 无序元素不可重复查找快支持交集.并集.差集等功能 Set类型的常见命令 …

浅谈AI未来发展趋势与挑战

对于AI大模型未来发展趋势与挑战的个人看法&#xff1a; 1、未来的发展趋势&#xff1a; AI大模型未来发展趋势可以从以下几个关键方面来讨论&#xff1a; 1. 能源与计算效率 绿色计算与节能技术&#xff1a;随着硬件技术的发展&#xff0c;预计未来的AI大模型将进一步降低能…

redis学习-主从复制和哨兵模式

目录 1. 主从复制&#xff0c;读写分离 1.1 介绍 1.2 使用命令介绍 1.3 实现 1.4全量复制和增量复制 2.哨兵模式 1. 主从复制&#xff0c;读写分离 1.1 介绍 指的是将一台redis服务器中的数据复制到其他redis服务器&#xff0c;前者称为主机&#xff0c;后者称为从机&#xf…

基于SpringBoot + Vue实现的高校汉服租赁网站系统设计与实现+毕业论文

介绍 高校汉服租赁网站管理系统可以提高高校汉服租赁网站信息管理问题的解决效率&#xff0c;优化高校汉服租赁网站信息处理流程&#xff0c;保证高校汉服租赁网站信息数据的安全&#xff0c;它是一个非常可靠&#xff0c;非常安全的应用程序。系统包含普通用户和管理员两个角…

【AI系列】Python NLTK 库和停用词处理的应用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…