数据结构大作业——家谱管理系统(超详细!完整代码!)

目录

设计思路:

一、项目背景

二、功能分析

查询功能流程图: 

管理功能流程图: 

三、设计

四、实现

代码实现:

头文件

结构体

函数声明及定义

创建家谱树头结点

绘制家谱树(打印)

建立右兄弟

建立左孩子

建立孩子结点信息

查找x的孩子

查找祖先

添加孩子

添加兄弟

中序遍历

删除结点

主函数

完整代码:

调试分析及测试结果:

进入主界面

建立家谱

生成树

查询操作

删除操作

写在最后


设计思路:

一、项目背景

家谱是一种以表谱形式,记载一个以血缘关系为主体的家族世袭繁衍和重要人物事迹的特殊图书体裁。家谱是中国特有的文化遗产,是中华民族的三大文献(国史,地志,族谱)之一,属于珍贵的人文资料,对于历史学,民俗学,人口学,社会学和经济学的深入研究,均有其不可替代的独特功能。

经历了历朝历代的连年战乱和社会动荡,历史上传世的家谱几乎丧失殆尽,许多家族的世系也因此断了线、失了传。流传至今的古代家谱,大多是明清两代纂修。在我国明清时期,出现了专门替人伪造家谱世系的“谱匠”。 

本项目旨在完成一个家谱系统,并实现家谱树所需要的查找、插入、搜索和删除等相关功能。


二、功能分析

完成一个简易的家谱管理系统,主要包含了管理和查询两大功能。

首先允许用户进行家谱的创建并能简易的输出整个家谱。其次,还要具有查询某结点祖先和孩子的功能,同时为保证用户可以随时修改家谱,添加了完善孩子、完善兄弟和删除结点的功能。其中删除结点规则定义为:若有孩子,则孩子一并删去;若有兄弟,则保留兄弟。最后考虑到现实中用户中输入错误的情况,还要包括健壮性的检查。

查询功能流程图: 

管理功能流程图: 


三、设计

该程序具有明显的树形结构,故采用树作为数据结构。我们选择采用二叉树,每个结点包括三个域,具体为lchild,rbrother,data,分别用来存储孩子、兄弟和此结点的名称。

结点代码设计如下:

typedef struct Node

{

string data;

struct Node* lchild;//左孩子

struct Node* rbrother;//右兄弟

}SLNode;

void Initiate(SLNode** T)这个函数用来创建家谱树头结点

SLNode* Insertright(SLNode* arr, string x)这个函数用来建立右兄弟

SLNode* Insertleft(SLNode* arr, string x)这个函数用来建立左孩子

void input(SLNode* arr)这个函数用来输入结点的儿子的信息

void PrintTree(SLNode* T, int n)这个函数用来打印家谱树

void Searchchild(SLNode* T, string x,bool &flag)这个函数用来查找x的孩子,在树T中查找x是否存在,并用flag来标记

void SearchAncestor(SLNode* T, string x, bool& flag)这个函数用来查找x的祖先,在树T中查找x是否存在,并用flag来标记

void addChild(SLNode* T, string x, string t)这个函数用来添加孩子,在树T中找到x结点并把t加入其左孩子之中

void addBrother(SLNode* T, string x, string t)这个函数用来添加兄弟,在树T中找到x结点并把t加入其左孩子之中

void inOrder(SLNode* T, string x, bool& flag)这个函数中序遍历查找x是否存在,并用flag来标记

void deleteNode(SLNode* T, string x)这个函数用来解散结点x的家庭


四、实现

完善家谱功能流程图


代码实现:

头文件

#include<iostream>
#include<windows.h>
#include <stdio.h>
#include <stdlib.h>
#include<string>

结构体

typedef struct Node
{string data;struct Node* lchild;//左孩子 struct Node* rbrother;//右兄弟 
}SLNode;

函数声明及定义

