使用哈希表(散列表)+顺序二叉树实现电话簿系统(手把手讲解)

介绍相关概念

哈希表:

也称哈希映射(hash map)或者散列表,是根据关键码值(key value)而直接进行访问的数据结构。它通过计算一个散列函数,将关键码值映射到表中一个位置,以实现直接访问存储在该位置的数据,大大提高查找的效率。

顺序二叉树

顺序二叉树(Binary Search Tree,BST)是一种特殊的二叉树数据结构。它具有以下特征:

  • 顺序二叉树是一个二叉树,每个节点最多有两个子节点(左子节点和右子节点)。

  • 若任意节点的左子节点不为空,则左子节点的值必须小于该节点的值;

  • 若任意节点的右子节点不为空,则右子节点的值必须大于该节点的值;

  • 任意节点的左、右子树也必须是顺序二叉树。

也就是说,顺序二叉树的任意节点的值都大于其左子树上所有节点的值,小于其右子树上所有节点的值。查找过程就相当于二分查找

链表

是一种线性存储结构

实现思路如下图

实现大体思路

存储结构

对于普通用户,如果用户过多我们可以使用哈希表+顺序二叉树去查找 存储结构如下

 思路讲解

1.对于初始化

        *要考虑初始化的时候要不要顺便读取文件内容然后打印

2.增删改查

        *对于增加用户,因为我们使用的是hash表,所以需要主键,就要考虑主键重复问题(我使用名字             当主键)

注意:我们在输入字符或者字符串时候呢肯定会出现多输入字符比如空格或者回车或者多输入了需对字符,所以我们要是使用getchar的话只能解决前两种问题,无法解决第三中问题,所以我提供一种思路,我们可以声明一个 字符串来当做缓冲区,把所有多余的字符读取进去,然后最后使用 memset 释放掉

eg

//充当缓冲区char buffer[1000];printf("请输入你想删除的联系人姓名:\n");scanf("%10s", name);gets_s(buffer);memset(buffer, 0, sizeof(buffer));
// 0代表从第一个位置开始删除,sizeof(buffer)代表删除到最后

这样呢就可以解决缓冲区的问题 

        *删除用户的话,因为我们有特别关心用户,所以呢,要保证删除掉普通用户的同时会删除特别关心用户,删除特别关心用户并不会影响普通用户 还有就是顺序二叉树的删除

        *修改用户就要保证在修改普通用户的同时又修改为特别关心用户的

        *查找就比较简单,但是查找还有在排重中使用,只需要注意没有用户时的查找处理.

3.打印信息

        1.在终端对用户打印

                注意二叉树的顺序打印,还有美化一下打印界面,比如带上索引

        2.向文件中打印存储的信息,要注意打印格式方便读取,比如每种信息使用'#'隔开

                注意小细节,因为姓名是关键字,所以我们存储特别关心用户时,我们可以只存储名字,打印时候只需要调用查找函数即可调用其他信息

 4.读取信息

        根据存储的格式去读取

5.实现注意

        头文件的使用,了解头文件的概念

        特别要注意删除时候,对于地址的传参,会造成指针异常

实现开始

一定要在一个工程文件里面!!!!!

头文件 来声明使用的头文件+存储结构+函数声明

