数据结构-线性表-具有独立头节点的双向循环链表
完整代码:
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6013)#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<time.h>// 一个具有独立头节点的双向循环链表,
// 区别在于将头节点和数据区域分开;
// 而且有独立头节点的链表为空的条件是:L->next等于L->prior等于NULL;
// 没有独立头节点的链表未空的条件是:L->next等于L->prior等于L;
// 还有一点要注意的是如何让p=L,指针转一圈之后不会回到L;typedef int ElemType;
typedef int Status;typedef struct Node {ElemType data;struct Node* next; //直接后继指针struct Node* prior; //直接前驱指针
}Node;
typedef Node* DuLinkList;// 函数声明
Status ListCreate(DuLinkList* L);
Status LinkEmpty(DuLinkList L);
Status ClearList(DuLinkList L);
Status GetElem(DuLinkList L, int i, ElemType* e);
Status LocateElem(DuLinkList L, ElemType e);
Status ListInsert(DuLinkList L, int i, ElemType e);
Status ListDelete(DuLinkList L, int i, ElemType* e);
void printAll(DuLinkList L);
void randList(DuLinkList L, int i);
Status insertHead(DuLinkList L, ElemType e);
Status insertEnd(DuLinkList L, ElemType e);
Status deleteEnd(DuLinkList L);
void ListReverse(DuLinkList L);
void test(DuLinkList L);/// <summary>
/// 创建一个空的链表,并创建头节点
/// </summary>
Status ListCreate(DuLinkList* L) { //传递的是指针,要用指针接收*L = (DuLinkList)malloc(sizeof(Node));if (!L) {printf("创建失败!\n");return 0;}(*L)->data = 0;(*L)->next = NULL;(*L)->prior = NULL;printf("创建成功!\n");return 1;
}/// <summary>
/// 判断链表是否为空
/// </summary>
Status LinkEmpty(DuLinkList L) {int flag;flag = (L->next == NULL) ? 0 : 1;return flag;
}/// <summary>
/// 将链表清空。
/// </summary>
Status ClearList(DuLinkList L) {DuLinkList p;p = L->next;int j = 1;while (1) {if (p == L->prior) {free(p);break;}p = p->next;free(p->prior);}L->next = NULL;L->prior = NULL;L->data = 0;return 1;
}/// <summary>
/// 将链表L中的第i个位置元素值返回给e。
/// </summary>
Status GetElem(DuLinkList L, int i, ElemType* e) {DuLinkList p;p = L->next;int j = 1;while (j < i) {if (p == L->prior && j != 1 || p == NULL) { return 0; } //指针转了一圈,没找到第i个元素;p = p->next;j++;}if (j > i || p == NULL) { return 0; }*e = p->data;return 1;
}/// <summary>
/// 在链表L中查找与给定值e相等的元素,
/// 如果查找成功,返回该元素在表中序号表示成功;
/// 否则,返回0表示失败。
/// </summary>
Status LocateElem(DuLinkList L, ElemType e) {DuLinkList p;p = L->next;int i;i = 1;while (p) {if (p->data == e) { return i; }if (p == L->prior) { break; }p = p->next;i++;}return 0;
}/// <summary>
/// 在链表L中的第i个位置插入新元素e。
/// </summary>
Status ListInsert(DuLinkList L, int i, ElemType e) {DuLinkList p, s;p = L->next;s = NULL;int j = 1;if (i < 1) {printf("第%d个元素不存在。\n", i);return 0;}while (j < i) {if (p == L->next && j != 1) {printf("第%d个元素不存在。\n", i);return 0;}p = p->next;j++;}s = (DuLinkList)malloc(sizeof(Node));if (!s) {printf("内存申请失败!\n");}s->data = e;// 考虑极端情况if (L->next == NULL) { //链表中没有数据元素;s->next = s;s->prior = s;L->next = s;L->prior = s;}else { // 链表中有数据元素;s->next = p;s->prior = p->prior;p->prior->next = s;p->prior = s;if (i == 1) { //插入的位置是首元结点;L->next = s;}else if (i == L->data + 1) { //插入的位置是尾节点;L->prior = s;}}L->data++;return 1;
}/// <summary>
/// 删除链表L中第i个位置元素,并用e返回其值。
/// </summary>
Status ListDelete(DuLinkList L, int i, ElemType* e) {DuLinkList p;p = L->next;int j = 1;if (i < 1 || i>L->data) {printf("第%d个元素不存在。\n", i);return 0;}while (j < i) {p = p->next;j++;}*e = p->data;if (L->next == L->prior) { // 链表中只有一个元素L->next = NULL;L->prior = NULL;}else if (L->next == p) { // 删除第一个元素L->next = p->next;}else if (L->prior == p) { // 删除最后一个元素L->prior = p->prior;}// 正常情况p->next->prior = p->prior;p->prior->next = p->next;free(p);L->data--;return 1;
}/// <summary>
/// 输出链表中所有元素。
/// </summary>
void printAll(DuLinkList L) {DuLinkList p;p = L->next;int i = 0;while (p) {printf("%d\t", p->data);if (p == L->prior)break;p = p->next;}printf("\n");
}/// <summary>
/// 向链表中添加i个随机元素。
/// </summary>
void randList(DuLinkList L, int i) {int min = 0;int max = 1000;int range = max - min + 1;for (int j = 0; j < i; j++) {ElemType e = min + rand() % range;insertEnd(L, e);}printf("\n");
}
/// <summary>
/// 在链表头部插入一个元素(头插法)
/// </summary>
Status insertHead(DuLinkList L, ElemType e) {DuLinkList p, s;p = L->next;s = (DuLinkList)malloc(sizeof(Node));if (s == NULL) {return 0;}s->data = e;L->next = s;if (!p) { //链表中没有一个元素L->prior = s;s->next = s;s->prior = s;}else { //链表中又元素s->next = p;s->prior = L->prior;L->prior->next = s;p->prior = s;}L->data++;return 1;
}/// <summary>
/// 在链表末尾插入一个元素(尾插法)
/// </summary>
Status insertEnd(DuLinkList L, ElemType e) {DuLinkList p, s;p = L->prior;s = (DuLinkList)malloc(sizeof(Node));if (!s) {return 0;}s->data = e;L->prior = s;if (!p) { //链表中没有一个元素L->next = s;s->next = s;s->prior = s;}else { //链表中有元素s->prior = p;s->next = L->next;L->next->prior = s;p->next = s;}L->data++;return 1;
}/// <summary>
/// 在链表末尾删除一个元素
/// </summary>
Status deleteEnd(DuLinkList L) {DuLinkList p;p = L->prior;if (!p) { //链表中没有一个元素return 0;}if (L->prior == L->next) { //链表中的元素只有一个L->prior = NULL;L->next = NULL;}else { //链表中的元素大于一个L->prior = p->prior;L->prior->next = L->next;L->next->prior = L->prior;}L->data--;free(p);return 1;
}/// <summary>
/// 将所有元素反转(交换每一个结点的next和prior指针)\
/// (还有一种实现方法是:创建一个新的头结点,将原链表的的结点根据一定顺序插进去)
/// </summary>
void ListReverse(DuLinkList L) {DuLinkList p, agent;p = L->next;agent = NULL;while (p) {agent = p->next;p->next = p->prior;p->prior = agent;if (p == L->prior) {break;}p = agent;}agent = L->next;L->next = L->prior;L->prior = agent;
}// 另一种实现方式
void Reverse(DuLinkList L) {DuLinkList p, s;p = L->next;s = NULL;ListCreate(&s);if (!s) {return;}while (p) {insertHead(s, p->data);if (p == L->prior) {break;}p = p->next;}//printf("%p\n", &L);//printf("%p\n", L);ClearList(L);*L = *s;//printf("%p\n", L);//test(L);//printf("---------\n");//test(s);free(s);
}/// <summary>
/// 获得链表长度(同ListEmpty)
/// </summary>
int ListLight(DuLinkList L) {return L->data;
}void menu() {printf("=============================菜单-双向循环链表===================================\n");printf("(1) 显示菜单\t\t\t\t(2) 判空\t\t\t\t|\n");printf("(3) 清空链表\t\t\t\t(4) 按位删除\t\t\t\t|\n");printf("(5) 按位查找\t\t\t\t(6) 按值查找\t\t\t\t|\n");printf("(7) 按位插入\t\t\t\t(8) 元素个数\t\t\t\t|\n");printf("(9) 输出链表\t\t\t\t(10) 随机生成\t\t\t\t|\n");printf("(11) 头插入\t\t\t\t(12) 尾插入\t\t\t\t|\n");printf("(13) 尾删除\t\t\t\t(14) 反转链表\t\t\t\t|\n");printf("(0) 结束程序\t\t\t\t\t\t\t\t\t|\n");printf("=================================================================================\n");
}void test(DuLinkList L) {int i = 1;printf("[0] data: %d\tself: %p next: %p prior: %p\n", L->data, L, L->next, L->prior);DuLinkList p;p = L->next;while (p) {printf("[%d] data: %d\tself: %p next: %p prior: %p\n", i++, p->data, p, p->next, p->prior);if (p == L->prior) { break; }p = p->next;}
}// 简化后的main函数
int main() {DuLinkList L = NULL;ListCreate(&L);int choice;ElemType e, * p_e = (ElemType*)malloc(sizeof(ElemType));int i;menu();while (1) {printf("请输入菜单序号:");scanf("%d", &choice);switch (choice) {case 999:test(L);break;case 0:free(L);printf("链表已经销毁。\n");return 0;case 1:menu();break;case 2:if (LinkEmpty(L)) {printf("非空。\n");}else {printf("空\n");}break;case 3:ClearList(L);printf("Ok\n");break;case 4:printf("要删除的位置是:");scanf("%d", &i);if (ListDelete(L, i, p_e)) {printf("Success:删除第%d个位置上的元素 %d\n", i, *p_e);}else {printf("Error:检查输入是否正确。\n");}break;case 5:printf("要查找的位置为:(下标从1开始)");scanf("%d", &i);if (GetElem(L, i, p_e)) {printf("Success:第%d个元素为:%d\n", i, *p_e);}else {printf("Error:无法找到第%d个元素,检查输入是否正确。\n", i);}break;case 6:printf("要查找的值为:");scanf("%d", &e);i = LocateElem(L, e);if (i) {printf("Success:第%d个位置\n", i);}else {printf("没有发现这个值。\n");}break;case 7:printf("输入插入的位置(下标从1开始)以及插入的数值,用空格隔开:\n");scanf("%d %d", &i, &e);if (ListInsert(L, i, e)) {printf("Success\n");}else {printf("Error:插入失败!\n");}break;case 8:printf("表中元素个数为:%d\n", ListLight(L));break;case 9:printAll(L);break;case 10:printf("随机生成几个数?");scanf("%d", &i);randList(L, i);break;case 11:printf("输入要插入的数:");scanf("%d", &e);if (insertHead(L, e)) {printf("Success:插入成功。\n");}else {printf("Error:插入失败!\n");}break;case 12:printf("输入要插入的数:");scanf("%d", &e);if (insertEnd(L, e)) {printf("Success:插入成功。\n");}else {printf("Error:插入失败!\n");}break;case 13:if (deleteEnd(L)) {printf("Success:删除成功。\n");}else {printf("Error:删除失败\n");}break;case 14:/* printf("%p\n", &L);printf("%p\n", L);*/Reverse(L);break;default:printf("Error:错误输入。\n");break;}}free(p_e);return 0;
}
一、双向循环链表简介
双向循环链表是一种在链表基础上拓展而来的数据结构。与普通链表不同的是,它的每个节点都有两个指针,一个指向前驱节点(prior
),一个指向后继节点(next
)。而且,它是循环的,即链表的尾节点的后继指针指向头节点,头节点的前驱指针指向尾节点,形成一个闭合的环。
我们这里讨论的双向循环链表还有一个独立的头节点。这个独立头节点不存储数据,主要用于方便对链表的操作和维护。这种链表为空的条件是头节点的next
和prior
指针都指向NULL
。
二、代码结构和数据类型定义
(一)数据类型定义
在代码中,首先定义了链表节点的数据类型。通过以下结构体来表示一个节点:
typedef struct Node {ElemType data;struct Node* next;struct Node* prior;
} Node;
typedef Node* DuLinkList;
这里,ElemType
被定义为int
类型,用于存储节点的数据。Node
结构体包含了数据域data
以及next
和prior
这两个指针,分别用于构建链表的双向连接。DuLinkList
则是指向Node
类型的指针,它代表了整个链表(实际上是从独立头节点开始)。
(二)函数声明
代码中声明了一系列操作双向循环链表的函数,包括创建链表、判断链表是否为空、清空链表、按位获取元素、按值查找元素、插入元素(按位插入、头插法、尾插法)、删除元素(按位删除、尾删除)以及链表的反转等功能。这些函数为我们全面操作链表提供了丰富的接口。
三、主要函数实现分析
(一)创建链表 - ListCreate
函数
Status ListCreate(DuLinkList* L) {*L = (DuLinkList)malloc(sizeof(Node));if (!L) {printf("创建失败!\n");return 0;}(*L)->data = 0;(*L)->next = NULL;(*L)->prior = NULL;printf("创建成功!\n");return 1;
}
这个函数用于创建一个空的链表。它通过malloc
函数为链表的头节点分配内存空间。如果分配成功,将头节点的data
初始化为0
,next
和prior
指针都设为NULL
,并返回1
表示创建成功;如果malloc
失败,则返回0
。
(二)判断链表是否为空 - LinkEmpty
函数
Status LinkEmpty(DuLinkList L) {int flag;flag = (L->next == NULL)? 0 : 1;return flag;
}
通过检查链表头节点的next
指针是否为NULL
来判断链表是否为空。如果next
为NULL
,说明链表没有数据节点,返回0
;否则返回1
。
(三)清空链表 - ClearList
函数
Status ClearList(DuLinkList L) {DuLinkList p;p = L->next;int j = 1;while (1) {if (p == L->prior) {free(p);break;}p = p->next;free(p->prior);}L->next = NULL;L->prior = NULL;L->data = 0;return 1;
}
这个函数用于清空链表。它从链表的第一个数据节点开始,依次释放每个节点的内存。在遍历过程中,通过free(p->prior)
释放当前节点的前驱节点,直到到达尾节点。最后,将头节点的next
和prior
指针设为NULL
,data
设为0
。
(四)按位获取元素 - GetElem
函数
Status GetElem(DuLinkList L, int i, ElemType* e) {DuLinkList p;p = L->next;int j = 1;while (j < i) {if (p == L->prior && j!= 1 || p == NULL) { return 0; } p = p->next;j++;}if (j > i || p == NULL) { return 0; }*e = p->data;return 1;
}
该函数用于获取链表中指定位置i
的元素值。通过遍历链表,从头节点的下一个节点开始,逐个移动指针p
,直到找到第i
个节点。如果找到了,将该节点的数据存储到e
所指向的变量中,并返回1
;如果在遍历过程中出现指针转了一圈还没找到或者p
为NULL
等情况,则返回0
。
(五)按值查找元素 - LocateElem
函数
Status LocateElem(DuLinkList L, ElemType e) {DuLinkList p;p = L->next;int i;i = 1;while (p) {if (p->data == e) { return i; }if (p == L->prior) { break; }p = p->next;i++;}return 0;
}
在链表中查找值为e
的元素。从链表的第一个数据节点开始,逐个比较节点的数据值与e
是否相等。如果找到相等的值,返回该元素在链表中的序号;如果遍历完整个链表都没找到,则返回0
。
(六)按位插入元素 - ListInsert
函数
Status ListInsert(DuLinkList L, int i, ElemType e) {DuLinkList p, s;p = L->next;s = NULL;int j = 1;if (i < 1) {printf("第%d个元素不存在。\n", i);return 0;}while (j < i) {if (p == L->next && j!= 1) {printf("第%d个元素不存在。\n", i);return 0;}p = p->next;j++;}s = (DuLinkList)malloc(sizeof(Node));if (!s) {printf("内存申请失败!\n");}s->data = e;if (L->next == NULL) {s->next = s;s->prior = s;L->next = s;L->prior = s;}else {s->next = p;s->prior = p->prior;p->prior->next = s;p->prior = s;if (i == 1) { L->next = s;}else if (i == L->data + 1) { L->prior = s;}}L->data++;return 1;
}
这个函数实现在链表的指定位置i
插入新元素e
。首先,通过遍历找到要插入位置的前一个节点p
。然后创建一个新节点s
,并根据链表是否为空以及插入位置是否为首元节点或尾节点等情况,调整节点之间的指针关系,最后增加链表长度计数器L->data
的值。
(七)按位删除元素 - ListDelete
函数
Status ListDelete(DuLinkList L, int i, ElemType* e) {DuLinkList p;p = L->next;int j = 1;if (i < 1 || i>L->data) {printf("第%d个元素不存在。\n", i);return 0;}while (j < i) {p = p->next;j++;}*e = p->data;if (L->next == L->prior) {L->next = NULL;L->prior = NULL;}else if (L->next == p) {L->next = p->next;}else if (L->prior == p) {L->prior = p->prior;}p->next->prior = p->prior;p->prior->next = p->next;free(p);L->data--;return 1;
}
用于删除链表中指定位置i
的元素,并将删除元素的值存储到e
所指向的变量中。先找到要删除的节点p
,然后根据链表中节点的数量情况(如只有一个元素、删除第一个元素、删除最后一个元素等)调整指针关系,最后释放被删除节点的内存,并减少链表长度计数器的值。
(八)头插法 - insertHead
函数
Status insertHead(DuLinkList L, ElemType e) {DuLinkList p, s;p = L->next;s = (DuLinkList)malloc(sizeof(Node));if (s == NULL) {return 0;}s->data = e;L->next = s;if (!p) {L->prior = s;s->next = s;s->prior = s;}else {s->next = p;s->prior = L->prior;L->prior->next = s;p->prior = s;}L->data++;return 1;
}
实现将一个元素插入到链表头部。创建一个新节点s
,将其数据域设为e
,然后调整头节点与新节点以及原第一个节点(如果存在)之间的指针关系,最后增加链表长度。
(九)尾插法 - insertEnd
函数
Status insertEnd(DuLinkList L, ElemType e) {DuLinkList p, s;p = L->prior;s = (DuLinkList)malloc(sizeof(Node));if (!s) {return 0;}s->data = e;L->prior = s;if (!p) {L->next = s;s->next = s;s->prior = s;}else {s->prior = p;s->next = L->next;L->next->prior = s;p->next = s;}L->data++;return 1;
}
将元素插入到链表的末尾。创建新节点s
,设置其数据值为e
,然后根据链表是否为空来调整新节点与链表尾节点(如果存在)以及头节点之间的指针关系,最后更新链表长度。
(十)尾删除 - deleteEnd
函数
Status deleteEnd(DuLinkList L) {DuLinkList p;p = L->prior;if (!p) {return 0;}if (L->prior == L->next) {L->prior = NULL;L->next = NULL;}else {L->prior = p->prior;L->prior->next = L->next;L->next->prior = L->prior;}L->data--;free(p);return 1;
}
用于删除链表的尾节点。首先判断链表是否为空,如果不为空,根据链表中节点数量情况(只有一个节点或多个节点)调整指针关系,释放尾节点内存并减少链表长度。
(十一)链表反转 - ListReverse
函数
void ListReverse(DuLinkList L) {DuLinkList p, agent;p = L->next;agent = NULL;while (p) {agent = p->next;p->next = p->prior;p->prior = agent;if (p == L->prior) {break;}p = agent;}agent = L->next;L->next = L->prior;L->prior = agent;
}
这个函数通过交换每个节点的next
和prior
指针来实现链表的反转。使用一个临时指针agent
来辅助交换过程,遍历链表,逐个交换节点的指针,最后调整头节点的next
和prior
指针,完成链表的反转。
(十二)另一种链表反转 - Reverse
函数
void Reverse(DuLinkList L) {DuLinkList p, s;p = L->next;s = NULL;ListCreate(&s);if (!s) {return;}while (p) {insertHead(s, p->data);if (p == L->prior) {break;}p = p->next;}ClearList(L);*L = *s;free(s);
}
这是另一种实现链表反转的方法。它先创建一个新的链表s
,然后通过遍历原链表L
,将原链表的元素以头插法插入到新链表s
中。接着清空原链表L
,再将新链表s
的内容复制到原链表L
中(通过*L = *s
),最后释放新链表s
的头节点内存。
相关文章:

数据结构-线性表-具有独立头节点的双向循环链表
完整代码: #define _CRT_SECURE_NO_WARNINGS #pragma warning(disable:6013)#include<stdio.h> #include<malloc.h> #include<stdlib.h> #include<time.h>// 一个具有独立头节点的双向循环链表, // 区别在于将头节点和数据区域…...

CSS 响应式设计之媒体查询技术
CSS 媒体查询(Media Queries)是一种根据不同设备的特性(如屏幕宽度、分辨率、方向等)来应用不同的 CSS 样式的技术。它通常用于响应式设计,帮助网页在不同设备和屏幕尺寸下良好地展示。 基本语法 media (条件) {/* 样…...

HARCT 2025 分论坛4:智能系统传感、传感器开发和数据融合中的智能数据分析
机电液一体化与先进机器人控制技术国际会议(HARCT 2025)将于2025年1月3日-6日在中国广西桂林召开。本届会议围绕“机电液一体化”“机器人”“控制技术”等最新研究成果,邀请海内外在这一领域贡献卓著的专家学者做精彩致辞和报告。 会议期间…...

云计算研究实训室建设方案
一、引言 随着云计算技术的迅速发展和广泛应用,职业院校面临着培养云计算领域专业人才的迫切需求。本方案旨在构建一个先进的云计算研究实训室,为学生提供一个集理论学习、实践操作、技术研发与创新于一体的综合性学习平台,以促进云计算技术…...

VRT: 关于视频修复的模型
🏡作者主页:点击! 🤖编程探索专栏:点击! ⏰️创作时间:2024年11月15日14点34分 神秘男子影, 秘而不宣藏。 泣意深不见, 男子自持重, 子夜独自沉。 论文链接 点击开启你的论文编程之旅…...

实习冲刺Day22
算法题 路径总和 112. 路径总和 - 力扣(LeetCode) class Solution { public:bool hasPathSum(TreeNode* root, int targetSum) {if(!root)return 0;//节点为空返回0int sumroot->val;//记录当前节点的值int ntargetSum-sum;//距离目标值还差多少if…...

datawhale2411组队学习之模型压缩技术1:模型剪枝
文章目录 一、环境配置二、模型压缩2.1 模型压缩简介2.2 模型压缩评价指标 三、 模型剪枝3.1 模型剪枝简介3.2 何为剪枝(What is Pruning?)3.3 剪枝标准(How to prune?)3.4 剪枝频率(How often?)3.5 剪枝…...

高防服务器的费用受到哪些原因影响?
在如今的互联网社会中,越来越多的企业都开始了线上网络业务的发展,网络安全也日益受到了重视,高防服务器成为了众多企业的首要选择,不仅可以帮助企业有效抵御各种网络攻击,保证网站和应用的稳定性。 但是高防服务器与其…...

中断和异常处理,嵌入式行业的门槛?
Linux内核中,中断和异常是重要的机制,用于响应硬件事件和处理异常情况。它们直接关系到系统的稳定性和性能。本文将通过清晰的结构、逻辑图、表格,深入解析中断和异常处理的种类、流程以及它们与系统调用和用户空间的联系。 1. 中断和异常概述…...

latex中英文环境中双引号怎么输入
latex中英文环境中双引号怎么输入 1. **英文环境中的双引号**2. **中文环境中的双引号**3. **嵌套引号**4. **一致性处理**小结: 在 LaTeX 中,输入双引号的方法取决于文档的语言环境。以下是针对英文和中文环境的双引号输入方法: 1. 英文环境…...

用 Python 从零开始创建神经网络(三):添加层级(Adding Layers)
添加层级(Adding Layers) 引言1. Training Data2. Dense Layer Class 引言 我们构建的神经网络变得越来越受人尊敬,但目前我们只有一层。当神经网络具有两层或更多隐藏层时,它们变成了“深度”网络。目前我们只有一层,…...

前端知识点---构造函数(javascript)
文章目录 前端知识点---构造函数(Javascript)1. 定义构造函数2. 使用构造函数创建对象3. 工作原理4. 构造函数与原型5. 类的语法糖6. 注意事项 前端知识点—构造函数(Javascript) 在我的文章 “对象” 里我提到了构造函数 , 前端知识点—Javascript的对象(Javascript) 因为day…...

Nginx 上安装 SSL 证书并启用 HTTPS 访问
本文将介绍如何在 Nginx 上为你的域名安装 SSL 证书,并配置 Nginx 使用 HTTPS 安全访问。我们将使用 Let’s Encrypt 免费的 SSL 证书,通过 Certbot 生成并管理证书,然后配置 Nginx 实现 HTTPS 加密访问。同时,我们将解决因 SSL 证…...

谷歌Gemini发布iOS版App,live语音聊天免费用!
大家好,我是木易,一个持续关注AI领域的互联网技术产品经理,国内Top2本科,美国Top10 CS研究生,MBA。我坚信AI是普通人变强的“外挂”,专注于分享AI全维度知识,包括但不限于AI科普,AI工…...

docker运行ActiveMQ-Artemis
前言 artemis跟以前的ActiveMQ不是一个产品,原ActiveMQ改为ActiveMQ Classic, 现在的artemis是新开发的,和原来不兼容,全称:ActiveMQ Artemis 本位仅介绍单机简单部署使用,仅用于学习和本地测试使用 官网:…...

90.选择排序(理论分析)
一.选择排序 冒泡排序每相邻的俩个元素之间都会比较交换一次,效率比较慢。这对这个问题所改进的算法叫做选择排序。 二.选择排序的实现思路 首先在一组未排序的数据中假定一个最大或者最小元素,一般是第0个元素。然后在从剩余未排序的元素中…...

GitLab 如何跨版本升级?
本分分享 GitLab 跨版本升级的一些注意事项。 众所周知,GitLab 的升级必须要严格遵循升级路径,否则就会出现问题,导致升级失败。因此,在 GitLab 升级之前需要做好两件事情: 当前版本的确认升级路径的确认 极狐GitLa…...

【Fermat】费马小定理
定理 若存在整数 a , p 且g c d ( a , p ) 1 gcd(a,p)1gcd(a,p)1,即二者互为质数,则有 a ( p − 1 ) ≡ 1 ( m o d p ) a^{(p-1)}≡ 1(mod p) a (p−1) ≡1(modp) 目录 定理 引理 引理一 引理二 证…...

NVMe(Non-Volatile Memory Express)非易失性存储器访问和传输协议
目录 NVMe(Non-Volatile Memory Express)非易失性存储器访问和传输协议 一、NVMe的定义 二、NVMe的特点 三、NVMe的应用场景 四、举例说明 NVMe(Non-Volatile Memory Express)非易失性存储器访问和传输协议 是一种非易失性存储器访问和传输协议,专为固态硬盘(SSD)…...

C++初阶——queue
一、什么是queue 是一个容器适配器,专门设计用于在先进先出(FIFO,First In First Out)的上下文中操作。它是一个容器适配器,这意味着它不是一个完整的容器类,而是封装了一个特定的容器类(如list…...

达梦数据库迁移j脚本
国产环境使用达梦数据库的越来越多,除了使用管理工具,还是可以使用脚本。 下面简单记录下,我在迁移中遇到的问题: 备份脚本 使用此脚本可以一次备份一个数据 backup_one_db.sh #!/bin/bashexport DB$1 export PASS<your_p…...

【Linux】内核调用栈打印函数dump_stack使用效果
init/main.c的start_kernel示例,这个调用栈不太深: /var/log/dmesg日志: [ 0.000000] kernel: [init/main.c start_kernel 911] start_kernel(void) [ 0.000000] kernel: [kernel/panic.c print_tainted 519 LOG_TIMES: 1 ] [ 0.…...

Uniapp踩坑input自动获取焦点ref动态获取实例不可用
前言 大家好我是没钱的君子下流坯,用自己的话解释自己的知识。很久很更新了,这几个月一直在加班,今天记录一个uniapp关于input中focus()方法自动获取焦点的坑。 案例 为了实现一个手机验证码的页面,验证码是五个输入框…...

数据分析-47-时间序列变点检测之离线历史数据的CPD
文章目录 1 时间序列结构1.1 变化点的定义1.2 结构变化的类型1.2.1 水平变化1.2.2 方差变化1.3 变点检测1.3.1 离线数据检测方法1.3.2 实时数据检测方法2 模拟数据2.1 模拟恒定方差数据2.2 模拟变化方差数据3 离线数据变点检测3.1 Ruptures模块3.2 恒定方差CPD3.3 变化方差CPD4…...

加入GitHub Spark需要申请
目录 加入GitHub Spark需要申请 GitHub Spark 一、产品定位与特点 二、核心组件与功能 三、支持的AI模型 四、应用场景与示例 五、未来展望 六、申请体验 加入GitHub Spark需要申请 GitHub Spark 是微软旗下GitHub在2024年10月30日的GitHub Universe大会上推出的一款革…...

生成式GPT商品推荐:精准满足用户需求
生成式GPT商品推荐:精准满足用户需求 随着人工智能(AI)技术的飞速发展,电商平台正在逐步迎来一场前所未有的变革。尤其是生成式GPT(Generative Pre-trained Transformer)技术的应用,正在重新定…...

async 和 await的使用
一、需求 点击按钮处理重复提交,想要通过disabled的方式实现。 但是点击按钮调用的方法里有ajax、跳转、弹窗等一系列逻辑操作,需要等方法里流程都走完,再把disabled设为false,这样下次点击按钮时就可以继续走方法里的ajax等操作…...

Spring Cloud Vault快速入门Demo
1.什么是Spring Cloud Vault? Spring Cloud Vault 是 Spring Cloud 生态系统中的一个项目,旨在简化 Spring 应用程序与 HashiCorp Vault 的集成。它提供了一种方便的方式来管理和访问应用程序的敏感配置数据,如数据库凭证、API 密钥和其他机…...

道陟科技EMB产品开发进展与标准设计的建议|2024电动汽车智能底盘大会
11月12日,2024电动汽车智能底盘大会在重庆开幕。会议由中国汽车工程学会主办,电动汽车产业技术创新战略联盟、中国汽车工程学会智能底盘分会、智能绿色车辆与交通全国重点实验室承办。本届大会围绕电动汽车智能底盘相关技术发展与融合,满足高…...

GitHub Org
运营一个GitHub Org(组织)是一个复杂但充满价值的过程,它涉及多个方面,包括项目管理、团队协作、代码审查、文档维护、社区建设等。以下是一篇关于如何运营GitHub Org的详细指南,旨在帮助组织者更好地管理和维护其GitH…...