【数据结构】顺序表实操——通讯录项目
Hi~!这里是奋斗的小羊,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~
💥💥个人主页:奋斗的小羊
💥💥所属专栏:C语言
🚀本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为展示我的学习过程及理解。文笔、排版拙劣,望见谅。
目录
- 前言
- 1、创建结构体类型
- 2、通讯录的初始化和销毁
- 3、通讯录的增删查改
- 3.1 添加联系人
- 3.2 删除联系人
- 3.3 展示联系人
- 3.4 修改联系人
- 3.5 查找联系人
- 4、通讯录菜单
- 5、通讯录项目代码
- 总结
前言
本篇文章将介绍一个运用顺序表的例子——通讯录项目。
通讯录我们都知道,细细一想通讯录不就是一个顺序表吗?在通讯录中以一个联系人为单位,存储着若干个联系人的各种信息,我们也可以对通讯录中的联系人信息进行相应的增删查改操作。但是上篇文章的顺序表存的只是整型数据,而在本文联系人的信息可不只是整形数据,如果想把一个联系人的各种信息以一个联系人为单位存储,就需要用到我们之前学到的内置类型——结构体类型。
接下来将详细介绍基于顺序表的通讯录项目搭建的具体过程。
本文将延用上篇文章中实现好的顺序表代码,具体请看—>顺序表
1、创建结构体类型
我们需要存联系人的姓名、性别、年龄、电话、地址等信息,如果把联系人看作一个单位,就需要一个类型能将联系人的这些信息储存,我们很容易的就能想到自定义类型——结构体类型。
所以第一步我们需要创建一个结构体类型来保存联系人的这些信息。
#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100typedef struct personinfo
{char name[NAME_MAX];char gender[GENDER_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}peoinfo;
我们将保存名字等信息的数组大小用宏代替,这样方便后续可能的更改。
创建好用于保存联系人信息的结构体类型后,接着就需要将顺序表头文件中的动态顺序表管理的数据类型替换掉,不要忘了包含相应的头文件。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "contact.h"//顺序表管理数据的类型
//typedef int sl_data_type;
typedef peoinfo sl_data_type;//动态顺序表
typedef struct seqlist
{sl_data_type* arr;int size;//数据个数int capacity;//空间大小
}SL;
2、通讯录的初始化和销毁
我们操作通讯录,实际上就是操作顺序表
那么通讯录的初始化和销毁,实际上就是顺序表的初始化和销毁。
为了方便识别,我们在通讯录头文件中给struct seqlist
重新改个名字就叫contact
。要想使用顺序表头文件中的struct seqlist
原本是需要在通讯录头文件包含顺序表头文件的,但是顺序表头文件中已经包含了通讯录头文件,而我们知道头文件是不能互相包含的,那为了在通讯录头文件中使用struct seqlist
,需要在使用前进行前置类型声明。
contact.h:
//给顺序表改一个名字
typedef struct seqlist contact;//前置声明//通讯录的初始化
void contact_init(contact* con);
//通讯录的销毁
void contact_destroy(contact* con);
contact.c:
#include "contact.h"
#include "seqlist.h"//通讯录的初始化
void contact_init(contact* con)
{//通讯录的初始化实际就是顺序表的初始化sl_init(con);
}//通讯录的销毁
void contact_destroy(contact* con)
{sl_destroy(con);
}
3、通讯录的增删查改
3.1 添加联系人
在通讯录中添加联系人实际上就是上篇文章中的在顺序表中插入一个整型数据,只不过在这里把一个联系人当作一个单位。
首先我们需要一个结构体变量来存联系人的各种信息,然后再将这个结构体变量插入到通讯录(顺序表)中,插入方式可以有多种。
//通讯录添加数据
void contact_add(contact* con)
{//获取用户输入的信息//将用户输入的信息存到结构体变量中peoinfo info;printf("请输入要添加的联系人姓名:\n");scanf("%s", info.name);printf("请输入要添加的联系人性别:\n");scanf("%s", info.gender); printf("请输入要添加的联系人年龄:\n");scanf("%d", info.age);printf("请输入要添加的联系人电话:\n");scanf("%s", info.tel);printf("请输入要添加的联系人地址:\n");scanf("%s", info.addr);//将结构体数据插入到通讯录(顺序表)中sl_push_back(con, info);
}
测试:
void test()
{contact con;// == SL sl;contact_init(&con);contact_add(&con);contact_destroy(&con);
}int main()
{test();return 0;
}
可以看到我们成功地添加了一个联系人。
3.2 删除联系人
删除联系人操作有个大前提,就是要删除的这个联系人必须存在,否则无法删除。
怎么判断要删除的这个联系人是否存在呢?
首先我们需要获取要删除的这个联系人的信息,然后在通讯录中查找,如果找到了就可以执行删除操作,如果没找到就不能进行删除操作。
联系人的信息有好几个,我们可以任意选择其中的一个信息来判断是否存在这个联系人。
int find_by_name(contact* con, char name[])
{int i = 0;for (i = 0; i < con->size; i++){if (0 == strcmp(con->arr[i].name, name)){//找到了return i;}}return -1;
}//通讯录删除数据
void contact_delete(contact* con)
{//前提是要删除的这个联系人存在char name[NAME_MAX];printf("请输入您想删除的联系人姓名:\n");scanf("%s", name);int ret = find_by_name(con, name);if (ret < 0){printf("联系人不存在!\n");//直接返回return;}//删除指定位置的数据sl_erase(con, ret);printf("删除成功!\n");
}
上面我们是通过联系人的姓名来判断是否存在这个联系人,姓名是字符串,比较字符串需要用到字符串比较函数strcmp
,使用这个函数需要包含头文件<string.h>
如果找到匹配的姓名,则返回这个姓名对应联系人对应的下标,再调用顺序表中删除指定位置数据的函数删除这个联系人。
3.3 展示联系人
我们平时使用的通讯录是可以展示联系人的各种信息的,这里我们也简单地实现一下,将所有联系人的信息打印出来供使用者看。
//通讯录数据展示
void contact_show(contact* con)
{//打印表头printf("%2s %8s %8s %8s %8s\n", "姓名", "性别", "年龄", "电话", "地址");printf("——— ——— ——— ——— ———\n");int i = 0;for (i = 0; i < con->size; i++){printf("%2s %7s %7d %9s %9s\n", con->arr[i].name,con->arr[i].gender,con->arr[i].age,con->arr[i].tel,con->arr[i].addr);}
}
3.4 修改联系人
修改联系人信息也有个大前提,就是要修改的这个联系人必须存在,才能被修改。
//通讯录修改
void contact_modify(contact* con)
{//前提是要修改的联系人存在char name[NAME_MAX];printf("请输入要修改的联系人姓名:\n");scanf("%s", name);int ret = find_by_name(con, name);if (ret < 0){printf("联系人不存在!\n");return;}//修改指定位置的数据printf("请输入新的姓名:\n");scanf("%s", con->arr[ret].name);printf("请输入新的性别:\n");scanf("%s", con->arr[ret].gender);printf("请输入新的年龄:\n");scanf("%d", &con->arr[ret].age);printf("请输入新的电话:\n");scanf("%s", con->arr[ret].tel);printf("请输入新的地址:\n");scanf("%s", con->arr[ret].addr);printf("修改成功!\n");
}
3.5 查找联系人
我们可以延用之前写好的根据联系人姓名来查找联系人的find_by_name
函数。
//通讯录查找
void contact_find(contact* con)
{char name[NAME_MAX];printf("请输入要查找的联系人姓名:\n");scanf("%s", name);int ret = find_by_name(con, name);if (ret < 0){printf("您要查找的联系人不存在!\n");return;}printf("%2s %8s %8s %8s %8s\n", "姓名", "性别", "年龄", "电话", "地址");printf("——— ——— ——— ——— ———\n");printf("%2s %7s %7d %9s %9s\n", con->arr[ret].name,con->arr[ret].gender,con->arr[ret].age,con->arr[ret].tel,con->arr[ret].addr);
}
4、通讯录菜单
在实现完通讯录的相关操作后,我们接着制作一个简易菜单。
这个方法我们以前使用过多次了,这里就不再赘述。
其中枚举类型定义在头文件contact.h
中。
#include "seqlist.h"void menu()
{printf("************* 通讯录 *************\n");printf("**** 1.添加联系人 2.删除联系人 ****\n");printf("**** 3.修改联系人 4.查找联系人 ****\n");printf("**** 5.展示通讯录 0.退出通讯录 ****\n");printf("************************************\n");
}int main()
{int input = 0;contact con;contact_init(&con);do{menu();printf("请选择您的操作:");scanf("%d", &input);switch (input){case EXIT:printf("退出通讯录!\n");break;case ADD:contact_add(&con);break;case DELETE:contact_delete(&con);break;case MODIFY:contact_modify(&con);break;case FIND:contact_find(&con);break;case SHOW:contact_show(&con);break;default:printf("选择错误,请重新选择!\n");break;}} while (input);//销毁通讯录contact_destroy(&con);return 0;
}
5、通讯录项目代码
seqlist.h:
#pragma once#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "contact.h"//顺序表管理数据的类型
//typedef int sl_data_type;
typedef peoinfo sl_data_type;//动态顺序表
typedef struct seqlist
{sl_data_type* arr;int size;//数据个数int capacity;//空间大小
}SL;//顺序表初始化
void sl_init(SL* ps);
//头插
void sl_push_front(SL* ps, sl_data_type x);
//尾插
void sl_push_back(SL* ps, sl_data_type x);
//在指定位置之前插入数据
void sl_insert(SL* ps, int pos, sl_data_type x);
//头删
void sl_pop_front(SL* ps);
//尾删
void sl_pop_back(SL* ps);
//删除指定位置的数据
void sl_erase(SL* ps, int pos);
//顺序表的查找
int sl_find(SL* ps, sl_data_type x);
//顺序表打印
void sl_print(const SL sl);
//顺序表销毁
void sl_destroy(SL* ps);
seqlist.c:
#define _CRT_SECURE_NO_WARNINGS#include "seqlist.h"void sl_init(SL* ps)
{ps->arr = NULL;ps->size = 0;ps->capacity = 0;
}//检查是否有空间允许插入数据
void check_capacity(SL* ps)
{if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//为了处理capacity为0的问题sl_data_type* tmp = (sl_data_type*)realloc(ps->arr, newcapacity * sizeof(sl_data_type));if (tmp == NULL){perror("realloc fail!");exit(1);}ps->arr = tmp;tmp = NULL;ps->capacity = newcapacity;//及时更新空间大小}
}void sl_push_front(SL* ps, sl_data_type x)
{assert(ps != NULL);check_capacity(ps);int i = 0;for (i = ps->size; i > 0; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[0] = x;ps->size++;
}void sl_push_back(SL* ps, sl_data_type x)
{assert(ps != NULL);check_capacity(ps);ps->arr[ps->size++] = x;
}void sl_insert(SL* ps, int pos, sl_data_type x)
{assert(ps != NULL);assert(pos >= 0 && pos <= ps->size);//确保指定的位置是有效的check_capacity(ps);int i = 0;for (i = ps->size; i > pos; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;ps->size++;
}void sl_pop_front(SL* ps)
{assert(ps != NULL);assert(ps->size != 0);//顺序表为空不能删除int i = 0;for (i = 0; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}void sl_pop_back(SL* ps)
{assert(ps != NULL);assert(ps->size != 0);//顺序表为空不能删除ps->size--;
}void sl_erase(SL* ps, int pos)
{assert(ps != NULL);assert(ps->size != 0);//实际下面的断言侧面完成了这句代码assert(pos >= 0 && pos < ps->size);//确保指定的位置是有效的int i = 0;for (i = pos; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}//int sl_find(SL* ps, sl_data_type x)
//{
// assert(ps != NULL);
// int i = 0;
// for (i = 0; i < ps->size; i++)
// {
// if (ps->arr[i] == x)
// {
// return i;
// }
// }
// return -1;
//}//void sl_print(const SL sl)
//{
// int i = 0;
// for (i = 0; i < sl.size; i++)
// {
// printf("%d ", sl.arr[i]);
// }
// printf("\n");
//}void sl_destroy(SL* ps)
{assert(ps != NULL);if (ps->arr != NULL)//动态内存函数开辟了空间{free(ps->arr);}ps->arr = NULL;ps->size = 0;ps->capacity = 0;
}
contact.h:
#pragma once#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100enum contact
{EXIT,ADD,DELETE,MODIFY,FIND,SHOW
};typedef struct personinfo
{char name[NAME_MAX];char gender[GENDER_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}peoinfo;//给顺序表改一个名字
typedef struct seqlist contact;//前置声明//通讯录的初始化
void contact_init(contact* con);
//通讯录的销毁
void contact_destroy(contact* con);
//通讯录添加数据
void contact_add(contact* con);
//通讯录删除数据
void contact_delete(contact* con);
//通讯录修改
void contact_modify(contact* con);
//通讯录查找
void contact_find(contact* con);
//通讯录数据展示
void contact_show(contact* con);
contact.c:
#define _CRT_SECURE_NO_WARNINGS#include "contact.h"
#include "seqlist.h"
#include <string.h>//通讯录的初始化
void contact_init(contact* con)
{//通讯录的初始化实际就是顺序表的初始化sl_init(con);
}//通讯录的销毁
void contact_destroy(contact* con)
{sl_destroy(con);
}//通讯录添加数据
void contact_add(contact* con)
{//获取用户输入的信息//将用户输入的信息存到结构体变量中peoinfo info;printf("请输入要添加的联系人姓名:\n");scanf("%s", info.name);printf("请输入要添加的联系人性别:\n");scanf("%s", info.gender); printf("请输入要添加的联系人年龄:\n");scanf("%d", &info.age);printf("请输入要添加的联系人电话:\n");scanf("%s", info.tel);printf("请输入要添加的联系人地址:\n");scanf("%s", info.addr);//将结构体数据插入到通讯录(顺序表)中sl_push_back(con, info);printf("联系人添加成功!\n");
}int find_by_name(contact* con, char name[])
{int i = 0;for (i = 0; i < con->size; i++){if (0 == strcmp(con->arr[i].name, name)){//找到了return i;}}return -1;
}//通讯录删除数据
void contact_delete(contact* con)
{//前提是要删除的这个联系人存在char name[NAME_MAX];printf("请输入您想删除的联系人姓名:\n");scanf("%s", name);int ret = find_by_name(con, name);if (ret < 0){printf("联系人不存在!\n");//直接返回return;}//删除指定位置的数据sl_erase(con, ret);printf("删除成功!\n");
}//通讯录数据展示
void contact_show(contact* con)
{//打印表头printf("%2s %8s %8s %8s %8s\n", "姓名", "性别", "年龄", "电话", "地址");printf("——— ——— ——— ——— ———\n");int i = 0;for (i = 0; i < con->size; i++){printf("%2s %7s %7d %9s %9s\n", con->arr[i].name,con->arr[i].gender,con->arr[i].age,con->arr[i].tel,con->arr[i].addr);}
}//通讯录修改
void contact_modify(contact* con)
{//前提是要修改的联系人存在char name[NAME_MAX];printf("请输入要修改的联系人姓名:\n");scanf("%s", name);int ret = find_by_name(con, name);if (ret < 0){printf("联系人不存在!\n");return;}//修改指定位置的数据printf("请输入新的姓名:\n");scanf("%s", con->arr[ret].name);printf("请输入新的性别:\n");scanf("%s", con->arr[ret].gender);printf("请输入新的年龄:\n");scanf("%d", &con->arr[ret].age);printf("请输入新的电话:\n");scanf("%s", con->arr[ret].tel);printf("请输入新的地址:\n");scanf("%s", con->arr[ret].addr);printf("修改成功!\n");
}//通讯录查找
void contact_find(contact* con)
{char name[NAME_MAX];printf("请输入要查找的联系人姓名:\n");scanf("%s", name);int ret = find_by_name(con, name);if (ret < 0){printf("您要查找的联系人不存在!\n");return;}printf("%2s %8s %8s %8s %8s\n", "姓名", "性别", "年龄", "电话", "地址");printf("——— ——— ——— ——— ———\n");printf("%2s %7s %7d %9s %9s\n", con->arr[ret].name,con->arr[ret].gender,con->arr[ret].age,con->arr[ret].tel,con->arr[ret].addr);
}
test.c:
#define _CRT_SECURE_NO_WARNINGS#include "seqlist.h"void menu()
{printf("************* 通讯录 *************\n");printf("**** 1.添加联系人 2.删除联系人 ****\n");printf("**** 3.修改联系人 4.查找联系人 ****\n");printf("**** 5.展示通讯录 0.退出通讯录 ****\n");printf("************************************\n");
}int main()
{int input = 0;contact con;contact_init(&con);do{menu();printf("请选择您的操作:");scanf("%d", &input);switch (input){case EXIT:printf("退出通讯录!\n");break;case ADD:contact_add(&con);break;case DELETE:contact_delete(&con);break;case MODIFY:contact_modify(&con);break;case FIND:contact_find(&con);break;case SHOW:contact_show(&con);break;default:printf("选择错误,请重新选择!\n");break;}} while (input);//销毁通讯录contact_destroy(&con);return 0;
}
总结
- 通讯录其实就是顺序表,只是上文的顺序表存储的是整型数据,而本文的顺序表存储的结构体类型数据而已
- 在本篇文章中我们更多的是对保存联系人信息的结构体类型进行相应的操作,通讯录实际上就是顺序表,而顺序表的相关操作是我们已经实现好了的,所以我们只需要拿来用就可以了
- 通讯录就像是在顺序表的外面又包装了一层其他的操作,使其完成对联系人信息的增删查改操作
相关文章:
![](https://img-blog.csdnimg.cn/direct/de7e5c48907947e8a1a51d86bc7173b8.png)
【数据结构】顺序表实操——通讯录项目
Hi~!这里是奋斗的小羊,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~ 💥💥个人主页:奋斗的小羊 💥💥所属专栏:C语言 🚀本系列文章为个人学习…...
![](https://img-blog.csdnimg.cn/direct/fb0c0f6db53a462a9979a1af8e4567a8.png)
C++继承与多态—多重继承的那些坑该怎么填
课程总目录 文章目录 一、虚基类和虚继承二、菱形继承的问题 一、虚基类和虚继承 虚基类:被虚继承的类,就称为虚基类 virtual作用: virtual修饰成员方法是虚函数可以修饰继承方式,是虚继承,被虚继承的类就称为虚基类…...
![](https://img-blog.csdnimg.cn/direct/7128b783806e4bf2b0e14455a556848a.png)
论文阅读:基于谱分析的全新早停策略
来自JMLR的一篇论文,https://www.jmlr.org/papers/volume24/21-1441/21-1441.pdf 这篇文章试图通过分析模型权重矩阵的频谱来解释模型,并在此基础上提出了一种用于早停的频谱标准。 1,分类难度对权重矩阵谱的影响 1.1 相关研究 在最近针对…...
![](https://img-blog.csdnimg.cn/direct/2f700ece488a4789a74e1dc225a47c17.png)
1.接口测试-postman学习
目录 1.接口相关概念2.接口测试流程3.postman基本使用-创建请求(1)环境(2)新建项目集合Collections(3)新建collection(4)新建模块(5)构建请求请求URLheader设…...
![](https://www.ngui.cc/images/no-images.jpg)
2024年码蹄杯本科院校赛道初赛(省赛)
赛时所写题,简单写一下思路,qwq 第一题: 输出严格次小值, //#pragma GCC optimize(2)#include <iostream> #include <cstring> #include <algorithm> #include <vector> #include <queue> #incl…...
![](https://img-blog.csdnimg.cn/img_convert/9dfb9d397fdcf9e109e54636cc3d97c9.png)
PHP蜜语翻译器在线文字转码解码源码
源码介绍 PHP蜜语翻译器在线文字转码解码源码 文字加密通话、一键转换、蜜语密码 无需数据库,可以将文字、字母、数字、代码、表情、标点符号等内容转换成新的文字形式,通过简单的文字以不同的排列顺序来表达不同的内容!支持在线加密解密 有多种加密展示…...
![](https://www.ngui.cc/images/no-images.jpg)
安卓浏览器区分启动、打开、分享
搞了几个钟头,终于全兼容了,分享有2种类型! void getDataFromIntent(Intent intent) {if (intent.getAction().equals(Intent.ACTION_VIEW)) {urln intent.getDataString();if (urln ! null) {if (urln.contains("\n"))urln url…...
![](https://img-blog.csdnimg.cn/6b808a6e0d2c40e79d3f70d1514ffd34.jpg)
C/C++ 数组负数下标
一 概述 在 C 中,数组是一块连续的内存空间,数组的下标通常用来定位这段内存中的特定元素。下标通常从 0 开始,最大到数组长度减 1。例如,一个有 10 个元素的数组,其有效下标范围是从 0 到 9。 当你尝试使用负数下标来…...
![](https://www.ngui.cc/images/no-images.jpg)
钓鱼网站开发原理(社会工程学)
钓鱼网站开发原理(社会工程学) 一、课程简介1、课程大纲2、课程目标3、知识储备 二、钓鱼网站简介1、什么是钓鱼网站2、开发&原理 三、PHP环境搭建1、简介2、自动安装MySQL/apache/PHP3、安装navicat 四、PDO表单入库案例1、语法2、显示登录表单3、入…...
![](https://img-blog.csdnimg.cn/direct/80e6d88aac074ce4b020de350c5f986d.png)
如何优雅地使用 console.log 打印数组或对象
一、背景 使用 console.log 在控制台中打印数组或者对象时,很多时候它们的字段都是默认关闭的,需要手动一个个的点开,非常不直观且麻烦。 二、解决方案 使用 JSON.stringify() 的第三个参数 我们来看一下官方对于 JSON.stringify 的介绍 三、…...
![](https://img-blog.csdnimg.cn/direct/9bbf2b7f2015472fafa4cf1be7209092.png)
模式分解的概念(下)-无损连接分解的与保持函数依赖分解的定义和判断、损失分解
一、无损连接分解 1、定义 2、检验一个分解是否是无损连接分解的算法 输入与输出 输入: 关系模式R(U,F),F是最小函数依赖集 R上的一个分解 输出: 判断分解是否为无损连接分解 (1&#x…...
![](https://www.ngui.cc/images/no-images.jpg)
vue3父组件获取子组件的实例对象
一,ref 在父组件的模板里,对子组件的标签定义ref属性,并且设置属性值,在方法里获取ref()获取实例对象。 父组件: <template><div ><div>我是父组件</div><<SonCom ref"sonComRe…...
![](https://img-blog.csdnimg.cn/direct/dc5e76d30d1d485c9fe4a94ac41eabc1.png)
主流框架选择:React、Angular、Vue的详细比较
目前前端小伙伴经常使用三种广泛使用的开发框架:React、Angular、Vue - 来设计网站 Reactjs:效率和多功能性而闻名 Angularjs:创建复杂的应用程序提供了完整的解决方案,紧凑且易于使用的框架 Vuejs:注重灵活性和可重用…...
![](https://www.ngui.cc/images/no-images.jpg)
交易者的意义是什么?
按照阿德勒的说法:人生的意义就是为社会创造价值,推动整个人类社会的发展进步。 我认同且秉持这种观点。 而在交易中,你是否直接或者间接为社会做贡献了呢?这个还真不好说。 但是做为职业交易者,你的存在价值&#…...
![](https://www.ngui.cc/images/no-images.jpg)
io_uring
转:[译] Linux 异步 I_O 框架 io_uring:基本原理、程序示例与性能压测(2020) 新一代异步IO框架 io_uring | 得物技术 干翻 nio ,王炸 io_uring 来了 !!(图解史上最全&a…...
![](https://www.ngui.cc/images/no-images.jpg)
构建高并发Web应用:基于Gunicorn、Flask和Docker的部署指南
目录 一 理解基础组件 什么是Flask? 什么是Gunicorn? 什么是Docker? 二 环境准备 三 构建Flask应用 创建项目结构 编写Flask应用 app/views.py 四 使用Gunicorn部署Flask应用 配置Gunicorn Gunicorn配置文件 五 使用Docker进行容器化部署 编写Dockerfile 构建…...
![](https://www.ngui.cc/images/no-images.jpg)
【Ruby简单脚本02】双色球系统
# frozen_string_literal: true require date # 生成中奖号码的工具 # 红球 1-32 篮球 1-15 def create_num nums [] 6.times do while true num rand(1..32) unless nums.include?(num) nums << num break end end end blue rand(1..15) nums…...
![](https://img-blog.csdnimg.cn/direct/e75e3b51ab56474d8dea4e2c60f165ba.jpeg)
Netty ByteBuf 使用详解
文章目录 1.概述2. ByteBuf 分类3. 代码实例3.1 常用方法3.1.1 创建ByteBuf3.1.2 写入字节3.1.3 扩容3.1.2.1 扩容实例3.1.2.2 扩容计算新容量代码 3.1.4 读取字节3.1.5 标记回退3.1.6 slice3.1.7 duplicate3.1.8 CompositeByteBuf3.1.9 retain & release3.1.9.1 retain &a…...
![](https://img-blog.csdnimg.cn/img_convert/935d03ce589990e37d0de68d3378429c.png)
怎样去掉卷子上的答案并打印
当面对试卷答案的问题时,一个高效而简单的方法是利用图片编辑软件中的“消除笔”功能。这种方法要求我们首先将试卷拍摄成照片,然后利用该功能轻松擦除答案。尽管这一方法可能需要些许时间和耐心,但它确实为我们提供了一个可行的解决途径。 然…...
![](https://img-blog.csdnimg.cn/direct/d4906c5cbe8c49ada32a3c14ea12a602.png)
海思SS928/SD3403开发笔记1——使用串口调试开发板
该板子使用串口可以调试,下面是win11 调试 该板子步骤 1、给板子接入鼠标、键盘、usb转串口 2、下载SecureCRT,并科学使用 下载地址: 链接:https://pan.baidu.com/s/11dIkZVstvHQUhE8uS1YO0Q 提取码:vinv 3、安装c…...
![](https://www.ngui.cc/images/no-images.jpg)
JSON数据操作艺术
在现代Web开发和数据交换场景中,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,扮演着至关重要的角色。它以易于阅读的文本形式存储和传输数据对象,而这些对象的核心便是由属性名(键&…...
![](https://img-blog.csdnimg.cn/direct/acd8f9ba1b4c42a6ac1af7d363c4fcc7.png#pic_center)
如何验证Rust中的字符串变量在超出作用域时自动释放内存?
讲动人的故事,写懂人的代码 在公司内部的Rust培训课上,讲师贾克强比较了 Rust、Java 和 C++ 三种编程语言在变量越过作用域时自动释放堆内存的不同特性。 Rust 通过所有权系统和借用检查,实现了内存安全和自动管理,从而避免了大部分内存泄漏。Rust 自动管理标准库中数据类…...
![](https://img-blog.csdnimg.cn/direct/aec88de42acf4a8187737f1ef73b9923.png)
55.Python pip install 安装失败的一个情况Requirement already satisfied
1.问题 以前使用Pycharm 社区版开发的一个项目,今天使用PyCharm 专业版打开,原项目的虚拟环境从venv更换为.venv,然后重新安装插件。安装时,提示Requirement already satisfied: qt_material in c:\tools\python37\lib\site-packa…...
![](https://img-blog.csdnimg.cn/direct/270f7739658546569b97c073db23d5dc.png)
Axios进阶
目录 axios实例 axios请求配置 拦截器 请求拦截器 响应拦截器 取消请求 axios不仅仅是简单的用基础请求用法的形式向服务器请求数据,一旦请求的端口与次数变多之后,简单的请求用法会有些许麻烦。所以,axios允许我们进行创建axios实例、ax…...
![](https://www.ngui.cc/images/no-images.jpg)
C++ 丑数
描述 把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第 n个丑数。 数据范围:0≤𝑛≤20000≤n≤…...
![](https://www.ngui.cc/images/no-images.jpg)
小山菌_代码随想录算法训练营第三十天|122.买卖股票的最佳时机II、55. 跳跃游戏 、45.跳跃游戏II、1005.K次取反后最大化的数组和
122.买卖股票的最佳时机II 文档讲解:代码随想录.买卖股票的最佳时机II 视频讲解:贪心算法也能解决股票问题!LeetCode:122.买卖股票最佳时机II 状态:已完成 代码实现 class Solution { public:int maxProfit(vector<…...
![](https://img-blog.csdnimg.cn/direct/42a59a22362b4abab28dd106610d56cc.gif#pic_center)
SpringMVC系列七: 手动实现SpringMVC底层机制-上
手动实现SpringMVC底层机制 博客的技术栈分析 🛠️具体实现细节总结 🐟准备工作🍍搭建SpringMVC底层机制开发环境 实现任务阶段一🍍开发ZzwDispatcherServlet🥦说明: 编写ZzwDispatcherServlet充当原生的DispatcherSer…...
![](https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8)
嵌入式web 服务器boa的编译和移植
编译环境:虚拟机 ubuntu 18.04 目标开发板:飞凌OKA40i-C开发板, Linux3.10 操作系统 开发板本身已经移植了boa服务器,但是在使用过程中发现POST方法传输大文件时对数据量有限制,超过1M字节就无法传输,这是…...
![](https://www.ngui.cc/images/no-images.jpg)
什么是js?特点是什么?组成部分?
Js是一种直译式脚本语言,一种动态类型,弱类型,基于原型的高级语言。 直译式:js程序运行过程中直接编译成机器语言。 脚本语言:在程序运行过程中逐行进行解释说明,不需要预编译。 动态类型:js…...
![](https://www.ngui.cc/images/no-images.jpg)
Java 面试题:如何保证集合是线程安全的? ConcurrentHashMap 如何实现高效地线程安全?
在多线程编程中,保证集合的线程安全是一个常见而又重要的问题。线程安全意味着多个线程可以同时访问集合而不会导致数据不一致或程序崩溃。在 Java 中,确保集合线程安全的方法有多种,包括使用同步包装类、锁机制以及并发集合类。 最简单的方法…...
![](/images/no-images.jpg)
做ppt图表的网站/种子资源地址
参考资料: https://www.cnblogs.com/kumufengchun/p/10384325.html https://www.kancloud.cn/hello123/beego/126138...
![](/images/no-images.jpg)
国外做宠物产品的网站/百度查一下
冈萨雷斯版<图像处理>里面的解释非常形象:一个恰当的比喻是将傅里叶变换比作一个玻璃棱镜。棱镜是可以将光分解为不同颜色的物理仪器,每个成分的颜色由波长(或频率)来决定。 傅里叶变换可以看作是数学上的棱镜,将…...
![](https://img-blog.csdnimg.cn/img_convert/628a76026f26a9b0192a8fa75416b71f.png)
电器类网站设计/跨境电商培训机构哪个靠谱
云服务器打补丁 内容精选换一换本节操作介绍Linux操作系统云服务器使用重新挂载系统盘的方式重置密码的操作步骤。本文档适用于X86架构的CentOS 7、Ubuntu、EulerOS操作系统云服务器。进入单用户模式下重置root密码前请先做好数据备份。已经准备一台Linux操作系统的临时弹性云服…...
![](https://img2018.cnblogs.com/blog/573911/201907/573911-20190709173512174-1131800883.png)
网站建设合同附加协议/百度西安分公司地址
1.Configuration有什么用? configuration 2.Spring是如何获取Bean的定义的? 1):通过启动一个AnnotationConfigApplicationContext 来引导这个Configuration 注解的类,比如: AnnotationConfigApplicationCo…...
![](https://img-blog.csdnimg.cn/img_convert/45680244238c50610865765d0dcbf0a6.gif)
wordpress 手机 菜单/营销型网站设计制作
Public Broadcasting Service (PBS) 希望构建一个智能推荐引擎(SRE,Smart Recommendation Engine),使其能够根据多种因素向观众提供高质量的推荐内容。Public Broadcasting Service (PBS) :https://www.pbs.org/ 为了确…...
![](/images/no-images.jpg)
网站群怎么做/宁波seo网络推广报价
在Ubuntu中备份svn上传的代码,将备份的文件命名为svn_backup当前时间.dump文件(例svn_backup20100525.dump)1.编写脚本文件(backup.sh)sudo touch backup.sh创建脚本文件,并编辑文件sudo vim backup.sh上图为配置的文件内容,代码如下…...