#ifndef AddressBookTools
#define AddressBookTools
#define MaxNum 27 //一共26个首字母
const int INFOEMATIONNUMS =  3;
const int  MaxPhone = 20;#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/* 使用二叉排序树 + 哈希表创建通讯录*/
typedef char keyName[11];//名字
typedef char  Number[12];//电话号码
typedef char Sex;//性别/*人物信息*/
typedef struct  InforNode{keyName name;//名字Number num[MaxPhone];//电话号Sex sex;//性别/*......等等多个信息*/
}Information;/*顺序二叉树的存储结构*/
typedef struct BSTNode {Information information;struct BSTNode* lchild, * rchild;//左右孩子
}BSTNode,*BSTree;
/*哈希表结构*/
typedef struct HashNode {BSTree T;
}*HashTable,HashNode;
/*存储特别关心*/
typedef struct Node {Information information;struct Node* next;
}Node,*List;//初始化功能
//=====================================================
//创建新的电话簿
void CreatHT(HashTable &H);//创建一个Hash表并复制NULL
//创建特别关心列表
void CreatL(List& L);
//=====================================================//辅助函数
//=====================================================
//哈希函数
int Hash(keyName name);
//计算名字字符大小之和
int NameSum(keyName name);
//判断两个关键字是否相同 相同返回 1 不同返回 0
int equals(keyName name1, keyName name2);
//=====================================================//插入信息功能  插入特别关心人
//=====================================================
//插入普通用户
Information InputInformation();//输入信息并返回输入后的节点
void InsertHT(HashTable &H);//在表里插入信息
//哈希表中的排序二叉树
void InsertBST(BSTree& T,Information E);//插入特别关心人
void InsertLike(List& L, HashTable& H, keyName name);
//=====================================================//打印信息
//=====================================================
//在终端打印普通用户信息
void PrintHT(HashTable H,List L);
void PrintTree(BSTree T);
//在终端打印特别关心用户信息
void PrintLike(List L);
//在文件打印信息
void PrintfLike(List L, FILE* fLike);
void PrintFile(HashTable H,FILE* f);
void PrintTreeF(BSTree T,FILE* f);
//=====================================================//从文件中读取信息
//=====================================================
void ReadFile(FILE* f, FILE* fLike, HashTable& H, List& L);
//=====================================================//删除某顶点
//=====================================================
//定位在哈希表的某个位置
void DeleteHT(HashTable& H, keyName name);
//删除二叉树的节点
void DeleteBST(BSTree& T, keyName name);
//删除链表节点
void DeleteList(List& L, keyName name);
//=====================================================//查找联系人 等修改联系人信息
//=====================================================
//查找指定联系人的节点
BSTree Search(HashTable H, keyName name);
//查找链表中指定联系人
List SearchL(List L, keyName naem);
//修改指定联系人节点的信息
void Modify(HashTable& H,List &L, keyName name);
//=====================================================//打印用户界面
int OperateMenu();
#endif // !AddressBookTools

第一个 .cpp文件用来实现头文件中函数

