最小代价生成树实现(算法与数据结构设计)

课题内容和要求

最小代价生成树的实现,分别以普利姆算法和克鲁斯卡尔算法实现最小代价生成树,并分析两种算法的适用场合。

数据结构说明

普利姆算法实现最小代价生成树的图采用邻接表存储结构,还有辅助数据结构,数组nearest,数组lowcost,数组mark。克鲁斯卡尔算法实现最小代价生成树的图采用邻接矩阵存储结构,其中还定义了辅助数据结构用于存放边。

算法设计

普利姆算法。
辅助数据结构说明:
(1)一维数组nearest,nearest[v]存放与v距离最近的顶点编号u,距离最近是指边(u,v)是所有与顶点v关联的边中权值最小的边。初始时,nearest[v] = -1.
(2)一维数组lowcost,lowcost[v]用于存放边(nearest[v],v)的权值。初始时lowcost[v]=INFINITY。INFINITY是假定的极大值。
(3)一维数组mark,mark[v]用于标记顶点v是否在生成树中,若mark[v]=0,表示顶点v未加入生成树;否则,表示v已加入生成树。初始时,mark[v]=0。
算法步骤:
(1)分别将数组nearest,lowcost,mark初始化并将源点加入生成树。
(2)循环n-1次,重复以下操作。
a.查找顶点k的未加入生成树的所有邻接顶点j,若边(k,j)的权值比lowcost[j]小,则将lowcost[j]更新为此权值,并令lowcost[j]=k。
b.在未加入生成树的顶点中,查找具有最小lowcost的顶点k。
c.将k加入生成树。

克鲁斯卡尔算法。
辅助数据结构说明:
(1)一维数组Edge,从邻接矩阵中获取所有边以及边对应的顶点保存在数组Edge中,并且采用排序算法对边按照权值递增排序。
(2)一维数组parent,用于标识各个顶点所属的连通分量,若两个顶点属于不同的连通分量,则将这两个顶点关联的边加入到生成树中。parent[i]表示顶点i所属的连通分量,初始时parent[i]=i,表示各顶点自成一个连通分量。
算法步骤:
(1)从邻接矩阵中获取所有边存储于数组Edge。
(2)调用快速排序对数组Edge边按权值从小到大排序
(3)变量k表示当前构造的最小代价生成树中的边数,其初始值为0,若k<n-1,则循环执行以下操作。
a.依次从Edge中取出边(u,v)
对u和v所在连通分量paren[u]和parent[v]进行判断,若两者不相等,表示两顶点属于不同连通分量,输出此边,并合并paren[u]和parent[v]两个连通分量;若paren[u]和parent[v]相等,表示属于同一连通分量,舍去此边而选择下一条最小的边。

详细设计

普利姆算法生成最小代价生成树文件Prim_main.c、Prim.c、Prim.h
Prim_main.c

