数据结构:栈和队列
文章目录
- 一、栈
- 1.栈的概念及结构
- 1.栈的概念及结构
- 2.栈的实现
- 2.栈的顺序表实现
- 1.栈的结构体和实现的功能函数
- 2.栈的初始化,入栈和出栈操作
- 3.栈的其他操作
- 3.栈的链表实现
- 1.栈的结构体和实现的功能函数
- 2.栈功能函数的实现
- 二、队列
- 1.队列的概念及结构
- 1.队列的概念及结构
- 2.队列的实现
- 2.队列的顺序表实现(循环队列)
- 1.循环队列分析
- 2.循环队列的结构体和实现的功能函数
- 2.循环队列初始化和插入
- 2.循环队列的其他操作
- 3.队列的链表实现
- 1.队列的结构体和实现的功能函数
- 2.队列功能函数的实现
- 二、栈和队列应用实列:实现简单计算器
- 1.问题分析
- 1.代码实现
- 总结
一、栈
1.栈的概念及结构
1.栈的概念及结构
栈是一种特殊的线性表,只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端其称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出的原则。
2.栈的实现
栈的实现一般可以使用数组或者链表实现
栈的数组实现:
栈的链表实现:
对比两种方式的插入和删除:数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。
2.栈的顺序表实现
1.栈的结构体和实现的功能函数
typedef int STDataType;
typedef struct Stack
{STDataType* data;int top; // 栈顶int capacity; // 容量
}Stack;
void StackInit(Stack* ps);// 初始化栈
void StackPush(Stack* ps, STDataType data);// 入栈
void StackPop(Stack* ps);// 出栈
STDataType StackTop(Stack* ps);// 获取栈顶元素
int StackSize(Stack* ps);// 获取栈中有效元素个数
bool StackEmpty(Stack* ps);// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
void StackDestroy(Stack* ps);// 销毁栈
这里我们使用动态开辟的结构,保证栈的空间足够。数组实现我们需要一个变量来保存栈顶元素。栈顶元素也是我们栈中有效元素的个数。
2.栈的初始化,入栈和出栈操作
// 初始化
void StackInit(Stack* ps)
{ps->top = 0;//指向栈顶的位置置为数组的起始位置ps->capacity = 0;//把容量进行初始化ps->data = NULL;//把数据区进行初始化
}
// 入栈
void StackPush(Stack* ps, STDataType data)
{assert(ps);if (ps->top == ps->capacity)//判断空间是否已满,已满就进行扩容{int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//产生新的容量Stack* p = (Stack*)realloc(ps->data, sizeof(Stack)* newcapacity);//进行扩容if (p == NULL)//判断是否扩容成功{perror("realloc");exit(-1);}ps->data = p;//指向扩容后的地址ps->capacity = newcapacity;//更新容量为新的容量}ps->data[(ps->top)++] = data;//把数据弹入栈顶
}
// 出栈
void StackPop(Stack* ps)
{assert(ps);if (ps->top == 0)//判断是否还有元素{return;}ps->top--;//弹出栈顶元素
}
这里初始化,入栈和出栈操作和顺序表的操作没什么区别。
3.栈的其他操作
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{assert(ps);return ps->data[(ps->top) - 1];//栈顶的前一个位置为我们的栈顶元素,因为我们设置的起始位置从0开始
}
// 获取栈中有效元素个数
int StackSize(Stack* ps)
{assert(ps);return ps->top;//栈顶元素就是栈中有效元素个数
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
bool StackEmpty(Stack* ps)
{assert(ps);return ps->top == 0;//返回判断结果,等于0则代表没有元素,则返回真。反之则为假。
}
// 销毁栈
void StackDestroy(Stack* ps)
{assert(ps);free(ps->data);//释放掉我们开辟的数据空间ps->data = NULL;//把指向我们开辟数据的空间指向空ps->top = 0;ps->capacity = 0;
}
这里销毁注意我们的数据区的也要进行空间释放,防止造成空间泄露。
测试代码:
void test1()
{Stack ps;StackInit(&ps);StackPush(&ps, 1);StackPush(&ps, 2);StackPush(&ps, 3);StackPush(&ps, 4);StackPush(&ps, 5);printf("栈顶:%d\n", StackTop(&ps));// 获取栈顶元素 printf("个数:%d\n", StackSize(&ps));// 获取栈中有效元素个数if (!StackEmpty(&ps)){printf("Stack is not NULL\n");}StackPop(&ps);printf("栈顶:%d\n", StackTop(&ps));// 获取栈顶元素 if (!StackEmpty(&ps)){printf("Is not Empty\n");}StackDestroy(&ps);
}
int main()
{test1();//test2();//test3();//test4();//test5();return 0;
}
3.栈的链表实现
1.栈的结构体和实现的功能函数
typedef int STDataType;
typedef struct StackNode
{STDataType data;struct StackNode* next; //记录下一个区域的指针
}StackNode;
typedef struct Stack//头节点
{int size;//记录元素的个数StackNode head;
}Stack;
void StackInit(Stack* ps);// 初始化栈
void StackPush(Stack* ps, STDataType data);// 入栈
void StackPop(Stack* ps);// 出栈
STDataType StackTop(Stack* ps);// 获取栈顶元素
int StackSize(Stack* ps);// 获取栈中有效元素个数
bool StackEmpty(Stack* ps);// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
void StackDestroy(Stack* ps);// 销毁栈
我们这里和实现双链表一样,设置了一个特殊的头节点。头节点比正常节点多了一个变量用来记录栈中的元素个数,可以避免返回栈的元素个数时对栈进行遍历。
2.栈功能函数的实现
// 初始化栈
void StackInit(Stack* ps)
{ps->size = 0;//初始元素为0ps->head.next = NULL;//无元素时头节点的下一个指向空ps->head.data = 0;
}
// 入栈
void StackPush(Stack* ps, STDataType data)
{assert(ps);StackNode* add = (StackNode*)malloc(sizeof(StackNode));//创建节点if (add == NULL)//判断节点是否创建成功{perror("malloc");exit(-1);}add->data = data;//给节点赋上数据StackNode* pos = &(ps->head);//要取地址add->next = pos->next;//进行头插pos->next = add;ps->size++;
}
// 出栈
void StackPop(Stack* ps)
{assert(ps);StackNode* pos = &(ps->head);if (pos->next == NULL){return;}StackNode* del = pos->next;//进行头删pos->next = del->next;free(del);ps->size--;
}
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{assert(ps);StackNode* pos = (&(ps->head))->next;if (pos == NULL)//判断头指针的下一个是否为空{return;}return pos->data;
}
// 获取栈中有效元素个数
int StackSize(Stack* ps)
{assert(ps);return ps->size;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
bool StackEmpty(Stack* ps)
{assert(ps);return ps->size == 0;
}
// 销毁栈
void StackDestroy(Stack* ps)
{assert(ps);StackNode* pos = &(ps->head);if (pos->next == NULL)//判断头指针的下一个是否为空{return;}StackNode* del = pos->next;while (del != NULL){pos->next = del->next;free(del);del = pos->next;}
}
这里就是沿用链表的操作,注意释放节点时避免节点丢失。
测试函数:
void test2()
{Stack ps;StackInit(&ps);StackPush(&ps, 1);StackPush(&ps, 2);StackPush(&ps, 3);StackPush(&ps, 4);StackPush(&ps, 5);printf("栈顶:%d\n", StackTop(&ps));// 获取栈顶元素 printf("个数:%d\n", StackSize(&ps));// 获取栈中有效元素个数if (!StackEmpty(&ps)){printf("Stack is not NULL\n");}StackPop(&ps);printf("栈顶:%d\n", StackTop(&ps));// 获取栈顶元素 StackDestroy(&ps);
}
int main()
{//test1();test2();//test3();//test4();//test5();return 0;
}
二、队列
1.队列的概念及结构
1.队列的概念及结构
队列只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出的特点。进行插入操作的一端称为队尾 ,进行删除操作的一端称为队头。
2.队列的实现
队列的实现一般可以使用数组或者链表实现
队列的链表实现:
对比两种方式的插入和删除:使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,需要频繁移动数据,效率会比较低。
2.队列的顺序表实现(循环队列)
由于队列使用数组需要扩容和频繁移动数据,这样的结构并不常用,所以我们用顺序表实现循环的队列。
1.循环队列分析
我们假设数组的大小有五个元素
我们如何判断队列中的元素是否已经满了呢?
用头位置等于尾位置吗?
上述一个元素也没有会不会直接判断为数组已满呢?
我们的解决办法是保证一个位置为空,当尾位置等于头位置时即为队列满,即队尾不存储数据。
2.循环队列的结构体和实现的功能函数
#define MAXNUM 5
typedef int QDataType;
typedef struct QListNode
{QDataType data[5];int head;//对头元素int end;//队尾元素
}QNode;
void QueueInit(QNode* q);// 初始化队列
void QueuePush(QNode* q, QDataType data);// 队尾入队列
void QueuePop(QNode* q);// 队头出队列
QDataType QueueFront(QNode* q);// 获取队列头部元素
QDataType QueueBack(QNode* q);// 获取队列队尾元素
int QueueSize(QNode* q);// 获取队列中有效元素个数
int QueueEmpty(QNode* q);// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
void QueueDestroy(QNode* q);// 销毁队列
2.循环队列初始化和插入
// 初始化队列
void QueueInit(QNode* q)
{q->head = 0;q->end = 0;
}
// 队尾入队列
void QueuePush(QNode* q, QDataType data)
{assert(q);if ((q->end - q->head) == (MAXNUM-1))//尾元素和首元素相差最大数量减一个元素代表队列已满{printf("队列已满,无法插入\n");return;}q->data[(q->end) % MAXNUM] = data;q->end++;
}
我们对队列进行插入时要对队尾元素进行取模运算。防止插入时造成越界。
2.循环队列的其他操作
// 队头出队列
void QueuePop(QNode* q)
{assert(q);if (q->head == q->end)//尾元素和首元素相同证明队列中没有元素{printf("没有元素可以出队\n");return;}q->head++;
}
// 获取队列头部元素
QDataType QueueFront(QNode* q)
{assert(q);if (q->head == q->end && q->end != 0)//尾元素和首元素相同证明队列中没有元素{printf("没有元素可以查看\n");return -1;}return q->data[(q->head) % MAXNUM];
}
// 获取队列队尾元素
QDataType QueueBack(QNode* q)
{assert(q);if (q->head == q->end && q->end != 0)//尾元素和首元素相同证明队列中没有元素{printf("没有元素可以查看\n");return -1;}return q->data[(q->end - 1) % MAXNUM];
}
// 获取队列中有效元素个数
int QueueSize(QNode* q)
{assert(q);return q->end - q->head;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(QNode* q)
{assert(q);return q->head == q->end;
}
// 销毁队列
void QueueDestroy(QNode* q)
{assert(q);q->head = 0;q->end = 0;
}
我们返回队头队尾数据要看尾是否在0位置,为0代表一个元素还没插入。我们进行插入返回元素的操作都需要进行取模操作!!!
测试函数:
void test3()
{QNode qu;QueueInit(&qu);int i = 0;for(i = 0; i < 5; i++){QueuePush(&qu, i);}printf("队头:%d\n", QueueFront(&qu));printf("队尾:%d\n", QueueBack(&qu));QueuePop(&qu);printf("队头:%d\n", QueueFront(&qu));printf("个数:%d\n", QueueSize(&qu));printf("为空:%d\n", QueueEmpty(&qu));QueuePop(&qu);QueuePop(&qu);QueuePop(&qu);QueuePop(&qu);QueueDestroy(&qu);
}
int main()
{//test1();//test2();test3();//test4();//test5();return 0;
}
3.队列的链表实现
1.队列的结构体和实现的功能函数
typedef int QDataType;
typedef struct QListNode
{QDataType data;struct QListNode* next;
}QNode;
// 队列的结构
typedef struct Queue
{QNode* head;QNode* end;
}Queue;
void QueueInit(Queue* q);// 初始化队列
void QueuePush(Queue* q, QDataType data);// 队尾入队列
void QueuePop(Queue* q);// 队头出队列
QDataType QueueFront(Queue* q);// 获取队列头部元素
QDataType QueueBack(Queue* q);// 获取队列队尾元素
int QueueSize(Queue* q);// 获取队列中有效元素个数
int QueueEmpty(Queue* q);// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
void QueueDestroy(Queue* q);// 销毁队列
我们设置了一个结构体用来存储头节点和尾节点,目的是为了减少遍历。
2.队列功能函数的实现
//初始化队列
void QueueInit(Queue* q)
{assert(q);q->head = NULL;q->end = NULL;
}
// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{assert(q);QNode* pos = (QNode*)malloc(sizeof(QNode));if (pos == NULL){perror("malloc");exit(-1);}pos->data = data;pos->next = NULL;if (q->end == NULL){q->head = pos;q->end = pos;}else{q->end->next = pos;q->end = q->end->next;}
}
// 队头出队列
void QueuePop(Queue* q)
{assert(q);QNode* del = q->head;if (q->head == q->end && q->end != NULL)//当头指针等于尾指针时证明队列中没有元素{printf("没有元素可以出队\n");return;}q->head = q->head->next;free(del);
}
// 获取队列头部元素
QDataType QueueFront(Queue* q)
{assert(q);if (q->head == q->end && q->end != NULL)//当头指针等于尾指针时证明队列中没有元素{printf("没有元素可以查看\n");return -1;}return q->head->data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{assert(q);if (q->head == q->end && q->end != NULL)//当头指针等于尾指针时证明队列中没有元素{printf("没有元素可以查看\n");return -1;}return q->end->data;
}
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{assert(q);int size = 0;QNode* pos = q->head;while (pos != q->end){size++;pos = pos->next;}return size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q)
{assert(q);return q->head == q->end;
}
// 销毁队列
void QueueDestroy(Queue* q)
{assert(q);QNode* del = q->head;while (del != q->end){q->head = del->next;free(del);del = q->head;}free(q->head);q->head = NULL;q->end = NULL;
}
测试函数:
void test4()
{Queue qu;QueueInit(&qu);int i = 0;for(i = 0; i < 5; i++){QueuePush(&qu, i);}printf("队头:%d\n", QueueFront(&qu));printf("队尾:%d\n", QueueBack(&qu));QueuePop(&qu);printf("队头:%d\n", QueueFront(&qu));printf("个数:%d\n", QueueSize(&qu));printf("为空:%d\n", QueueEmpty(&qu));QueuePop(&qu);QueuePop(&qu);QueuePop(&qu);QueuePop(&qu);QueueDestroy(&qu);
}
int main()
{//test1();//test2();//test3();test4();//test5();return 0;
}
二、栈和队列应用实列:实现简单计算器
计算10+(10+20*30)*4-50
1.问题分析
我们计算需要进行优先级比较,是否含有括号,数据的存储等,我们需要两个栈来进行存储,一个符号栈,一个数字栈。
思路分析:
1.代码实现
void Count(Stack* num, int headsign)
{int n1 = 0;//用于计算的变量1int n2 = 0;//用于计算的变量2//已经是指针了,不可以在取地址了n2 = StackTop(num);//n2先进性出栈StackPop(num);//数字出栈n1 = StackTop(num);//n2出栈是为了防止除法是顺序错乱StackPop(num);//数字出栈int sum = 0;//用来存储两个值的结果switch (headsign)//判断符号{case '+':sum = n1 + n2;break;case '-':sum = n1 - n2;break;case '*':sum = n1 * n2;break;case '/':sum = n1 / n2;break;default:exit(-1);//未知符号,程序退出}//入数字栈StackPush(num, sum);
}
void Match_Brace(Stack* sign, Stack* num)//开始匹配左括号
{int headsign = 0;//存储栈顶的元素符号headsign = StackTop(sign);//获取栈顶元素符号while(!StackEmpty(sign))//符号栈不为空则一直进行循环, 直到在左括号处结束{if (headsign == '(')//如果为左括号则直接出栈结束{StackPop(sign);//符号出栈break;}else{//计算Count(num, headsign);//计算函数StackPop(sign);//符号出栈}headsign = StackTop(sign);//获取栈顶元素符号}
}
int Priority(int symbol)
{switch (symbol)//判断符号{case '(':return 0;case '+':case '-':return 1;case '*':case '/':return 2;default:exit(-1);//未知符号,程序退出}
}
void Match_Symbols(Stack* sign, Stack* num, int symbol)
{if (StackEmpty(sign) || symbol == '(')//如果栈为空或者为左括号,则直接入栈{StackPush(sign, symbol);//入栈return;}int headsign = 0;//存储栈顶的元素符号headsign = StackTop(sign);//获取栈顶元素符号if (Priority(symbol) > Priority(headsign))//优先级比较,该符号优先级高则直接入栈{StackPush(sign, symbol);//入栈return;}while(Priority(symbol) <= Priority(headsign))//直到优先级高于栈顶元素,停止循环{//计算Count(num, headsign);//计算函数StackPop(sign);//栈顶符号出栈if (StackEmpty(sign))//栈为空则退出循环{break;}headsign = StackTop(sign);//获取栈顶元素符号}StackPush(sign, symbol);//入栈
}
void test5()
{Stack num;//存储数字所使用的栈Stack sign;//存储算数符号所用的栈StackInit(&num);//对数字栈进行初始化StackInit(&sign);//对符号栈进行初始化char* s = "10+(10+20*30)*4-50";//要计算的表达式int i = 0;//用来判断表达式是否已到结尾int sum = 0;//用来存储一个整形数据int flag = 0;//用来判断是否取完一个整形元素while (s[i] != '\0'){if (isdigit(s[i]))//判断是否为数字{sum = sum * 10 + (s[i] - '0');//更新sum的值flag = 1;//把标志位置为1,为后面判断是否入栈准备}else{if (flag == 1)//判断该数字是否以入栈{//入数字栈StackPush(&num, sum);flag = 0;//更新标志位sum = 0;//更新sum值,防止下次计算时出错}if (s[i] == ')')//开始匹配左括号{//进行出栈匹配左括号Match_Brace(&sign, &num);}else//字符为( + - * /{//进行优先级比较Match_Symbols(&sign, &num,s[i]);}}i++;}if (flag == 1)//判断该数字是否以入栈{//入数字栈StackPush(&num, sum);flag = 0;//更新标志位sum = 0;//更新sum值,防止下次计算时出错}int headsign = 0;//存储栈顶的元素符号while (!StackEmpty(&sign))//符号栈不为空则一直进行计算{headsign = StackTop(&sign);//获取栈顶元素符号//计算Count(&num, headsign);StackPop(&sign);//符号出栈}printf("%d\n", StackTop(&num));StackDestroy(&num);//销毁数字栈StackDestroy(&sign);//销毁字符栈
}
int main()
{//test1();//test2();//test3();//test4();test5();return 0;
}
注意函数对指针的二次传参不需要在进行取地址,在计算机中计算机识别的是字符,所以我们需要一个字符一个字符的进行,这时间需要我们判断这个数字到底几位数,需要我们一个临时量,也可以用库函数atoi实现。其他按照思路可以轻而易举的实现。
总结
栈和队列都是含有限制的线性表。前面的知识扎实的话实现栈和队列没有一点问题。都是顺序表和链表的其中一部分。
相关文章:

数据结构:栈和队列
文章目录 一、栈1.栈的概念及结构1.栈的概念及结构2.栈的实现 2.栈的顺序表实现1.栈的结构体和实现的功能函数2.栈的初始化,入栈和出栈操作3.栈的其他操作 3.栈的链表实现1.栈的结构体和实现的功能函数2.栈功能函数的实现 二、队列1.队列的概念及结构1.队列的概念及…...

SpringCloud Gateway服务网关的介绍与使用
目录 1、网关介绍2、SpringCloudGateway工作原理3、三大组件3.1 、Route(路由)3.2、断言 Predicate3.3、过滤器 filter 4、Gateway整合nacos的使用4.1 、引入依赖4.2、 编写基础类和启动类4.3、 编写基础配置和路由规则4.4 、测试结果 1、网关介绍 客户…...

深入解析:如何打造高效的直播视频美颜SDK
在当今数字化时代,视频直播已经成为人们交流、娱乐和信息传递的重要方式。然而,许多人在直播时都希望能够呈现出最佳的外观,这就需要高效的直播视频美颜技术。本文将深入解析如何打造高效的直播视频美颜SDK,以实现令人满意的视觉效…...

每日一博 - MPP(Massively Parallel Processing,大规模并行处理)架构
文章目录 概述优点缺点小结 概述 MPP(Massively Parallel Processing,大规模并行处理)架构是一种常见的数据库系统架构,主要用于提高数据处理性能。它通过将多个单机数据库节点组成一个集群,实现数据的并行处理。 在 …...
ssh框架原理及流程
1.hibernate工作原理: 读取并解析配置文件读取并解析映射信息,创建sessionFactory打开session创建事务transaction持久化操作提交事务关闭session关闭sessionFactory 为什么使用: 对JDBC访问数据库的代码做了封装,大大简化了数据…...
eslint 配置和用法
在一个使用Webpack的项目中配置ESLint,你可以按照以下步骤操作: 首先,你需要在你的项目中安装ESLint和对应的Webpack loader。你可以使用npm或者yarn来安装。在你的项目根目录下打开终端,然后运行以下命令: 使用npm&…...

字符设备驱动实例(PWM和RTC)
目录 五、PWM 六、RTC 五、PWM PWM(Pulse Width Modulation,脉宽调制器),顾名思义就是一个输出脉冲宽度可以调整的硬件器件,其实它不仅脉冲宽度可调,频率也可以调整。它的核心部件是一个硬件定时器,其工作原理可以用…...

Ribbon 源码分析
Ribbon 源码分析 Ribbon Debug 分析 断点 LoadBalancerInterceptor LoadBalancerInterceptor 实现了 ClientHttpRequestInterceptor 接口,重写了其中的 intercept 方法,用来拦截请求; 获取原始的 uri 和 服务名,调用 LoadBalanc…...

【1-3章】Spark编程基础(Python版)
课程资源:(林子雨)Spark编程基础(Python版)_哔哩哔哩_bilibili 第1章 大数据技术概述(8节) 第三次信息化浪潮:以物联网、云计算、大数据为标志 (一)大数据 大数据时代到来的原因…...
宇宙原理:黑洞基础。
宇宙原理:黑洞基础TOC 黑洞的数理基础:一个由满数组成的数盘,经过自然演进,将会逐步稀疏化、最终会向纯数方案发展;纯数方案虽然只有{2}、无数(虚拟)、{0,1,2,3}(虚拟)、…...

分类预测 | MATLAB实现SCNGO-CNN-LSTM-Attention数据分类预测
分类预测 | MATLAB实现SCNGO-CNN-LSTM-Attention数据分类预测 目录 分类预测 | MATLAB实现SCNGO-CNN-LSTM-Attention数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.SCNGO-CNN-LSTM-Attention数据分类预测程序,改进算法,融合正余弦和…...

Android学习之路(7) Frament
Fragment 表示应用界面中可重复使用的一部分。fragment 定义和管理自己的布局,具有自己的生命周期,并且可以处理自己的输入事件。fragment 不能独立存在。它们必须由 activity 或其他 fragment 托管。fragment 的视图层次结构会成为宿主的视图层次结构的…...
metallb , istio ingress 部署httpbin使用例子
安装metaillb,参考:Kubernetes的负载均衡方案:MetalLB - 文章详情 wget https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-frr.yaml -O metallb.yaml kubectl apply -f metallb-frr.yaml 配置负载均衡ip池 apiVe…...

基于swing的销售管理系统java仓库库存信息jsp源代码mysql
本项目为前几天收费帮学妹做的一个项目,Java EE JSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 基于swing的销售管理系统 系统有1权限:管…...

FreeCAD傻瓜式教程之约束设定和构建实体、开孔、调整颜色等
本内容基于官方教程中的绘制简单的零件中的体会,在初次绘制的时候,总是无法完成,几经尝试才发现其关键点所在,以此文记录,用以被查资料,同时也希望能够帮到纯白新手快速熟悉该软件的绘图方法。 一、. 打开…...

代码随想录算法训练营day41 | 343. 整数拆分,96. 不同的二叉搜索树
目录 343. 整数拆分 96. 不同的二叉搜索树 343. 整数拆分 类型:动态规划 难度:medium 思路: dp[i]所用的拆分方法至少已经拆分了两次,比如dp[2]1,小于2,在大于2的数中,最后的2是不会拆的。 …...
飞天使-k8sv1.14二进制安装
文章目录 安装前准备安装前设置分发脚本 开始安装k8s集群cfssl 安装部署kubectl命令行工具创建admin证书和私钥创建kubeconfig文件部署ETCD集群部署Flannel网络kube-apiserver 高可用KeepLived 部署部署master节点部署高可用kube-controller-manager集群kube-controller-manage…...
TypeScript封装Axios
TypeScript封装Axios Axios的基本使用 因axios基础使用十分简单,可参考axios官方文档,这里不在介绍他基本用法,主要讲解拦截器。 拦截器主要分为两种,请求拦截器和响应拦截器。 请求拦截器:请求发送之前进行拦截&…...

指针(一)【C语言进阶版】
大家好,我是深鱼~ 【前言】: 指针的主题,在初阶指针章节已经接触过了,我们知道了指针的概念: 1.指针就是个变量,用来存放地址,地址的唯一标识一块内存空间(指针变量)&a…...

回归预测 | MATLAB实现SA-BP模拟退火算法优化BP神经网络多输入单输出回归预测(多指标,多图)
回归预测 | MATLAB实现SA-BP模拟退火算法优化BP神经网络多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现SA-BP模拟退火算法优化BP神经网络多输入单输出回归预测(多指标,多图)效果一览基本介…...

XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...

给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...