#define _CRT_SECURE_NO_WARNINGS 1
#include "AddressBookTools.h"/*创建功能*/
void CreatHT(HashTable &H) {  //创建初始化哈希表H = (HashNode*)malloc(sizeof(HashNode) * MaxNum);if (H == NULL) exit(-1);//申请失败退出程序for (int i = 0; i < MaxNum; ++i) {H[i].T = NULL;}
}
void CreatL(List& L) {L = (Node*)malloc(sizeof(Node));if (L == NULL) {printf("申请内存失败!\n");exit(-1);}L->next = NULL;L->information = {};
}
int Hash(keyName name) {if(name[0]>='a'&&name[0]<='z')return (name[0]-97) % (MaxNum-1);if (name[0] >='A' && name[0] <= 'Z')return (name[0] - 65) % (MaxNum-1);return 26;
}
/*关键字的每一个Ascll码之和作为权值*/
int NameSum(keyName name) {int sum=0;for(int i=0;name[i]!='\0';++i){sum += name[i];}return sum;
}
int equals(keyName name1, keyName name2) {int count = 0;if (sizeof(name1) != sizeof(name2))return 0;while (name1[count] != '\0' || name2[count] != '\0') {if (name1[count] != name2[count])return 0;count++;}return 1;
}/*插入功能*/
//插入普通用户
Information InputInformation() {//要对E进行初始化,要不然会产生地址访问冲突Information E = { {},{}, ' '
};for (int i = 0; i < MaxPhone; ++i) {strcpy(E.num[i], " ");}//充当缓冲区char buffer[1000];printf("请输入联系人姓名\n");scanf("%10s", E.name);gets_s(buffer);printf("你要输入电话和姓名吗? -1 要,-0不要\n");int choice = 0;scanf("%d", &choice);gets_s(buffer);int nums = 0;switch (choice){input :case 1:printf("你想输入多少个号码(最多十个)?\n");scanf("%d", &nums);if (nums > MaxPhone) {printf("数量过多!\n");goto input;}gets_s(buffer);for (int i = 0; i < nums; ++i) {printf("请输入联系人电话号(11个数字)\n");scanf("%11s", E.num[i]);gets_s(buffer);}printf("请输入联系人的性别(一个字母 M:男性,W:女性)\n");scanf("%c", &E.sex);gets_s(buffer);default:break;}//清理缓存区memset(buffer, 0, sizeof(buffer));return E;
}
void InsertHT(HashTable& H) {Information E = InputInformation();BSTree p = Search(H, E.name);if (p != NULL) {printf("名字与电话簿已存在!\n插入失败\n");return;}//调用哈希函数 获取存储的位置int index = Hash(E.name);//存入对应位置//如果该位置为空则T指向新节点InsertBST(H[index].T,E);printf("插入成功!\n");
}
void InsertBST(BSTree& T,Information E) {if (T == NULL) {BSTree node = (BSTNode*)malloc(sizeof(BSTNode));if (node == NULL)exit(0);node->information = E;node->lchild = NULL;node->rchild = NULL;T = node;}else {//把名字的字母和作为关键字计算权值大小int weightNew = NameSum(E.name);int weightOld = NameSum(T->information.name);if (weightNew <= weightOld) {InsertBST(T->lchild, E);}else if(weightNew>=weightOld){InsertBST(T->rchild, E);}}}
//插入特别关心用户
void InsertLike(List& L,HashTable &H,keyName name) {BSTree T = Search(H,name);if (T == NULL) {printf("没有该用户!\n");return;}if (SearchL(L, name) != NULL) {printf("该用户已存在!\n");return;}List nexttemp = (Node*)malloc(sizeof(Node));if (nexttemp == NULL) {printf("申请内存失败!\n");exit(-1);}List p = L;//遍历到最后while (p->next != NULL) {p = p->next;}nexttemp->information = T->information;p->next = nexttemp;nexttemp->next = NULL;
}/*打印功能*/
void PrintTree(BSTree T) {if (T == NULL) return;//中序遍历 从小到大遍历PrintTree(T->lchild);printf("||姓名:%s\t||",T->information.name);printf("电话:||");for (int i = 0; i<MaxPhone; ++i) {if(strcmp(T->information.num[i], " ") != 0)printf("%s\t||", T->information.num[i]);}printf("性别:%c||\n", T->information.sex);PrintTree(T->rchild);
}
void PrintHT(HashTable H,List L) {printf("**************************************************************************************************************************************************\n");printf("特别关心\n");PrintLike(L);printf("**************************************************************************************************************************************************\n");for (int i = 0; i < MaxNum-1; ++i) {if (H[i].T != NULL) {printf("==================================================================================================================================================\n");printf("||索引:%c||\n",'a'+i);printf("==================================================================================================================================================\n");PrintTree(H[i].T);}}if (H[MaxNum - 1].T != NULL) {printf("===============================================================================================================================================\n");printf("||索引:%c||\n", '#');printf("===============================================================================================================================================\n");PrintTree(H[MaxNum-1].T);}printf("==================================================================================================================================================\n");
}
void PrintLike(List L) {List p = L->next;while (p != NULL) {printf("||姓名:%s\t||", p->information.name);printf("电话:||");for (int i = 0; i < MaxPhone; ++i) {if (strcmp(p->information.num[i], " ") != 0)printf("%s\t||", p->information.num[i]);}printf("性别:%c||\n", p->information.sex);p = p->next;}
}
void PrintTreeF(BSTree T,FILE* f) {if (T == NULL) return;//中序遍历 从小到大遍历PrintTreeF(T->lchild,f);fprintf(f,"%s#", T->information.name);for (int i = 0; i<MaxPhone; ++i) {fprintf(f, "%s#", T->information.num[i]);}fprintf(f,"%c\n", T->information.sex);PrintTreeF(T->rchild,f);
}
void PrintFile(HashTable H,FILE* f) {f = fopen("AddressBook.txt", "w");for (int i = 0; i < MaxNum; ++i) {if (H[i].T != NULL) {PrintTreeF(H[i].T,f);}}fclose(f);
}
void PrintfLike(List L, FILE* fLike) {fLike = fopen("like.txt", "w");List p = L->next;while (p != NULL) {fprintf(fLike,"%s\n", p->information.name);p = p->next;}fclose(fLike);
}
/*读取存储的用户文件功能*/
void ReadFile(FILE* f, FILE* fLike, HashTable& H, List& L) {f = fopen("AddressBook.txt", "r");fLike = fopen("like.txt", "r");if (f == NULL) {printf("不存在该文件!\n");return;}if (fLike == NULL) {printf("不存在该文件!\n");return;}char str[1000];char* strMode = NULL;int countStr = 0;int countInformation = 0;while (fgets(str, 1000, f)) {Information* e = (Information*)malloc(sizeof(Information));/*strtok 切割函数*/strMode = strtok(str, "#");int index = Hash(strMode);strcpy(e->name, strMode);for (int i = 0; i < MaxPhone; ++i) {strMode = strtok(NULL, "#");strcpy(e->num[i], strMode);}strMode = strtok(NULL, "#");e->sex = strMode[0];InsertBST(H[index].T, *e);}while (fgets(str, 1000, fLike)) {int index = Hash(str);strMode = strtok(str, "\n");InsertLike(L, H, str);}fclose(f);fclose(fLike);
}/*删除功能*/
void DeleteHT(HashTable& H, keyName name) {int index = Hash(name);if (!H[index].T) {printf("没有该联系人\n");return;}DeleteBST(H[index].T, name);
}
void DeleteBST(BSTree& T, keyName name) {//从二叉树排序树T中删除为name的节点BSTree p = T;BSTree f = NULL;//初始化/*-----------使用while循环从跟找关键字-----------*/while (p) {if (equals(p->information.name, name)) break;f=p;//f为p的双亲节点if (NameSum(p->information.name) >= NameSum(name)) {p = p->lchild;}else {p = p->rchild;}}if (p == NULL) {				//没有找到该元素printf("没有该元素\n");return;}/*---- 考虑3种情况实现p所指子树内部的处理: p 的左右子树均不为空,无右子树,无左子树*/BSTree q = p;if ((p->lchild) && (p->rchild)) {BSTree s = p->lchild;while (s->rchild) {  //向右到尽头q = s;s = s->rchild;}p->information = s->information;if (q != p) q->rchild = s->lchild; //重接右子树else q->lchild = s->lchild;  //重接左子树free(s);return;}else if (!p->rchild) {p = p->lchild;}else if (!p->lchild) {p = p->rchild;}/*-----------将p所指的子树挂接到其双亲节点 f的相应位置---------------*/if (!f) T = p;							//被删除节点为根节点else if (q == f->lchild) f->lchild = p; //挂接到左子树else f->rchild = p;						//挂接到右子树free(q);printf("删除成功!\n");
}
void DeleteList(List& L, keyName name) {List prev = NULL;List p = L;//处理头节点的情况if (p && equals(p->information.name, name)) {L = p->next;free(p);printf("删除成功!\n");return;}//循环找节点while (p != NULL) {if (equals(p->information.name, name)) {if (prev == NULL) { //头节点L = p->next;}else {prev->next = p->next;}free(p);printf("删除成功!\n");return;}prev = p;p = p->next;}printf("无该元素!\n");return;
}/*查找,修改功能*/
BSTree Search(HashTable H, keyName name) {int index = Hash(name);if (!H[index].T) {return NULL;}BSTree p = H[index].T;/*-----------使用while循环从跟找关键字-----------*/while (p) {if (equals(p->information.name, name)) {		 return p;}if (NameSum(p->information.name) >= NameSum(name)) {p = p->lchild;}else {p = p->rchild;}}if (p == NULL) {				//没有找到该元素return NULL;}
}
List SearchL(List L, keyName name) {List p = L->next;while (p) {if (equals(p->information.name, name)) {return p;}p = p->next;}return NULL;
}
void Modify(HashTable& H, List& L, keyName name) {int index = Hash(name);if (!H[index].T) {printf("无此人信息\n");return ;}BSTree p = Search(H, name);if(p==NULL) {printf("无此人信息\n");return;}/*-----------修改电话号,性别,姓名---------*//*姓名牵扯关键字,所以我们需要重新进行排序插入*/int choice = 0;int choice2 = 0;printf("-------------修改选项----------------\n");printf("-------------1.姓名------------------\n");printf("-------------2.电话号----------------\n");printf("-------------3.性别------------------\n");printf("-------------4.退出------------------\n");scanf("%d", &choice);getchar();char buffer[1000];char newname[11];char newnum[12];char newsex = '0';int index2 = 0;int count = 0;switch (choice){//修改姓名case 1:printf("请输入你想修改的新姓名:\n");scanf("%10s", newname);gets_s(buffer);Information newnode;strcpy(newnode.name, newname);for (int i = 0;i<MaxPhone; ++i) {strcpy(newnode.num[i], p->information.num[i]);}newnode.sex = p->information.sex;//删除旧的  插入新的index = Hash(newname);DeleteHT(H, name);InsertBST(H[index].T, newnode);//更新链表状态DeleteList(L, name);InsertLike(L,H,newname);printf("修改成功!\n");break;//电话号修改case 2:printf("你想修改还是删除? -0 修改 -1删除 -2添加\n");scanf("%d", &choice2);gets_s(buffer);switch (choice2){case 0:printf("你想修改第几个电话?\n");scanf("%d", &index2);gets_s(buffer);if (strcmp(p->information.num[index2-1], " ") == 0) {printf("改电话不存在\n");break;}printf("请输入联系人电话号(11个数字)\n");scanf("%11s", newnum);strcpy(p->information.num[index2 - 1], newnum);gets_s(buffer);//更新特别关心列表DeleteList(L, name);InsertLike(L, H, name);break;case 1:printf("请输入你想删除的第几个电话?\n");scanf("%d", &index2);gets_s(buffer);if (strcmp(p->information.num[index2-1], " ") == 0) {printf("改电话不存在\n");break;}for (int i = index2; i < MaxPhone; ++i) {strcpy(p->information.num[i- 1], p->information.num[i]);}printf("删除成功!\n");//更新特别关心列表DeleteList(L, name);InsertLike(L, H, name);break;case 2:printf("输入你想添加的电话号\n");printf("请输入联系人电话号(11个数字)\n");scanf("%11s", newnum);gets_s(buffer);count = 0;for (int i = 0; i < MaxPhone; ++i) {count++;if (strcmp(p->information.num[i], " ") == 0) {strcpy(p->information.num[i], newnum);break;}	}if (count == MaxNum - 1) {printf("电话存储空间已经满了\n");break;}printf("添加成功!\n");//更新特别关心列表DeleteList(L, name);InsertLike(L, H, name);break;default:return;}break;//性别case 3:printf("请输入联系人的性别(一个字母 M:男性,W:女性)\n");scanf("%c", &newsex);p->information.sex = newsex;gets_s(buffer);//更新特别关心列表DeleteList(L, name);InsertLike(L, H, name);break;default:break;}//清理缓存区memset(buffer, 0, sizeof(buffer));
}/*用户界面*/
int OperateMenu() {int choice;printf("===========================================================\n");printf("||<<<<<<<<<<<<<<<<<<<<<1.创建哈希表>>>>>>>>>>>>>>>>>>>>>>||\n");printf("||<<<<<<<<<<<<<<<<<<<<<2.插入联系人>>>>>>>>>>>>>>>>>>>>>>||\n");printf("||<<<<<<<<<<<<<<<<<<<<<3.打印>>>>>>>>>>>>>>>>>>>>>>>>>>>>||\n");printf("||<<<<<<<<<<<<<<<<<<<<<4.删除指定联系人信息>>>>>>>>>>>>>>||\n");printf("||<<<<<<<<<<<<<<<<<<<<<5.查找指定联系人>>>>>>>>>>>>>>>>>>||\n");printf("||<<<<<<<<<<<<<<<<<<<<<6.修改指定联系人信息>>>>>>>>>>>>>>||\n");printf("||<<<<<<<<<<<<<<<<<<<<<7.信息存入文件中>>>>>>>>>>>>>>>>>>||\n");printf("||<<<<<<<<<<<<<<<<<<<<<8.添加特别关心>>>>>>>>>>>>>>>>>>>>||\n");printf("||<<<<<<<<<<<<<<<<<<<<<9.删除特别关心>>>>>>>>>>>>>>>>>>>>||\n");printf("||<<<<<<<<<<<<<<<<<<<<<输入其他.退出>>>>>>>>>>>>>>>>>>>>>||\n");printf("===========================================================\n");scanf("%d", &choice);getchar();//吞掉回车return choice;
}

第二个 .cpp文件来写主函数mian

#define _CRT_SECURE_NO_WARNINGS 1
#include "AddressBookTools.h"
int main() {HashTable H=NULL;List L = NULL;CreatHT(H);//接受的选项int choice = 0;//修改姓名char name[11] = { 0 };//树节点BSTree p = NULL;int nums = 0;//存储用户文件指针FILE* f=NULL;//存储特别关心用户指针FILE* fLike = NULL;//充当缓冲区char buffer[1000];while (true){choice = OperateMenu();switch (choice){case 1:CreatHT(H);CreatL(L);//读取文件ReadFile(f,fLike, H,L);printf("创建成功!\n");PrintHT(H,L);break;//--------------------------------------------case 2:if (H == NULL) {printf("该哈希表未被初始化!\n");break;}nums = 0;printf("你想插入几个联系人:\n");scanf("%d", &nums);getchar();for (int i = 0; i < nums; ++i)InsertHT(H);PrintHT(H,L);PrintFile(H, f);break;//--------------------------------------------case 3:if (H == NULL) {printf("该哈希表未被初始化!\n");break;}PrintHT(H,L);break;//--------------------------------------------case 4:if (H == NULL) {printf("该哈希表未被初始化!\n");break;}printf("请输入你想删除的联系人姓名:\n");scanf("%10s", name);gets_s(buffer);DeleteHT(H, name);DeleteList(L, name);PrintfLike(L, fLike);PrintFile(H, f);break;//--------------------------------------------case 5:if (H == NULL) {printf("该哈希表未被初始化!\n");break;}printf("请输入你想查找的联系人姓名:\n");scanf("%10s", name);gets_s(buffer);p = Search(H, name);if (p == NULL)printf("查找不到该元素\n");printf("||姓名:%s\t||", p->information.name);printf("电话:%s\t||", p->information.num);printf("性别:%c||\n", p->information.sex);break;//--------------------------------------------case 6:if (H == NULL) {printf("该哈希表未被初始化!\n");break;}printf("请输入你想修改的联系人姓名:\n");scanf("%10s", name);gets_s(buffer);Modify(H,L, name);PrintFile(H, f);break;//--------------------------------------------case 7:if (H == NULL) {printf("该哈希表未被初始化!\n");break;}PrintFile(H, f);break;case 8:printf("请输入你想加入的姓名\n");scanf("%10s", name);gets_s(buffer);InsertLike(L, H, name);PrintHT(H, L);PrintfLike(L, fLike);break;case 9:printf("请输入你想删除的姓名\n");scanf("%10s", name);gets_s(buffer);DeleteList(L, name);PrintHT(H, L);PrintfLike(L, fLike);break;default:return 0;}memset(buffer, 0, sizeof(buffer));}}

资源文件

创建 Addressbook.txt与like.txt文件来存储读入的文件,

1.如果都在一个项目我们只需要在fopen()函数里面输入文件名,即相对路径,

2.如果在文件外,我们就要输入全部路径又称绝对路径

运行结果

 具体操作呢你们可以自己去使用,

总结:

本次实验使用了  哈希表,顺序二叉树,链表存储结构,实现了相关的算法,有不足的地方可以评论区或者私聊本人指出错误

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

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

相关文章

Linuxapache安装

Apache 介绍 Apache HTTP Server&#xff08;简称Apache&#xff09;是Apache软件基金会的一个开放源码的网页服务器&#xff0c;Apache是世界使用排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上&#xff0c;由于其跨平台和安全性被广泛使用&#xff0…

『OPEN3D』1.1 点云处理

目录 1.open3d中的点云IO 2.点云的可视化 3 点云voxel下采样 4. 顶点法线估计 5.最小外界矩 6. 凸包计算 7. 点云距离计算 8. DBSCAN clustering聚类 9. RANSAC(Random Sample Consensus) 10. 点云平面分割 11. 隐藏点移除 12.outliers移除 13 最远点采样&#xf…

【OAuth2】:赋予用户控制权的安全通行证--原理篇

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于OAuth2的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.什么是OAuth? 二.为什么要用OAuth?…

BUG记录 | 注册功能报错:Data too long for column ‘sex‘ at row 1

项目场景 SpringBootVue 前后端分离的项目&#xff0c;在实现前后端交互&#xff08;注册功能&#xff09;时出现报错 问题描述 点击注册按钮后显示服务异常 报错提示 org.springframework.dao.DataIntegrityViolationException: ### Error updating database. Cause: …

Unity | HybridCLR 热更新(Windows端)

目录 一、准备工作 1.环境相关 2.Unity中配置 二、热更新 1.创建 HotUpdate 热更新模块 2.安装和配置HybridCLR 3.配置PlayerSettings 4.创建热更新相关脚本 5.打包dll 6.测试热更新 一、准备工作 1.环境相关 安装git环境。Win下需要安装visual studio 2019或更高版…

【Git】fatal: bad boolean config value ‘true~‘ for ‘core.longpaths‘

windwos操作系统git config设置错了参数值&#xff0c;解决方法。 出现原因 在拉取代码时&#xff0c;仓库中存在文件名过长得文件&#xff0c;拉取报错了“filename too long” 解决 git config --system core.longpaths true结果在复制命令时&#xff0c;粘贴到命令行多了一…

Redis-实践知识

转自极客时间Redis 亚风 原文视频&#xff1a;https://u.geekbang.org/lesson/535?article681062 Redis最佳实践 普通KEY Redis 的key虽然可以自定义&#xff0c;但是最好遵循下面几个实践的约定&#xff1a; 格式&#xff1a;[业务名称]:[数据名]:[id] 长度不超过44字节 不…

Go 随机密码

一.Go实现随机密码 随机密码 package mainimport ("fmt""math/rand""os""strconv""time" )func RandomPassword(num int) {length : numif len(os.Args) > 1 {arg : os.Args[1]i, err : strconv.ParseInt(arg, 10, 6…

全方位掌握卷积神经网络:理解原理 优化实践应用

计算机视觉CV的发展 检测任务 分类与检索 超分辨率重构 医学任务 无人驾驶 整体网络架构 卷积层和激活函数&#xff08;ReLU&#xff09;的组合是网络的核心组成部分 激活函数(ReLU&#xff09; 引入非线性&#xff0c;增强网络的表达能力。 卷积层 负责特征提取 池化层…

双十一邮件群发最佳时间:提升营销效果与转化率的关键节点

如今&#xff0c;随着电子商务领域的兴起&#xff0c;电子邮件群发已经成为一种广泛的营销手段。在我国电子商务行业嘉年华双十一&#xff0c;挑选群发邮件的时间对营销效果至关重要。本文将探讨双十一电子商务节上群发邮件的最佳时期&#xff0c;助力企业运用群发邮件更好地提…

如何利用PPT绘图并导出清晰图片

在写论文的过程中&#xff0c;免不了需要绘图&#xff0c;但是visio等软件绘图没有在ppt上绘图比较熟练&#xff0c;尤其流程图结构图. 但是ppt导出的图片也不够清晰&#xff0c;默认分辨率是96dpi&#xff0c;而杂志投稿一般要求至300dpi。解决办法如下&#xff1a; 1.打开注…

深入探讨DNS数据包注入与DNS中毒攻击检测 (C/C++代码实现)

DNS数据包注入和DNS中毒攻击是网络安全领域中的两个重要主题。DNS&#xff08;域名系统&#xff09;是互联网中的一项核心服务&#xff0c;负责将域名转换为与之相对应的IP地址。 DNS数据包注入是指攻击者通过篡改或伪造DNS请求或响应数据包来干扰或破坏DNS服务的过程。攻击者…