#include <stdio.h>
#include <stdlib.h>
#include "Prim.h"
int main()
{// 以下为图例1LGraph *lg = (LGraph *)malloc(sizeof(LGraph));if (!Init(lg, 6)){printf("邻接表初始化失败\n");return 0;}// 定义边集数组然后利用循环加入到图中int e[18][3] = {{0, 1, 10}, {1, 0, 10}, {1, 4, 2}, {4, 1, 2}, {4, 3, 9}, {3, 4, 9}, {0, 5, 4}, {5, 0, 4}, {4, 5, 7}, {5, 4, 7}, {0, 2, 7}, {2, 0, 7}, {2, 5, 6}, {5, 2, 6}, {3, 5, 5}, {5, 3, 5}, {2, 3, 8}, {3, 2, 8}};for (int i = 0; i < 18; i++){if (!Insert(lg, e[i][0], e[i][1], e[i][2])){printf("边插入失败\n");return 0;}}int nearest[6] = {0};int lowcost[6] = {0};if (!Prim(0, nearest, lowcost, *lg))    // 构造最小生成树,以结点0为源点{printf("最小生成树构造失败\n");}printf("图例1最小代价生成树的边集如下:\n");int sum = 0;    // 计算最小权值之和for (int i = 0; i < lg->n; i++) // 输出最小代价生成树的边集{printf("(%d,%d,%d) ",nearest[i],i,lowcost[i]);sum+=lowcost[i];}printf("\n最小权值和为%d\n",sum);// 以上为图例1printf("----------------------------\n");// 以下为图例2LGraph *lg_2 = (LGraph *)malloc(sizeof(LGraph));if (!Init(lg_2, 6)){printf("邻接表初始化失败\n");return 0;}// 定义边集数组然后利用循环加入到图中int e_2[20][3] = {{0, 1, 6}, {1, 0, 6}, {0, 2, 1}, {2, 0, 1}, {0, 3, 5}, {3, 0, 5}, {1, 2, 5}, {2, 1, 5}, {2, 3, 5}, {3, 2, 5}, {1, 4, 3}, {4, 1, 3}, {3, 5, 2}, {5, 3, 2}, {2, 4, 6}, {4, 2, 6}, {2, 5, 4}, {5, 2, 4}, {4, 5, 6}, {5, 4, 6}};for (int i = 0; i < 20; i++){if (!Insert(lg_2, e_2[i][0], e_2[i][1], e_2[i][2])){printf("边插入失败\n");return 0;}}int nearest_2[6] = {0};int lowcost_2[6] = {0};if (!Prim(0, nearest_2, lowcost_2, *lg_2))  // 构造最小生成树,以0为源点{printf("最小生成树构造失败\n");}printf("图例2最小代价生成树的边集如下:\n");sum = 0;for (int i = 0; i < lg_2->n; i++)   // 输出最小代价生成树的边集{printf("(%d,%d,%d) ",nearest_2[i],i,lowcost_2[i]);sum+=lowcost_2[i];}printf("\n最小权值和为%d\n",sum);printf("输入回车结束程序。\n");getchar();Destroy(lg);Destroy(lg_2);
}

Prim.h

#ifndef __PRIM_H__
#define __PRIM_H__
typedef struct eNode    // 边结点
{int adjVex;            // 顶点vint w;                 // 点u与点v之间的权值struct eNode *nextArc; // 指向下一个结点
} ENode;
typedef struct lGraph   // 邻接表
{int n; // 图顶点数int e; // 图边数ENode **a;  // 指向一维指针的数组
} LGraph;
#define INFINITY 65535  // 假定一个无限值int Init(LGraph *lg, int nSize);                       // 邻接表初始化
void Destroy(LGraph *lg);                              // 邻接表的撤销
int Exist(LGraph *lg, int u, int v);                   // 边搜索
int Insert(LGraph *lg, int u, int v, int w);           // 边插入
int Prim(int k, int *nearest, int *lowcost, LGraph g); // 普利姆算法
#endif

Prim.c