void Initiate(SLNode** T);
SLNode* Insertright(SLNode* arr, string x);
SLNode* Insertleft(SLNode* arr, string x);
void input(SLNode* arr);
void PrintTree(SLNode* T, int n);
void Searchchild(SLNode* T, string x);
void SearchAncestor(SLNode* T, string x);
void addChild(SLNode* T, string x, string t);
void addBrother(SLNode* T, string x, string t);
void inOrder(SLNode* T, string x, bool& flag);
void deleteNode(SLNode* T, string x);
SLNode* p;

创建家谱树头结点

void Initiate(SLNode** T)
{*T = new SLNode;(*T)->lchild = NULL;(*T)->rbrother = NULL;
}

绘制家谱树(打印)

void PrintTree(SLNode* T, int n)
{int i, j;if (T){for (i = 0; i < n; i++) cout << "       " ;cout << T->data;cout << endl;//打印家谱时为左孩子n+1,整体向右推移一位,右兄弟依然是nPrintTree(T->lchild, n + 1);PrintTree(T->rbrother, n);}
}

建立右兄弟

SLNode* Insertright(SLNode* arr, string x)
{SLNode* m;if (arr == NULL) return NULL;if (arr->rbrother != NULL)  arr = arr->rbrother;m = new SLNode;m->data = x;m->rbrother = arr->rbrother;m->lchild = NULL;arr->rbrother = m;return arr->rbrother;
}

建立左孩子

SLNode* Insertleft(SLNode* arr, string x)
{SLNode* m;if (arr == NULL) return NULL;else if (arr->lchild == NULL)//为什么这里要判空?//因为有可能插入多个孩子,如果已经插入一个或多个了,就需要执行else块里的右兄弟函数往下递归找到空指针在插入 {//开始创建要插入的左孩子 m = new SLNode;//malloc无法为string分配正确内存,所以用newm->data = x;m->lchild = arr->lchild;//方便下次插入孩子结点 m->rbrother = NULL;arr->lchild = m;//孩子结点插入完成 return arr->lchild;}else{Insertright(arr->lchild, x);}
}

建立孩子结点信息

void input(SLNode* arr)
{string p;if (arr == NULL) return;cout << "请输入"<<arr->data<<"所有的儿子结点, 若没有儿子或者输完所有儿子,输入#即可:" << endl;cin >> p;while (p != "#"){Insertleft(arr, p);cin >> p;}//这个建立家谱的过程,为了防止输入混乱,先递归兄弟结点,再递归孩子结点 if (arr->rbrother != NULL)input(arr->rbrother);if (arr->lchild != NULL)input(arr->lchild);/*if (arr->rbrother != NULL )input(arr->rbrother);if (arr->lchild != NULL )input(arr->lchild);}

查找x的孩子

void Searchchild(SLNode* T, string x,bool &flag)
{SLNode* p;//要用T->data和x比较,所以要保证T不为空指针if (T != NULL && T->data != x){Searchchild(T->lchild, x,flag);Searchchild(T->rbrother, x,flag);}//加入限定条件只允许T->data==x时通过if (T != NULL && T->lchild != NULL && T->data == x){cout << T->data << "结点的儿子结点为:" << T->lchild->data << endl;p = T->lchild;while (p->rbrother != NULL)//右兄弟,找到一个儿子结点后去右子树找兄弟结点{cout << p->rbrother->data << endl;p = p->rbrother;}}
}

查找祖先

void SearchAncestor(SLNode* T, string x, bool& flag)//函数为找x的祖先 
{if (T != NULL && T->data != x)//如果T不为空并且data不是x {SearchAncestor(T->lchild, x, flag);//不断向下递归找左孩子 SearchAncestor(T->rbrother, x, flag);//右兄弟 }//保证p为不变的指针,指向选择的结点if (T != NULL && T->data == x)//T不为空并且已经找到了结点 {p = T;//此时的结点赋给p flag = true;//说明已经找到了 }//下面找p的祖先即可 ,T是p的祖先,可能T的左孩子就是了也可能是T的左孩子的兄弟 if (T != NULL && T->lchild != NULL && (T->lchild == p || T->lchild->rbrother == p))	{cout << "他的祖先结点为:" << T->data << endl;p = T;}
}

添加孩子

void addChild(SLNode* T, string x, string t)
{//考虑到现实生活中会有二胎三胎,这个函数的作用即为添加孩子添加孩子结点 if (T != NULL && T->data != x){addChild(T->lchild, x, t);addChild(T->rbrother, x, t);}if (T != NULL && T->data == x){p = T;Insertleft(p, t);//调用前面的插入左孩子函数进行添加 }
}

添加兄弟

void addBrother(SLNode* T, string x, string t)
{if (T != NULL && T->data != x){addBrother(T->rbrother, x, t); addBrother(T->lchild, x, t);}if (T != NULL && T->data == x){p = T;Insertright(p, t);return;}
}

中序遍历

void inOrder(SLNode* T, string x, bool& flag)//中序遍历
{if (T == NULL || flag == true) return;inOrder(T->lchild, x, flag);if (T->data == x){flag = true;//如果要完善的结点在家谱里,flag为真 return;}inOrder(T->rbrother, x, flag);
}

删除结点

void deleteNode(SLNode* T, string x)
{//先定义删除规则://如果有孩子,孩子一并删去,有兄弟则保留兄弟。if (T == NULL) return;//因为T为头结点,这里从T->lchild开始遍历if ( T->lchild != NULL && T->lchild->data == x){SLNode* p = T->lchild->lchild;free(p);//根据删除规则,孩子一并删除T->lchild = T->lchild->rbrother;//保留兄弟}if (T->rbrother != NULL && T->rbrother->data == x){SLNode* p = T->rbrother->lchild;free(p);//根据删除规则,孩子一并删除T->rbrother = T->rbrother->rbrother;//保留兄弟}deleteNode(T->lchild, x);deleteNode(T->rbrother, x);//先根再左在右,先序遍历的方式删除
}

主函数

int main()
{SLNode* T;string p;int n;Initiate(&T);do{system("color 75");cout << "                                                           " << endl;cout << "                        家谱管理系统                    " << endl;cout << "------------------------- 功能选项 -------------------------";cout << endl << endl;cout << "                    **  1-开始建立家谱  **" << endl;cout << "                    **  2-查询-家谱树   **" << endl;cout << "                    **  3-查询-儿子     **" << endl;cout << "                    **  4-查询-祖先     **" << endl;cout << "                    **  5-完善-孩子     **" << endl;cout << "                    **  6-完善-兄弟     **" << endl;cout << "                    **  7-删除-结点     **" << endl;cout << "                    **  0-退出系统      **" << endl;cout << endl << endl;cout << "------------------------------------------------------------";cout << endl;cout << "请选择需要的功能(数字) :";char ch;ch = getchar();switch (ch){case '1':{cout << "请输入祖先结点:" << endl;cin >> p;Insertleft(T, p);input(T->lchild); getchar(); break;};case '2':{cout << endl;PrintTree(T->lchild, 1); getchar(); break;};case '3':{bool flag_1 = false;//flag_1用来标记是否有孩子bool flag_2 = false;//flag_2用来标记家谱里是否有要查询的结点cout << "请输入要查询的结点" << endl;cin >> p;inOrder(T, p, flag_2);//inOrder(T, p, flag_1); while (!flag_2){cout << "您要查询的结点并不存在, 请重新输入:" << endl;cin >> p;inOrder(T, p, flag_2);}Searchchild(T, p,flag_1); //直接在此函数中输出getchar(); break;};case '4':{cout << "请输入要查询的结点:" << endl;cin >> p;bool flag = false;while (p == T->lchild->data)//T是头结点,祖先存储在T的lchild域里{cout << "这个结点为祖先,请重新输入:" << endl;cin >> p;}SearchAncestor(T->lchild, p, flag);while (flag == false){cout << "此结点不存在,请重新输入:" << endl;cin >> p;while (p == T->lchild->data)//T是头结点,祖先存储在T的lchild域里{cout << "这个结点为祖先,请重新输入:" << endl;cin >> p;}SearchAncestor(T->lchild, p, flag);}getchar(); break;};case '5':{bool flag = false;//flag用来标记要完善的结点是否在家谱里 cout << "请输入要完善的结点:" << endl;cin >> p;inOrder(T, p, flag);//查找结点是否在家谱里while (!flag){cout << "您要完善的结点并不存在, 请重新输入:" << endl;cin >> p;inOrder(T, p, flag);}cout << "要添加的孩子为:" << endl;string x;cin >> x;addChild(T, p, x); getchar(); break;};case '6':{bool flag = false;//flag用来标记要完善的结点是否在家谱里cout << "请输入要完善的结点:" << endl;cin >> p;inOrder(T, p, flag);//查找结点是否在家谱里while (!flag){cout << "您要完善的结点并不存在,请重新输入:" << endl;cin >> p;inOrder(T, p, flag);}cout << "要添加的兄弟为:" << endl;string x;cin >> x;addBrother(T, p, x); getchar(); break;}case '7':{bool flag = false;//标记要删除的结点是否在家谱里cout << "请输入要删除的结点:" << endl;cin >> p;inOrder(T, p, flag);//查找结点是否在家谱里while (!flag){cout << "您要删除的结点并不存在,请重新输入:" << endl;cin >> p;inOrder(T, p, flag);}deleteNode(T, p); getchar(); break;}case '0':{cout << " 感谢您的使用,下次再见!" << endl;exit(0);}default:{cout << "输入有误,请重新输入:" << endl;ch = getchar();}}} while (1);return 0;
}

完整代码:

#include<iostream>
#include<windows.h>
#include <stdio.h>
#include <stdlib.h>
#include<string>using namespace std;typedef struct Node
{string data;struct Node* lchild;//左孩子 struct Node* rbrother;//右兄弟 
}SLNode;//extern SLNode* p;void Initiate(SLNode** T);
SLNode* Insertright(SLNode* arr, string x);
SLNode* Insertleft(SLNode* arr, string x);
void input(SLNode* arr);
void PrintTree(SLNode* T, int n);
void Searchchild(SLNode* T, string x);
void SearchAncestor(SLNode* T, string x);
SLNode* p;void Initiate(SLNode** T)
{*T = new SLNode;(*T)->lchild = NULL;(*T)->rbrother = NULL;
}SLNode* Insertright(SLNode* arr, string x)
{SLNode* m;if (arr == NULL) return NULL;if (arr->rbrother != NULL)  arr = arr->rbrother;m = new SLNode;m->data = x;m->rbrother = arr->rbrother;m->lchild = NULL;arr->rbrother = m;return arr->rbrother;
}SLNode* Insertleft(SLNode* arr, string x)
{SLNode* m;if (arr == NULL) return NULL;else if (arr->lchild == NULL)//为什么这里要判空?//因为有可能插入多个孩子,如果已经插入一个或多个了,就需要执行else块里的右兄弟函数往下递归找到空指针在插入 {//开始创建要插入的左孩子 m = new SLNode;//malloc无法为string分配正确内存,所以用newm->data = x;m->lchild = arr->lchild;//方便下次插入孩子结点 m->rbrother = NULL;arr->lchild = m;//孩子结点插入完成 return arr->lchild;}else{Insertright(arr->lchild, x);}
}void input(SLNode* arr)
{string p;if (arr == NULL) return;cout << "请输入"<<arr->data<<"所有的儿子结点, 若没有儿子或者输完所有儿子,输入#即可:" << endl;cin >> p;while (p != "#"){Insertleft(arr, p);cin >> p;}//这个建立家谱的过程,为了防止输入混乱,先递归兄弟结点,再递归孩子结点 if (arr->rbrother != NULL)input(arr->rbrother);if (arr->lchild != NULL)input(arr->lchild);/*if (arr->rbrother != NULL )input(arr->rbrother);if (arr->lchild != NULL )input(arr->lchild);//这里是先递归兄弟节点,再递归孩子结点*/
}void PrintTree(SLNode* T, int n)
{int i, j;if (T){for (i = 0; i < n; i++) cout << "       " ;cout << T->data;cout << endl;//打印家谱时为左孩子n+1,整体向右推移一位,右兄弟依然是nPrintTree(T->lchild, n + 1);PrintTree(T->rbrother, n);}
}void Searchchild(SLNode* T, string x,bool &flag)//flag用来标记是否有孩子
{SLNode* p;//要用T->data和x比较,所以要保证T不为空指针if (T != NULL && T->data != x){Searchchild(T->lchild, x,flag);Searchchild(T->rbrother, x,flag);}//加入限定条件只允许T->data==x时通过if (T != NULL && T->lchild != NULL && T->data == x){cout << T->data << "结点的儿子结点为:" << T->lchild->data << endl;p = T->lchild;while (p->rbrother != NULL)//右兄弟,找到一个儿子结点后去右子树找兄弟结点{cout << p->rbrother->data << endl;p = p->rbrother;}}
}void SearchAncestor(SLNode* T, string x, bool& flag)//函数为找x的祖先 
{if (T != NULL && T->data != x)//如果T不为空并且data不是x {SearchAncestor(T->lchild, x, flag);//不断向下递归找左孩子 SearchAncestor(T->rbrother, x, flag);//右兄弟 }//保证p为不变的指针,指向选择的结点if (T != NULL && T->data == x)//T不为空并且已经找到了结点 {p = T;//此时的结点赋给p flag = true;//说明已经找到了 }//下面找p的祖先即可 ,T是p的祖先,可能T的左孩子就是了也可能是T的左孩子的兄弟 if (T != NULL && T->lchild != NULL && (T->lchild == p || T->lchild->rbrother == p)){cout << "他的祖先结点为:" << T->data << endl;p = T;}
}void addChild(SLNode* T, string x, string t)
{//考虑到现实生活中会有二胎三胎,这个函数的作用即为添加孩子添加孩子结点 if (T != NULL && T->data != x){addChild(T->lchild, x, t);addChild(T->rbrother, x, t);}if (T != NULL && T->data == x){p = T;Insertleft(p, t);//调用前面的插入左孩子函数进行添加 }
}
void addBrother(SLNode* T, string x, string t)
{if (T != NULL && T->data != x){addBrother(T->rbrother, x, t); addBrother(T->lchild, x, t);}if (T != NULL && T->data == x){p = T;Insertright(p, t);return;}
}
void inOrder(SLNode* T, string x, bool& flag)//中序遍历
{if (T == NULL || flag == true) return;inOrder(T->lchild, x, flag);if (T->data == x){flag = true;//如果要完善的结点在家谱里,flag为真 return;}inOrder(T->rbrother, x, flag);
}
void deleteNode(SLNode* T, string x)
{//先定义删除规则://如果有孩子,孩子一并删去,有兄弟则保留兄弟。if (T == NULL) return;//因为T为头结点,这里从T->lchild开始遍历if ( T->lchild != NULL && T->lchild->data == x){SLNode* p = T->lchild->lchild;free(p);//根据删除规则,孩子一并删除T->lchild = T->lchild->rbrother;//保留兄弟}if (T->rbrother != NULL && T->rbrother->data == x){SLNode* p = T->rbrother->lchild;free(p);//根据删除规则,孩子一并删除T->rbrother = T->rbrother->rbrother;//保留兄弟}deleteNode(T->lchild, x);deleteNode(T->rbrother, x);//先根再左在右,先序遍历的方式删除
}
int main()
{SLNode* T;string p;int n;Initiate(&T);do{system("color 75");cout << "                                                           "<<endl;cout << "                        家谱管理系统                    "<<endl;cout << "------------------------- 功能选项 -------------------------";cout << endl << endl;cout << "                    **  1-开始建立家谱  **" << endl;cout << "                    **  2-查询-家谱树   **" << endl;cout << "                    **  3-查询-儿子     **" << endl;cout << "                    **  4-查询-祖先     **" << endl;cout << "                    **  5-完善-孩子     **" << endl;cout << "                    **  6-完善-兄弟     **" << endl;cout << "                    **  7-删除-结点     **" << endl;cout << "                    **  0-退出系统      **" << endl;cout << endl << endl;cout << "------------------------------------------------------------";cout << endl;cout <<"请选择需要的功能(数字) :";char ch;ch = getchar();switch (ch){case '1':{cout << "请输入祖先结点:" << endl;cin >> p;Insertleft(T, p);input(T->lchild); getchar(); break;};case '2':{cout << endl;PrintTree(T->lchild, 1); getchar(); break;};case '3':{bool flag_1 = false;//flag_1用来标记是否有孩子bool flag_2 = false;//flag_2用来标记家谱里是否有要查询的结点cout << "请输入要查询的结点" << endl;cin >> p;inOrder(T, p, flag_2);while (!flag_2){cout << "您要查询的结点并不存在, 请重新输入:" << endl;cin >> p;inOrder(T, p, flag_2);}Searchchild(T, p,flag_1); //如果有孩子,则直接在此函数中输出if (!flag_1)//flag_1为假,即没有孩子,执行if{cout << "此结点没有儿子!" << endl;}getchar(); break;};case '4':{cout<< "请输入要查询的结点:" << endl;cin >> p;bool flag = false;while(p == T->lchild->data)//T是头结点,祖先存储在T的lchild域里{cout << "这个结点为祖先,请重新输入:" << endl;cin >> p;}SearchAncestor(T->lchild, p,flag);while (flag == false) {cout << "此结点不存在,请重新输入:" << endl;cin >> p;while(p== T->lchild->data)//T是头结点,祖先存储在T的lchild域里{cout << "这个结点为祖先,请重新输入:" << endl;cin >> p;}SearchAncestor(T->lchild, p, flag);}getchar();break;};case '5':{bool flag = false;//flag用来标记要完善的结点是否在家谱里 cout << "请输入要完善的结点:" << endl;cin >> p;inOrder(T, p, flag);//查找结点是否在家谱里while (!flag){cout << "您要完善的结点并不存在, 请重新输入:" << endl;cin >> p;inOrder(T, p, flag);}cout << "要添加的孩子为:" << endl;string x;cin >> x;addChild(T, p, x); getchar(); break;};case '6':{bool flag = false;//flag用来标记要完善的结点是否在家谱里cout << "请输入要完善的结点:" << endl;cin >> p;while (p == T->lchild->data) //T是头结点,祖先存储在T的lchild域里{cout << "这个结点为祖先,请重新输入:" << endl;cin >> p;}inOrder(T, p, flag);//查找结点是否在家谱里while (!flag){cout << "您要完善的结点并不存在,请重新输入:" << endl;cin >> p;inOrder(T, p, flag);}cout << "要添加的兄弟为:" << endl;string x;cin >> x;addBrother(T, p, x); getchar(); break;}case '7':{bool flag = false;//标记要删除的结点是否在家谱里cout << "请输入要删除的结点:" << endl;cin >> p;inOrder(T, p, flag);//查找结点是否在家谱里while (!flag){cout << "您要删除的结点并不存在,请重新输入:" << endl;cin >> p;inOrder(T, p, flag);}deleteNode(T, p); getchar(); break;}case '0':{ cout << " 感谢您的使用,下次再见!" << endl;exit(0);}default:{cout << "输入有误,请重新输入:" << endl;ch = getchar();}}} while (1);//cout << "hello world!" << endl;return 0;
}

调试分析及测试结果:

本项目以《红楼梦》贾府建立家谱树为例

进入主界面


建立家谱


生成树


查询操作


删除操作


写在最后

此次大作业是博主在为完成数据结构课程设计与团队共同完成,此项目比较简单,涉及到的知识点与数据结构都是在树之中扩展的,如果想完成课程设计大作业,此项目分数可以80+(根据学校不同),如果追求更高的成绩,也可以在此项目扩展功能,例如:增加称呼功能(对于任意两个人可以查询出互相称呼什么)、完善个人信息(完善结点结构体,增加年龄、性别、性格等属性)。若你们大作业距离答辩仅剩1-3天,此项目可以用来应急,具体源代码、答辩PPT、测试数据会统一放到一个资源里面,下面会更新链接。也可以私信博主,免费提供给大家。

获取文件可以添加博主vx好友,备注来意,联系我传送门:https://bbs.csdn.net/topics/619404381

最后特此鸣谢团队三人,@池鱼c0de

此篇终,感谢大家支持。

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

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

相关文章

Leaflet的zoom层级-天地图层级之间的关系

Leaflet的tileLayer请求地址分析 天地图的瓦片服务地址&#xff1a; http://t1.tianditu.com/img_c/wmts?layerimg&styledefault&tilematrixsetc&ServiceWMTS&RequestGetTile&Version1.0.0&Formattiles&TileMatrix{z}&TileCol{x}&TileRo…

常用的JVM启动参数有哪些?

大家好&#xff0c;我是锋哥。今天分享关于【常用的JVM启动参数有哪些?】面试题。希望对大家有帮助&#xff1b; 常用的JVM启动参数有哪些? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 JVM启动参数用于配置Java虚拟机&#xff08;JVM&#xff09;的运行时行为…

CTF学习24.12.21[隐写术进阶]

MISC08[隐写术进阶] PDF文件隐写 隐写的加密&#xff1a;wbStego4open工具的下载和使用 1.wbStego4open介绍&#xff1a; wbStego4open是一个隐写开源工具&#xff0c;它支持Windows和Linux平台&#xff0c;可以使用wbStego4open把文件隐藏到BMP、TXT、HTM和PDF文件中&#…

电脑丢失dll文件一键修复的多种方法分析,电脑故障修复攻略

电脑在使用过程中&#xff0c;有时会遇到DLL文件丢失的情况&#xff0c;这可能导致软件无法正常运行或系统出现故障。当面对这种状况时&#xff0c;不必过于慌张&#xff0c;因为有多种有效的修复方法可供选择。下面我们一起来看看电脑丢失dll文件的多种解决方法。 一.了解什么…

Redis篇--常见问题篇5--热Key(Hot Key,什么是热Key,服务降级,一致性哈希)

热key&#xff08;Hot Key&#xff09;是指在Redis中访问频率非常高、读写请求非常频繁的键。由于Redis是单线程模型&#xff0c;所有操作都是串行执行的&#xff0c;Hot Key处理不好&#xff0c;会产生一些问题。比如短时间的群蜂效应&#xff08;群蜂请求&#xff09;&#x…

VSCode:Markdown插件安装使用 -- 最简洁的VSCode中Markdown插件安装使用

VSCode&#xff1a;Markdown插件安装使用 1.安装Marktext2.使用Marktext 本文&#xff0c;将在Visual Studio Code中&#xff0c;安装和使用Markdown插件&#xff0c;以Marktext插件为例。 1.安装Marktext 打开VSCode&#xff0c;侧边栏中找到扩展模块(或CtrlShiftX快捷键)&am…

SpringBoot+Vue3实现阿里云视频点播 实现教育网站 在上面上传对应的视频,用户开会员以后才能查看视频

要使用阿里云视频点播&#xff08;VOD&#xff09;实现一个教育网站&#xff0c;其中用户需要成为会员后才能查看视频&#xff0c;这个过程包括上传视频、设置权限控制、构建前端播放页面以及确保只有付费会员可以访问视频内容。 1. 视频上传与管理 创建阿里云账号&#xff…

深度学习——现代卷积神经网络(七)

深度卷积神经网络 学习表征 观察图像特征的提取⽅法。在合理地复杂性前提下&#xff0c;特征应该由多个共同学习的神经⽹络层组成&#xff0c;每个层都有可学习的参数。 当年缺少数据和硬件支持 AlexNet AlexNet⽐相对较⼩的LeNet5要深得多。 AlexNet由⼋层组成&#xff1a…

免费送源码:Java+ssm++MVC+HTML+CSS+MySQL springboot 社区医院信息管理系统的设计与实现 计算机毕业设计原创定制

摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;采用Java技术建设社区医院信息管理系统…

Marin说PCB之POC电路layout设计仿真案例---06

我们书接上回啊&#xff0c;对于上面的出现原因我这个美女同事安娜说会不会你把POC电感下面的相邻两层的CUT_OUT的尺寸再去加大一些会不会变得更好呢&#xff1f;这个难道说是真的有用吗&#xff1f;小编我先自己算一卦看下结果。 本期文章我们就接着验证通过改善我们的单板POC…

简洁清爽epub 阅读器

Jane Reader 是一款现代化的 epub 阅读器&#xff0c;有简洁清爽&#xff0c;支持自动多栏、多主题、直排模式等&#xff0c;开发者想要提供「媲美于印刷书籍的阅读体验」 Jane Reader 目前提供以下功能&#xff1a; 支持 epub 电子书格式&#xff1b; 内置书库&#xff1b; 支…

TDesign:NavBar 导航栏

NavBar 导航栏 左图&#xff0c;右标 appBar: TDNavBar(padding: EdgeInsets.only(left: 0,right: 30.w), // 重写左右内边距centerTitle:false, // 不显示标题height: 45, // 高度titleWidget: TDImage( // 左图assetUrl: assets/img/logo.png,width: 147.w,height: 41.w,),ba…

javaFX.(蜜雪冰城点餐小程序)MySQL数据库

学习Java只有3个月&#xff0c;不喜勿喷 该小程序是用的MySQL数据库&#xff0c;编辑软件用的equals,为什么不用idea有提示因为主打一个纯手打 要源码私信 目录 javafx.小程序&#xff08;蜜雪冰城点餐系统&#xff09;简介 主体思路 思路讲解 用户登录 用户注册 忘记…

StarRocks:存算一体模式部署

目录 一、StarRocks 简介 二、StarRocks 架构 2.1 存算一体 2.2 存算分离 三、前期准备 3.1前提条件 3.2 集群规划 3.3 配置环境 3.4 准备部署文件 四、手动部署 4.1 部署FE节点 4.2 部署BE节点 4.3 部署CN节点&#xff08;可选&#xff09; 4.4 FE高可用…

【LeetCode】394、字符串解码

【LeetCode】394、字符串解码 文章目录 一、递归: 嵌套类问题1.1 递归: 嵌套类问题 二、多语言解法 一、递归: 嵌套类问题 1.1 递归: 嵌套类问题 // go func decodeString(s string) string {// 如果遇到 嵌套括号的情况, 则递归// 可能连续多位数字, 则 通过 cur cur * 10 …

厦门凯酷全科技有限公司短视频带货可靠吗?

在当今这个数字化时代&#xff0c;抖音作为短视频和直播带货的领军平台&#xff0c;已经吸引了无数商家的目光。而在这一片繁荣的电商蓝海中&#xff0c;厦门凯酷全科技有限公司&#xff08;以下简称“凯酷全”&#xff09;凭借其专业的团队、丰富的经验和创新的服务模式&#…

图书馆管理系统(三)基于jquery、ajax

任务3.4 借书还书页面 任务描述 这部分主要是制作借书还书的界面&#xff0c;这里我分别制作了两个网页分别用来借书和还书。此页面&#xff0c;也是通过获取books.txt内容然后添加到表格中&#xff0c;但是借还的操作没有添加到后端中去&#xff0c;只是一个简单的前端操作。…

RabbitMQ消息可靠性保证机制7--可靠性分析-rabbitmq_tracing插件

rabbitmq_tracing插件 rabbitmq_tracing插件相当于Firehose的GUI版本&#xff0c;它同样能跟踪RabbitMQ中消息的注入流出情况。rabbitmq_tracing插件同样会对流入流出的消息进行封装&#xff0c;然后将封装后的消息日志存入相应的trace文件中。 # 开启插件 rabbitmq-plugins …

如何重新设置VSCode的密钥环密码?

故障现象&#xff1a; 忘记了Vscode的这个密码&#xff1a; Enter password to unlock An application wants access to the keyring “Default ke... Password: The unlock password was incorrect Cancel Unlock 解决办法&#xff1a; 1.任意terminal下&#xff0c;输入如下…

XILINX平台LINUX下高速ADC08060驱动

前置调研 原理图 AXI-FULL时序 由于项目需要实时性高&#xff0c;采用AXI-FULL接口ADC IP作为master端写入DDR中 引用&#xff1a; AXI_02 AXI4总线简介&#xff08;协议、时序&#xff09;_axi4总线时序-CSDN博客 AXI总线的访问 在ARM架构中&#xff0c;访问I/O地址通常通…