#include "Prim.h"
#include <stdlib.h>
#include <stdio.h>
/*** @brief 邻接表初始化* @param lg 指向邻接表的指针* @param nSize 顶点个数* @return 0,初始化失败;1,初始化成功
*/
int Init(LGraph *lg, int nSize)
{lg->n = nSize;lg->e = 0;lg->a = (ENode **)malloc(nSize * sizeof(ENode *)); // 动态生成长度为n的一维指针数组if (!lg->a)   // 判断空间申请是否成功{return 0; // 申请空间失败}else{for (int i = 0; i < lg->n; i++){lg->a[i] = NULL; // 将指针数组a置空}return 1; // 申请空间成功}
}
/*** @brief 邻接表的撤销* @param lg 指向邻接表的指针* @return void
*/
void Destroy(LGraph *lg)
{int i;ENode *p,*q;for(i = 0;i<lg->n;i++){p = lg->a[i];q=p;while(p){p = p->nextArc;free(q);q=p;}}free(lg->a);
}
// 边搜索
/*** @brief 边搜索* @param lg 指向邻接表的指针* @param u 边的始点* @param v 边的终点* @return 0,搜索失败或顶点有误;1,搜索成功
*/
int Exist(LGraph *lg, int u, int v)
{ENode *p = NULL;if(u<0||v<0||u>lg->n-1||v>lg->n-1||u==v){return 0;  // 判断顶点是否有误}p=lg->a[u];while(p&&p->adjVex != v){p = p->nextArc;}if(!p){return 0;  // 未找到边}else{return 1;   // 找到边}
}
// 边插入
/*** @brief 边插入* @param lg 指向邻接表的指针* @param u 边的始点* @param v 边的终点* @param w 边的权值* @return 0,插入失败或边已存在;1,插入成功
*/
int Insert(LGraph *lg, int u, int v, int w)
{ENode *p = NULL;if(u<0||v<0||u>lg->n-1||v>lg->n-1||u==v){return 0;  // 判断顶点是否有误}if(Exist(lg,u,v)){printf("边已存在。\n");return 0;}p = (ENode*)malloc(sizeof(ENode));  // 为新结点分配空间p->adjVex = v;p->w = w;// 将新结点插入单链表的最前面,头插p->nextArc = lg->a[u];  lg->a[u] = p;lg->e++;return 1;
}
// 普利姆算法
/*** @brief 普利姆算法生成最小代价生成树* @param k 源点* @param nearest 存放顶点的最近顶点编号* @param lowcost 存放顶点距离最近点的距离* @param g 邻接表* @return 0,失败;1,成功
*/
int Prim(int k, int *nearest, int *lowcost, LGraph g)
{ENode *p;int i,j;int *mark = (int*)malloc(g.n*sizeof(int));  // 辅助数组if(k<0||k>g.n-1)    // 判断源点是否有效{return 0;}for(i = 0;i<g.n;i++)    // nearest数组,lowcost数组和mark数组初始化{nearest[i] = -1;lowcost[i] = INFINITY;mark[i]=0;  // 赋值为1表示结点加入生成树,0表示未加入}// 源点k加入生成树lowcost[k] = 0;nearest[k]=k;mark[k] = 1;for(i = 1;i<g.n;i++)    // 将其余n-1条边加入生成树{for(p = g.a[k];p;p = p->nextArc)    // 更新生成树外的顶点lowcost值{j=p->adjVex;if((!mark[j])&&(lowcost[j]>p->w)){lowcost[j] = p->w;nearest[j] = k;}}int min = INFINITY;for(j = 0;j<g.n;j++)    // 找生成树外顶点中具有最小lowcost值的顶点k{if((!mark[j])&&(lowcost[j]<min)){min = lowcost[j];k = j;}}mark[k]=1;  // 将顶点k加入生成树}return 1;
}

克鲁斯卡尔算法生成最小代价生成树文件Kruskal_main.c、Kruskal.h、Kruskal.c
Kruskal_main.c

#include <stdio.h>
#include <stdlib.h>
#include "Kruskal.h"
int main()
{// 图例1MGraph *mg = (MGraph*)malloc(sizeof(MGraph));if(!Init(mg,6)){printf("邻接矩阵初始化失败\n");}// 定义边集数组然后利用循环加入到图中int e[9][3] = {{0,1,10},{1,4,2},{0,2,7},{0,5,4},{4,5,7},{3,4,9},{2,5,6},{3,5,5},{2,3,8}};for(int i = 0;i<9;i++){if(!Insert(mg,e[i][0],e[i][1],e[i][2])){printf("边插入失败\n");}}Edge *edg = (Edge*)malloc(mg->e*sizeof(Edge));  // 辅助数据结构,存放边集int k = 0;for(int i = 0;i<mg->n;i++){for(int j = 0; j<i;j++){if(mg->a[i][j]!=0&&mg->a[i][j]!=INFINITY){edg[k].u = i;edg[k].v = j;edg[k].w = mg->a[i][j];k++;}}}int sum = 0;    // 计算最小代价生成树权值和printf("图例1最小代价生成树的边集如下:\n");Kruskal(mg,edg,&sum);printf("\n最小代价生成树权值和为:%d\n",sum);// 以上为图例1printf("-------------------------\n");// 以下为图例2MGraph *mg_2 = (MGraph*)malloc(sizeof(MGraph));if(!Init(mg_2,6)){printf("邻接矩阵初始化失败\n");}// 定义边集数组然后利用循环加入到图中int e_2[10][3] = {{0,1,6},{0,2,1},{0,3,5},{1,2,5},{2,3,5},{1,4,3},{2,4,6},{2,5,4},{3,5,2},{4,5,6}};for(int i = 0;i<10;i++){if(!Insert(mg_2,e_2[i][0],e_2[i][1],e_2[i][2])){printf("边插入失败\n");}}Edge *edg_2 = (Edge*)malloc(mg_2->e*sizeof(Edge));k = 0;for(int i = 0;i<mg_2->n;i++){for(int j = 0; j<i;j++){if(mg_2->a[i][j]!=0&&mg_2->a[i][j]!=INFINITY){edg_2[k].u = i;edg_2[k].v = j;edg_2[k].w = mg_2->a[i][j];k++;}}}sum = 0;    // 计算最小代价生成树权值和printf("图例2最小代价生成树的边集如下:\n");Kruskal(mg_2,edg_2,&sum);printf("\n最小代价生成树权值和为:%d\n",sum);printf("输入回车结束程序。\n");getchar();Destroy(mg);Destroy(mg_2);
}

Kruskal.h

#ifndef __KRUSKAL_H__
#define __DRUSKAL_H__
typedef struct mGraph
{int **a; // 邻接矩阵int n;   // 图的顶点数int e;   // 图的边数
} MGraph;
typedef struct edge // 辅助数据结构,保存邻接矩阵的边
{int u;  // 边的始点int v;  // 边的终点int w;  // 边的权值
} Edge;
#define INFINITY 65535  // 假定一个最大值,给边赋值表示顶点间不可达
int Init(MGraph *mg, int nSize);                // 邻接矩阵初始化
void Destroy(MGraph *mg);                       // 邻接矩阵的撤销
int Insert(MGraph *mg, int u, int v, int w);    // 边插入
int FindParent(int *parent, int a);             // 查结点树根
void Swap(Edge *edg, int i, int j);             // 交换函数
int Partition(Edge *edg, int left, int right);  // 分划函数
void QuickSort(Edge *edg, int left, int right); // 快速排序
void Kruskal(MGraph *mg, Edge *edg,int *sum);            // 克鲁斯卡尔算法生成最小代价生成树
#endif

Kruskal.c

#include <stdio.h>
#include <stdlib.h>
#include "Kruskal.h"
/*** @brief 邻接矩阵初始化* @param mg 指向待初始化的矩阵指针* @param nSize 顶点数* @return 0,初始化失败;1,初始化成功
*/
int Init(MGraph *mg, int nSize)
{mg->n = nSize;  // 初始化顶点数mg->e = 0;mg->a = (int**)malloc(nSize*sizeof(int*));if(!mg->a){return 0;   // 初始化失败}for(int i = 0;i<mg->n;i++)  // 循环初始化每条边{mg->a[i] = (int*)malloc(nSize*sizeof(int));for(int j = 0; j<mg->n; j++){mg->a[i][j] = INFINITY;}mg->a[i][i] = 0;}return 1;   // 初始化成功
}
/*** @brief 邻接矩阵的撤销* @param mg 指向待撤销的矩阵的指针* @return void
*/
void Destroy(MGraph *mg)
{for(int i = 0; i<mg->n; i++){free(mg->a[i]);}free(mg->a);
}
/*** @brief 边插入 * @param mg 指向待邻接矩阵的指针* @param u 要插入边的始点* @param v 要插入边的终点* @param w 边的权值* @return 0,插入失败或边已存在;1,边插入成功
*/
int Insert(MGraph *mg, int u, int v, int w)
{if(u<0||v<0||u>mg->n-1||v>mg->n-1||u==v){return 0;   // 插入失败}if(mg->a[u][v] != INFINITY){printf("边已存在\n");return 0;}mg->a[u][v] = w;    // 插入新边mg->a[v][u] = w;mg->e++;return 1;   // 插入成功
}
/*** @brief 查找顶点的树根* @param parent 存放所有结点树根的数组* @param a 待查找树根的结点* @return 返回a的树根
*/
int FindParent(int *parent,int a)
{int t = a;while(t != parent[t]){t = parent[t];}return t;
}
/*** @brief 交换函数* @param edg 存放边以及边相关信息的数组* @param i 数组下标* @param j 数组下标* @return void
*/
void Swap(Edge *edg,int i, int j)
{Edge tmp;tmp = edg[i];edg[i] = edg[j];edg[j] = tmp;
}
/*** @brief 分划函数,由快速排序调用* @param edg 存放边以及边相关信息的数组* @param left 数组下标,左边界* @param right 数组下标,右边界* @return j,快速排序分划元素的下标
*/
int Partition(Edge *edg,int left,int right)
{int i = left;int j = right+1;do{do{i++;}while(edg[i].w<edg[left].w);do{j--;} while(edg[j].w>edg[left].w);if(i<j){Swap(edg,i,j);}}while(i<j);Swap(edg, left, j);return j;
}
/*** @brief 快速排序* @param edg 存放边以及边相关信息的数组* @param left 数组下标,左边界* @param right 数组下标,右边界* @return void
*/
void QuickSort(Edge *edg, int left, int right)
{if(left<right){int j = Partition(edg, left, right);QuickSort(edg, left, j-1);QuickSort(edg, j+1,right);}
}
/*** @brief 克鲁斯卡尔算法生成最小代价生成树* @param mg 指向邻接矩阵的指针* @param edg 存放边以及边相关信息的数组* @param sum 计算最小代价生成树权值之和* @return void
*/
void Kruskal(MGraph *mg, Edge *edg,int *sum)
{int u1,v1;  // 记录顶点的根结点int *parent = (int*)malloc(mg->n*sizeof(int));  // 记录所有顶点的根结点,用于判断选取的边是否使生成的树构成回路for(int i = 0;i<mg->n;i++)  // 初始化使每个顶点的根结点为自己{parent[i] = i;}QuickSort(edg, 0, mg->e-1); // 将保存边的数组按权值由小到大排序int count = 0;for(int i = 0;i<mg->e;i++){u1 = FindParent(parent,edg[i].u);   // 查找顶点的根结点v1 = FindParent(parent,edg[i].v);if(u1 != v1)    // 根结点不同,表示不属于同一颗树{count++;parent[u1] = v1;    // 合并根节点printf("(%d,%d,%d) ",edg[i].u,edg[i].v,edg[i].w); // 输出属于最小生成树的边集*sum += edg[i].w;}if(count == mg->n-1)    // 最小生成树边数e等于顶点数n-1,提前退出{break;}}
}

测试数据及其结果分析

普利姆算法生成最小代价生成树图例1
在这里插入图片描述
在这里插入图片描述

图例2
在这里插入图片描述
在这里插入图片描述

程序运行结果:
在这里插入图片描述

克鲁斯卡尔算法生成最小代价生成树图例1
在这里插入图片描述
在这里插入图片描述

图例2
在这里插入图片描述
在这里插入图片描述

程序运行结果:
在这里插入图片描述

总结

由普利姆算法的时间复杂度O(n2),普利姆算法更适合当图中边的数量远大于点的数量的情形,在电路设计中可以应用于印刷电路板的布线问题以减少导线长度。由克鲁斯卡尔算法的时间复杂度O(eloge),克鲁斯卡尔算法更适合当图中点的数量远大于边的数量的情形,与普利姆算法类似,也可以用于优化连接路径的问题。

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

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

相关文章

统一视频接入平台LntonCVS视频监控平台具体功能介绍

LntonCVS视频监控平台是一款基于H5技术开发的安防视频监控解决方案&#xff0c;专为全球范围内不同品牌、协议及设备类型的监控产品设计。该平台提供了统一接入管理&#xff0c;支持标准的H5播放接口&#xff0c;使其他应用平台能够快速集成视频功能。无论开发环境、操作系统或…

【Android Kotlin】全网最全的Android Kotlin入门教程指南,入股不亏_android kotlin教程

Kotlin入门教程指南 前言 1.概述 1.1使用 Kotlin 进行服务器端开发1.2 使用 Kotlin 进行 Android 开发1.3 Kotlin JavaScript 概述1.4 Kotlin/Native 用于原生开发1.5 用于异步编程等场景的协程1.6 Kotlin 1.1 的新特性1.7 Kotlin 1.2 的新特性1.8 Kotlin 1.3 的新特性 2.开…

pandas中 groupby分组详解 1

引言 在一个使用 pandas 做数据分析的项目过程中&#xff0c;再次深刻理解了一下 pandas 中使用 groupby 进行分组的一些细节问题&#xff0c;以及对想要做的操作如何实现&#xff0c;在此记录&#xff1b; 问题 1&#xff1a;groupby 分组查看分组结果&#xff0c;以及重设分…

51单片机嵌入式开发:3、STC89C52操作8八段式数码管原理

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 STC89C52操作8八段式数码管原理 1 8位数码管介绍1.1 8位数码管概述1.2 8位数码管原理1.3 应用场景 2 原理图图解2.1 74HC573原理2.2 74HC138原理2.3 数码管原理 3 数码管程序…

Python 程序打印图案“G”(Python Program to print the pattern ‘G’)

在本文中&#xff0c;我们将学习如何使用星号和空格打印图案 G。给定一个数字 n&#xff0c;我们将编写一个程序&#xff0c;在 n 行或列上打印图案 G。 例子&#xff1a; 输入&#xff1a;7 输出&#xff1a; *** * * * *** * * * * *** 输入&…

Windows使用nxlog发送系统日志到Linux的rsyslog服务器

Windows使用nxlog发送系统日志到Linux的rsyslog服务器 前言一、IP地址规划及示意图二、在windows上安装及配置nxlog1.下载nxlog2.安装nxlog3.配置nxlog4.创建对应日志路径的文件夹 三、windows上启动nxlog服务四、在CentOS 7上配置日志存到指定位置文件1.编辑/etc/rsyslog.conf…

MySql Innodb 索引有哪些与详解

概述 对于MYSQL的INNODB存储引擎的索引&#xff0c;大家是不陌生的&#xff0c;都能想到是 B树结构&#xff0c;可以加速SQL查询。但对于B树索引&#xff0c;它到底“长”得什么样子&#xff0c;它具体如何由一个个字节构成的&#xff0c;这些的基础知识鲜有人深究。本篇文章从…

MATLAB engine for python调用m文件函数输出变量值python调用MATLAB函数混合编程

MATLAB engine for python调用m文件函数输出变量值python调用MATLAB函数混合编程 说明(废话)解决方案总结 说明(废话) python调用MATLAB函数&#xff0c;MATLAB函数实现在m文件&#xff0c;python直接调用MATLAB中的函数。 首先还是要安装好MATLAB engine python setup.py ins…

普通Java工程如何在代码中引用docker-compose.yml中的environment值

文章目录 一、概述二、常规做法1. 数据库配置分离2. 代码引用配置3. 编写启动类4. 支持打包成可执行包5. 支持可执行包打包成docker镜像6. docker运行 三、存在问题分析四、改进措施1. 包含environment 变量的编排文件2. 修改读取配置文件方式3. 为什么可以这样做 五、运行效果…

从文本到安全图像:自动提示优化防止不当内容生成

T2I生成技术已经得到了广泛关注&#xff0c;并见证了如GLIDE、Imagen、DALL-E 2、Stable Diffusion等大型生成模型的发展。尽管这些模型能够根据文本描述生成高质量的图像&#xff0c;促进了书籍插图、品牌标识设计、游戏场景创作等多种实际应用&#xff0c;但它们也被恶意用户…

ROS 2官方文档(基于humble版本)学习笔记(四)

ROS 2官方文档&#xff08;基于humble版本&#xff09;学习笔记&#xff08;四&#xff09; 2.客户端库使用colcon构建包&#xff08;package&#xff09;创建工作空间&#xff08;workspace&#xff09;构建工作空间执行测试&#xff08;tests&#xff09;导入环境&#xff08…

如何搜索查找ICLR论文

记录有几个查找顶级会议文章的网址&#xff0c;不止ICLR ICLR 2024 还会有visualization模式&#xff1a; ICLR 2024 virtual 这个网站也很棒 Paper Copilot ICLR 2024 当然还有一个用图表示各论文相关关系的网站&#xff1a; connected papers

入职字节外包2个月后,我离职了...

有一种打工人的羡慕&#xff0c;叫做“大厂”。 真是年少不知大厂香&#xff0c;错把青春插稻秧。 但是&#xff0c;在深圳有一群比大厂员工更庞大的群体&#xff0c;他们顶着大厂的“名”&#xff0c;做着大厂的工作&#xff0c;还可以享受大厂的伙食&#xff0c;却没有大厂…

Python应用开发——30天学习Streamlit Python包进行APP的构建(13)

st.chat_input 显示聊天输入窗口小部件。 Function signature[source]st.chat_input(placeholder="Your message", *, key=None, max_chars=None, disabled=False, on_submit=None, args=None, kwargs=None) Returns(str or None) The current (non-empty) value of…

排序——数据结构与算法 总结8

目录 8.1 排序相关概念 8.2 插入排序 8.2.1 直接插入排序&#xff1a; 8.2.2 折半插入排序&#xff1a; 8.2.3 希尔排序&#xff1a; 8.3 交换排序 8.3.1 冒泡排序&#xff1a; 8.3.2 快速排序&#xff1a; 8.4 选择排序 8.4.1 简单选择排序 8.4.2 堆排序 8.5 归并…

Docker:一、安装与卸载、配置阿里云加速器(Ubuntu)

目录 &#x1f341;安装docker&#x1f332;1、环境准备&#x1f332;2、安装docker Engine&#x1f9ca;1、卸载旧版、任何冲突的包&#x1f9ca;2、使用存储库安装&#x1f9ca;3、安装 Docker 包。&#x1f9ca;4、查询是否安装成功&#x1f9ca;5、运行hello-world镜像&…

24西安电子科技大学马克思主义学院—考研录取情况

01、马克思主义学院各个方向 02、24马克思主义学院近三年复试分数线对比 PS&#xff1a;马院24年院线相对于23年院线增加15分&#xff0c;反映了大家对于马克思主义理论学习与研究的热情高涨&#xff0c;也彰显了学院在人才培养、学科建设及学术研究等方面的不断进步与成就。 6…

算法day02 回文 罗马数字转整数

回文 搞错了String类型的indexOf方法&#xff0c;理解成获取对应下标的值&#xff0c;实际上是在找对应值的下标。 4ms 耗时最少的方法尽量不会去调用jdk提供的方法&#xff0c;而是直接使用对应的数学逻辑关系来处理&#xff0c; 甚至用 代替equals方法。 罗马数字转整数 考…

设计模式探索:策略模式

1. 什么是策略模式&#xff08;Strategy Pattern&#xff09; 定义 策略模式&#xff08;Strategy Pattern&#xff09;的原始定义是&#xff1a;定义一系列算法&#xff0c;将每一个算法封装起来&#xff0c;并使它们可以相互替换。策略模式让算法可以独立于使用它的客户端而…

vue3+electron项目搭建,遇到的坑

我主要是写后端,所以对前端的vue啊vue-cli只是知其然,不知其所以然 这样也导致了我在开发前端时候遇到了很多的坑 第一个坑, vue2升级vue3始终升级不成功 第二个坑, vue add electron-builder一直卡进度,进度条走完就是不出提示succes 第一个坑的解决办法: 按照网上说的升级v…