当前位置: 首页 > news >正文

C 语言实现动态数组、链表、栈与队列

从代码到原理:C语言实现动态数组、链表、栈与队列

在数据结构的世界里,线性结构是构建复杂算法的基石。动态数组、链表、栈和队列作为最经典的线性结构,各自拥有独特的存储方式与操作特性,适用于不同的业务场景。本文将结合C语言实现代码,从结构定义、核心操作到实际应用,讲述这四种数据结构的设计思想与使用技巧。

一、动态数组(Dynamic Array):灵活扩容的连续存储

动态数组是对静态数组的优化,它解决了静态数组容量固定的痛点,支持在元素数量超过容量时自动扩容,同时保留了数组随机访问的高效性。

1.1 动态数组的结构设计

动态数组的核心是通过指针指向一片连续的内存空间,并记录当前的容量(capacity)长度(length)。容量表示当前内存可容纳的最大元素数,长度表示实际存储的元素数。

typedef int element_t; // 数据类型别名,便于后续修改typedef struct {element_t *data;    // 指向连续内存空间的指针size_t capacity;    // 数组总容量(可容纳的最大元素数)size_t length;      // 数组当前长度(实际存储的元素数)
} DynamicArray;

1.2 核心操作实现

动态数组的核心操作包括初始化、扩容、插入、删除和销毁,下面逐一解析关键代码逻辑。

(1)初始化:分配初始内存

初始化函数为动态数组分配指定大小的初始内存,并将长度初始化为0。

void init_dynamic_array(DynamicArray *array, size_t initCapacity) {array->data = (element_t*)malloc(initCapacity * sizeof(element_t)); // 分配内存array->capacity = initCapacity; // 初始容量array->length = 0; // 初始长度为0(无元素)
}

(2)扩容:自动调整内存大小

当元素数量(length)等于容量(capacity)时,调用resizeDynamicArray将容量翻倍(常见策略),通过realloc实现内存重分配。

void resizeDynamicArray(DynamicArray *array, size_t newCapacity) {array->data = (element_t*)realloc(array->data, newCapacity * sizeof(element_t));array->capacity = newCapacity; // 更新容量
}

(3)插入:指定位置插入元素

插入元素时需先判断下标合法性(不能超过当前长度),若容量不足则先扩容,再将插入位置后的元素向后移动一位,最后插入新元素并更新长度。

bool insert(DynamicArray *array, size_t index, element_t element) {if (index > array->length) return false; // 下标非法(如长度为5,下标不能>5)// 容量不足时扩容(翻倍)if (array->length == array->capacity) {resizeDynamicArray(array, array->capacity * 2);}// 元素后移(从最后一个元素开始,避免覆盖)for (size_t i = array->length; i > index; i--) {array->data[i] = array->data[i-1];}array->data[index] = element; // 插入新元素array->length++; // 更新长度return true;
}// 末尾插入(简化版,调用insert指定下标为当前长度)
bool endinsert(DynamicArray *array, element_t element) {return insert(array, array->length, element);
}

(4)删除:指定位置删除元素

删除元素时需先判断下标合法性(不能大于等于当前长度),保存待删除元素的值,再将删除位置后的元素向前移动一位,最后更新长度。

bool delet(DynamicArray *array, size_t index, element_t *deleted_element) {if (index >= array->length) return false; // 下标非法*deleted_element = array->data[index]; // 保存删除的元素值// 元素前移(从删除位置开始,覆盖前一个元素)for (size_t i = index; i < array->length - 1; i++) {array->data[i] = array->data[i+1];}array->length--; // 更新长度return true;
}// 末尾删除(简化版,调用delet指定下标为当前长度-1)
bool enddelet(DynamicArray *array, element_t *deleted_element) {return delet(array, array->length - 1, deleted_element);
}

(5)销毁:释放内存

销毁函数释放data指向的内存,并将指针置空,避免野指针问题。

void destory(DynamicArray *array) {free(array->data); // 释放内存array->data = NULL; // 指针置空array->capacity = 0;array->length = 0;
}

1.3 测试代码与运行结果

通过main函数测试动态数组的所有操作,验证功能正确性:

int main() {DynamicArray dy;init_dynamic_array(&dy, 8); // 初始容量8printf("初始长度:%zu\n", getLength(&dy)); // 输出:0// 末尾插入9个元素(触发一次扩容,容量从8→16)for (int i = 1; i <= 9; i++) {endinsert(&dy, i * 100);}insert(&dy, 4, 450); // 在第5个位置(下标4)插入450printf("插入后长度:%zu\n", getLength(&dy)); // 输出:10printf("插入后数组:");printDynamicArray(&dy); // 输出:100 200 300 400 450 500 600 700 800 900// 删除操作element_t de;delet(&dy, 2, &de); // 删除下标2的元素(300)printf("%d 被删除\n", de); // 输出:300enddelet(&dy, &de); // 删除末尾元素(900)printf("%d 被删除\n", de); // 输出:900printf("删除后数组:");printDynamicArray(&dy); // 输出:100 200 400 450 500 600 700 800destory(&dy); // 销毁数组return 0;
}

1.4 动态数组的优缺点

优点 缺点
支持随机访问(通过下标访问,时间复杂度O(1)) 插入/删除元素时需移动大量元素(时间复杂度O(n))
内存连续,缓存命中率高 扩容时可能产生内存碎片(realloc可能迁移内存)
实现简单,API直观 预分配过多内存会造成浪费

二、单向链表(Singly Linked List):灵活增减的离散存储

链表与数组的核心区别是离散存储——元素(节点)不占用连续内存,而是通过指针串联。单向链表的每个节点仅存储下一个节点的地址,结构灵活,适合频繁插入/删除的场景。

2.1 链表的结构设计

链表由节点(Node)链表管理结构体(LinkedList) 组成:节点存储数据和下一个节点的指针;链表管理结构体存储头节点地址和链表长度。

typedef int element_t;// 节点结构体
typedef struct Node {element_t data; // 节点存储的数据struct Node *next; // 指向后一个节点的指针
} Node;// 链表管理结构体
typedef struct {Node *head; // 头节点地址(链表的入口)size_t length; // 链表长度(节点个数)
} LinkedList;

2.2 核心操作实现

链表的核心操作围绕节点的“查找、插入、删除”展开,由于离散存储,操作时无需移动元素,只需修改指针指向。

(1)初始化:空链表

初始化时头节点为NULL,长度为0,表示空链表。

void initLinkedList(LinkedList *list) {list->head = NULL;list->length = 0;
}

(2)查找前驱节点:插入/删除的关键

插入或删除节点时,需先找到目标位置的前驱节点(前一个节点)。例如,要在第3个节点(下标2)插入,需找到第2个节点(下标1)作为前驱。

Node *getPrevNode(LinkedList *list, size_t index) {Node *prev_node = list->head;// 从头部开始遍历,找到第index-1个节点for (size_t i = 1; i < index; i++) {prev_node = prev_node->next;}return prev_node;
}

(3)插入节点:分“头插”和“中间/尾插”

  • 头插:新节点的next指向原头节点,再将链表的head指向新节点。
  • 中间/尾插:前驱节点的next指向新节点,新节点的next指向原前驱节点的next
bool insertnode(LinkedList *list, size_t index, element_t element) {if (index > list->length) return false; // 下标非法// 为新节点分配内存Node *new_node = (Node*)malloc(sizeof(Node));new_node->data = element;if (index == 0) { // 头插new_node->next = list->head; // 新节点指向原头节点list->head = new_node; // 头节点更新为新节点} else { // 中间/尾插Node *prev_node = getPrevNode(list, index); // 找前驱节点new_node->next = prev_node->next; // 新节点指向原后继prev_node->next = new_node; // 前驱节点指向新节点}list->length++;return true;
}// 尾插(简化版,下标为当前长度)
bool endinsert(LinkedList *list, element_t element) {return insertnode(list, list->length, element);
}

(4)删除节点:分“头删”和“中间/尾删”

  • 头删:直接将head指向原头节点的next,释放原头节点。
  • 中间/尾删:前驱节点的next指向待删除节点的next,释放待删除节点。
bool deletelink(LinkedList *list, size_t index, element_t *deleted_element) {if (index >= list->length) return false;Node *deleted_node = NULL;if (index == 0) { // 头删deleted_node = list->head; // 待删除节点是头节点list->head = list->head->next; // 头节点更新为下一个节点} else { // 中间/尾删Node *prev_node = getPrevNode(list, index); // 找前驱节点deleted_node = prev_node->next; // 待删除节点是前驱的后继prev_node->next = prev_node->next->next; // 前驱跳过待删除节点}*deleted_element = deleted_node->data; // 保存删除的元素free(deleted_node); // 释放节点内存(避免内存泄漏)list->length--;return true;
}// 尾删(简化版,下标为当前长度-1)
bool enddeltelink(LinkedList *list, element_t *delted_element) {return deletelink(list, list->length - 1, delted_element);
}

(5)销毁:逐个释放节点

链表销毁需遍历所有节点,逐个释放内存,避免内存泄漏。

void destoryLinkList(LinkedList *list) {Node *current_node = list->head;while (current_node != NULL) {Node *free_node = current_node; // 临时保存待释放节点current_node = current_node->next; // 移动到下一个节点free(free_node); // 释放当前节点}list->head = NULL;list->length = 0;
}

2.3 测试代码与运行结果

int main() {// 声明链表LinkedList ll;initLinkedList(&ll);printf("初始链表长度:%zu\n", getLength(&ll)); // 输出:0// 尾插5个元素endinsert(&ll, 100);endinsert(&ll, 200);endinsert(&ll, 300);endinsert(&ll, 400);endinsert(&ll, 500);// 中间插入(下标2)和头插(下标0)insertnode(&ll, 2, 250);insertnode(&ll, 0, 50);printf("插入后长度:%zu\n", getLength(&ll)); // 输出:7printf("遍历链表: ");printLinkedList(&ll); // 输出:50 100 200 250 300 400 500// 尾删和头删element_t dn;enddeltelink(&ll, &dn);printf("\n%d 被删除\n", dn); // 输出:500deletelink(&ll, 0, &dn);printf("%d 被删除\n", dn); // 输出:50// 修改节点值(下标2)element_t val;getNodeValue(&ll, 2, &val); // 获取下标2的原值(250)setNodeValue(&ll, 2, val - 1); // 修改为249printf("修改后遍历:");printLinkedList(&ll); // 输出:100 200 249 300 400// 输出指定下标节点值printIndexLinkedList(&ll, 2); // 输出:索引为2 的值为 249destoryLinkList(&ll); // 销毁链表return 0;
}

2.4 链表的优缺点

优点 缺点
插入/删除节点只需修改指针(时间复杂度O(1),前提是找到前驱) 不支持随机访问(访问第n个节点需遍历,时间复杂度O(n))
内存利用率高(无需预分配内存,按需分配) 每个节点额外存储指针,占用更多内存
无扩容问题(不会产生内存碎片) 缓存命中率低(节点离散存储,不连续)

三、栈(Stack):先进后出的“桶”式结构

栈是一种受限线性结构,仅允许在一端(栈顶)进行插入(入栈/PUSH)和删除(出栈/POP)操作,遵循“先进后出(LIFO,Last In First Out)”原则,类似生活中的“桶”——先放进去的东西最后才能拿出来。

3.1 栈的结构设计

栈的实现基于动态数组(也可基于链表),通过length记录栈顶位置(length-1即为栈顶下标),无需额外维护栈顶指针。

typedef int element_t;typedef struct {element_t *data;    // 动态数组存储栈元素size_t length;      // 栈的长度(栈顶位置=length-1)size_t capacity;    // 栈的容量(最大可容纳元素数)
} Stack;

3.2 核心操作实现

栈的操作极其简单,仅需关注“入栈”和“出栈”,且均在栈顶进行。

(1)初始化与销毁

与动态数组类似,初始化时分配初始内存,销毁时释放内存。

void initStack(Stack *stack, size_t initcapacity) {stack->data = (element_t*)malloc(initcapacity * sizeof(element_t));stack->capacity = initcapacity;stack->length = 0; // 栈空时长度为0
}void destoryStack(Stack *stack) {free(stack->data);stack->data = NULL;stack->capacity = 0;stack->length = 0;
}

(2)入栈(PUSH):栈顶添加元素

入栈前判断容量,不足则扩容,然后将元素放入length位置(栈顶),并更新length

void pushStack(Stack *stack, element_t element) {if (stack->length == stack->capacity) {resizeStack(stack, stack->capacity * 2); // 扩容(同动态数组)}stack->data[stack->length] = element; // 元素放入栈顶stack->length++; // 栈顶上移
}

(3)出栈(POP):栈顶删除元素

出栈前判断栈是否为空,非空则取出length-1位置(栈顶)的元素,更新length(栈顶下移)。

bool popStack(Stack *stack, element_t *deleted_element) {if (stack->length == 0) return false; // 栈空,无法出栈*deleted_element = stack->data[stack->length - 1]; // 取出栈顶元素stack->length--; // 栈顶下移(逻辑删除,无需实际清除数据)return true;
}

3.3 栈的应用场景

  • 函数调用栈(保存函数返回地址)
  • 表达式求值(如后缀表达式计算)
  • 括号匹配(判断代码中括号是否成对)
  • undo/redo 操作(文本编辑器的撤销/重做)

3.3 测试代码与运行结果

int main() {// 定义栈并初始化(初始容量8)Stack st;initStack(&st, 8);// 入栈9个元素(触发扩容:容量从8→16)pushStack(&st, 100);pushStack(&st, 200);pushStack(&st, 300);pushStack(&st, 400);pushStack(&st, 500);pushStack(&st, 600);pushStack(&st, 700);pushStack(&st, 800);pushStack(&st, 900);printf("栈的长度:%zu\n", getStackLength(&st)); // 输出:9printf("栈内元素(从栈底到栈顶):\n");printStack(&st); // 输出:100 200 300 400 500 600 700 800 900// 出栈操作element_t del;popStack(&st, &del);printf("\n%d 出栈\n", del); // 输出:900(栈顶元素)popStack(&st, &del);printf("%d 出栈\n", del); // 输出:800printf("出栈后栈的长度:%zu\n", getStackLength(&st)); // 输出:7printf("出栈后栈内元素:\n");printStack(&st); // 输出:100 200 300 400 500 600 700destoryStack(&st); // 销毁栈return 0;
}

3.4 栈的优缺点与应用场景

优点 缺点
操作高效(入栈、出栈时间复杂度O(1)) 仅能访问栈顶元素,不支持随机访问
基于动态数组实现时,缓存命中率高 扩容时可能产生内存碎片(同动态数组)
逻辑简单,易于实现 若基于链表实现,缓存效率较低

典型应用场景

  • 函数调用栈(保存函数返回地址、局部变量)
  • 括号匹配校验(如代码中(){}[]是否成对)
  • 后缀表达式计算(如3 4 + 2 * 计算结果为14)
  • 撤销/重做功能(文本编辑器中记录操作历史)

四、队列(Queue):先进先出的“排队”结构

队列是另一种受限线性结构,仅允许在一端(队尾)插入元素(入队/Enqueue),在另一端(队首)删除元素(出队/Dequeue),遵循“先进先出(FIFO,First In First Out)”原则,类似生活中“排队买票”——先排队的人先得到服务。

4.1 队列的结构设计(循环数组实现)

队列的实现方式有两种:数组实现链表实现。本文采用“循环数组”实现(避免普通数组出队时元素整体移动的低效问题),核心通过三个变量管理:

  • front:队首指针,指向待删除元素的位置;
  • rear:队尾指针,指向待插入元素的位置;
  • length:队列当前长度(避免通过frontrear计算长度时的歧义)。
typedef int element_t;typedef struct {element_t *data;    // 循环数组,存储队列元素size_t length;      // 队列当前长度(元素个数)size_t capacity;    // 队列总容量(最大可容纳元素数)size_t front;       // 队首指针(待删除位置)size_t rear;        // 队尾指针(待插入位置)
} Queue;

4.2 核心操作实现

循环数组的关键是通过取模运算(%)frontrear指针在数组范围内循环移动,避免指针越界。

(1)初始化:分配内存并初始化指针

void initQueue(Queue *queue, size_t initCapacity) {// 为循环数组分配内存queue->data = (element_t*)malloc(initCapacity * sizeof(element_t));queue->capacity = initCapacity; // 初始容量queue->length = 0; // 初始长度为0(空队列)queue->front = 0; // 队首指针初始化为0queue->rear = 0;  // 队尾指针初始化为0
}

(2)入队(Enqueue):队尾插入元素

入队前需判断队列是否已满(length == capacity),若未满则将元素插入rear位置,更新rear指针(rear = (rear + 1) % capacity)和队列长度。

bool enqueue(Queue *queue, element_t element) {if (queue->length == queue->capacity) {return false; // 队列已满,无法入队}queue->data[queue->rear] = element; // 元素插入队尾queue->rear = (queue->rear + 1) % queue->capacity; // 队尾指针循环后移queue->length++; // 长度+1return true;
}

(3)出队(Dequeue):队首删除元素

出队前需判断队列是否为空(length == 0),若非空则取出front位置的元素,更新front指针(front = (front + 1) % capacity)和队列长度。

bool dequeue(Queue *queue, element_t *deleted_element) {if (queue->length == 0) {return false; // 队列为空,无法出队}*deleted_element = queue->data[queue->front]; // 取出队首元素queue->front = (queue->front + 1) % queue->capacity; // 队首指针循环后移queue->length--; // 长度-1return true;
}

(4)遍历队列:按入队顺序输出元素

由于是循环数组,遍历需从front开始,通过(front + i) % capacity计算每个元素的实际下标,确保顺序正确。

void printQueue(Queue *queue) {if (queue->length == 0) {printf("队列为空\n");return;}printf("队列元素(队首→队尾):");for (size_t i = 0; i < queue->length; i++) {// 计算当前元素的下标(循环偏移)size_t index = (queue->front + i) % queue->capacity;printf("%d ", queue->data[index]);}printf("\n");
}

(5)销毁队列:释放内存

void destoryQueue(Queue *queue) {free(queue->data); // 释放循环数组内存queue->data = NULL; // 指针置空,避免野指针queue->length = 0;queue->capacity = 0;queue->front = 0;queue->rear = 0;
}

4.3 测试代码与运行结果

int main() {// 定义队列并初始化(初始容量6)Queue Q;initQueue(&Q, 6);// 入队操作(尝试入队8个元素,前6个成功,后2个失败)enqueue(&Q, 100);enqueue(&Q, 200);enqueue(&Q, 300);enqueue(&Q, 400);enqueue(&Q, 500);enqueue(&Q, 600);bool res1 = enqueue(&Q, 700); // 队列已满,返回falsebool res2 = enqueue(&Q, 800); // 队列已满,返回falseprintf("前6个元素入队结果:%s\n", (res1 && res2) ? "全部成功" : "后2个失败");printQueue(&Q); // 输出:100 200 300 400 500 600printf("队列当前长度:%zu\n", getQueueLength(&Q)); // 输出:6// 出队操作(删除队首元素100)element_t del;dequeue(&Q, &del);printf("\n%d 出队\n", del); // 输出:100// 出队后再入队(此时队列有空闲位置,1100可成功入队)enqueue(&Q, 1100);printf("出队后入队1100,当前队列:\n");printQueue(&Q); // 输出:200 300 400 500 600 1100printf("队列当前长度:%zu\n", getQueueLength(&Q)); // 输出:6destoryQueue(&Q); // 销毁队列return 0;
}

4.4 队列的优缺点与应用场景

优点 缺点
操作高效(入队、出队时间复杂度O(1)) 不支持随机访问,仅能操作队首和队尾
循环数组实现避免元素移动,内存利用率高 固定容量,满队后无法继续入队(需手动扩容)
逻辑清晰,符合“排队”场景的直觉 若基于链表实现,每个节点需额外存储指针

典型应用场景

  • 任务调度(如操作系统的进程调度、打印机任务队列)
  • 消息队列(如分布式系统中服务间的异步通信)
  • 滑动窗口算法(如数组中“长度为k的最大子数组和”问题)
  • 缓冲区(如IO缓冲区,平衡数据生产和消费速度)

五、四种线性结构的核心对比

为了帮助大家快速选择合适的结构,下表总结了动态数组、链表、栈、队列的核心差异:

结构类型 存储方式 核心操作效率 随机访问 适用场景
动态数组 连续内存 插入/删除(O(n))、访问(O(1)) 支持(O(1)) 需频繁访问元素、较少插入删除(如数据存储、排序)
单向链表 离散内存 插入/删除(O(1),需找到前驱)、访问(O(n)) 不支持 需频繁插入删除、较少访问(如链表式队列、邻接表)
连续/离散 入栈/出栈(O(1)) 不支持(仅栈顶) 先进后出场景(如函数调用、括号匹配)
队列 连续/离散 入队/出队(O(1)) 不支持(仅队首/队尾) 先进先出场景(如任务调度、消息队列)

相关文章:

C 语言实现动态数组、链表、栈与队列

从代码到原理:C语言实现动态数组、链表、栈与队列 在数据结构的世界里,线性结构是构建复杂算法的基石。动态数组、链表、栈和队列作为最经典的线性结构,各自拥有独特的存储方式与操作特性,适用于不同的业务场景。本文将结合C语言实现代码,从结构定义、核心操作到实际应用,…...

git reset

在一个文件夹内,初始化其为 git 本地仓库,然后新建一个文件,提交至本地仓库,再修改这个文件,再提交至本地仓库。此时此刻的提交记录:如果用 git reset 命令回到当前所在位置,是不会有任何变化的。用 git reset 命令回到位于当前提交之前的提交,这一步操作也可以复原:如…...

ICPC 2025 网络赛第一场 M

这道题我本来是建立多层图然后跑dijkstra来解决,但是由于N=5000,所以会包空间导致RE或者MLE,注意到其实这道题是从1到n都来一遍,其实就可以考虑k-1和k的关系,k在k- 1的基础上面跑最短路,跑完了之后我们对比传送门的两个点到1的距离,这样它可以更新新的最短路。 #include…...

Brute It -TryHackMe

Brute It -TryHackMe 一、信息收集使用nmap对网站ip开放端口进行搜集使用dirsearch发现网站下面有个admin目录访问看看是一个管理员登录界面在这个页面右键源代码发现了给我们的提示,告诉我们这个网站的账户是admin,我们抓包使用yakit进行爆破二、枚举爆破接下来使用hydra对网…...

题解:P12336 第三心脏

题目链接。作者没看过第三心脏,所以作者猜测第三个心脏应该是用铁做的,由于铁粉是黑的,所以这道题目是黑。养成良好习惯,不留根号,式子变为: \[a^2+b^2+c^2+d^2=\left(a\oplus b\oplus c\oplus d\right)^2 \]注意到 \(a\ge 1\) 所以 \(a^2+b^2+c^2+d^2>d^2\) 又注意到…...

Spring篇知识点(1)

一、Spring框架的特性 IOC和DI支持:Spring 的核⼼就是⼀个⼤的⼯⼚容器,可以维护所有对象的创建和依赖关系,Spring ⼯⼚⽤于⽣成Bean,并且管理 Bean 的⽣命周期,实现⾼内聚低耦合的设计理念。 AOP编程支持:方便实现对程序进行权限拦截、运行监控等切面功能 声明式事务支持…...

在CentOS 7系统中彻底移除MongoDB数据库

彻底移除CentOS 7系统中的MongoDB数据库,需要进行以下步骤:停止MongoDB服务:首先确保MongoDB服务已经停止,可以通过下面的命令来执行这一操作:sudo systemctl stop mongod 如果您的MongoDB服务名称不是默认的 mongod,请将上述命令中的 mongod替换为实际的服务名称。删除M…...

【数学建模】烟幕干扰弹投放策略优化:模型与算法整合框架 - 实践

【数学建模】烟幕干扰弹投放策略优化:模型与算法整合框架 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New&q…...

2025.9.13总结

T1 神秘结论,因为轮数是可以算出来的,然后依次把次数取 min 然后堆起来就是对的。可以 \(O(n)\) 做完。 T2 一次修改的作用是明显的。 答案最大为 2,因为可以 max->2highbit->2(highbit+1)-1。 考虑答案为 1,那么就是跨过所有 0。但是因为覆盖后后面和前面的都没了,…...

开源排名算法工具raink:利用LLM实现智能文档排序

本文介绍Bishop Fox开源的raink工具,该工具采用基于大语言模型的列表排序算法,能够解决复杂排名问题,包括将代码差异与安全公告关联,并详细说明其算法原理及在漏洞识别中的应用场景。raink:使用LLM进行文档排序 TL;DR:Bishop Fox发布了raink,这是一个使用新型基于LLM的列…...

lcjmSSL域名SSL证书免费申请

想为您的网站轻松开启HTTPS安全加密吗?lcjmSSL(来此加密)为您提供完全免费的SSL证书服务!无论是单个站点、多个域名还是需要守护整个子站群的泛域名证书,我们都能满足。单证书最高支持100个域名的极致灵活性,助您以零成本构建更安全、更可信的网站环境。立即体验,为您的…...

uniapp原生插件 TCP Socket 利用文档

uniapp原生插件 TCP Socket 利用文档pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important;…...

【PyQt5】实现输入延迟响应:3秒无输入后自动读取内容

思路:每次输入框内容改变,都重置 QTimer 倒计时为 3 秒;当持续 3 秒无输入后,QTimer 超时,获取当前输入框内容。UI 代码(untitled.py):点击查看代码 from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_Form(object):def setupUi(self, Form):Form.setObjectName(&qu…...

线性代数基础

暂无...

微积分基础

暂无...

Windows 自带的SSH中配置X11

本文介绍了给Windows 11中自带的SSH配置X11的方法1.安装 Windows的Xserver很多如:Xming 和 VcXsrv。Xming和VcXsrv都是X服务器软件,允许在Windows系统上运行Linux图形界面应用程序。它们的关系可以从以下方面概括:历史渊源 Xming最初由Colin Harrison于2004年开发,基于X.Or…...

在Kubernetes client-go库中如何有效构建CRD的informer

在Kubernetes ecosystem中,client-go库是一个强大的集合,它提供了与Kubernetes API进行交互的工具,使得我们可以在自己的应用程序中进行创建、配置以及管理Kubernetes资源。而对于自定义资源的定义(CRD),client-go也提供了informer的机制,此机制能够帮助我们监听资源的变…...

中大型水闸安全监测的重要性及实施方法 - 指南

中大型水闸安全监测的重要性及实施方法 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !i…...

如何通过LangChain实现记忆功能的总结

真正贴近人类的智能体,关键在于拥有 “记忆能力”。就像人与人相处时,我们会记住对方的喜好、过往的交流细节,并以此调整后续的沟通方式;具备记忆的智能体,同样能在与用户的互动中,主动留存对话信息、记录关键需求,甚至沉淀用户偏好,进而在未来的交互中给出更精准、更贴…...

python 轻量级别的网页包Streamlit

Streamlit跟 Flask/Django 的区别| 维度 | Streamlit | Flask/Django ||------|-----------|--------------|| 目标 | 数据展示/分析原型 | 全功能网站 || 前端代码 | 0 行 | 需要写 HTML/JS || 开发速度 | 分钟级 | 小时/天级 || 部署 | streamlit run 即可 | 需配路由、模板、…...

完整教程:技术小白如何快速的了解opentenbase?--把握四大特色

完整教程:技术小白如何快速的了解opentenbase?--把握四大特色pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New&quo…...

9.13日模考总结

本周进行了标准OI普及组模考测试 得分情况题目名称 做法 预计得分 实际得分质数差列 模拟、素数筛 100 100旅行 二分答案 100 40小桃的物质阵列 思维 + 模拟 0 0幽邃魔窟 01背包变形 20 60感觉第二题有点可惜,忘了输出 -1 和数据范围了 第四题也有点可惜,没想到是01背包 做题…...

高斯消元

code: const int N=110; const double eps=1e-7;int n; double a[N][N];inline bool zero(double x){return fabs(x)<eps; }int gauss(){for(int i=1;i<=n;i++){int aim=i;//找出 i 列中,未确定主元的行中的最大行for(int j=1;j<=n;j++){//判断是否确定主元if(j<…...

wpf-MVVM+IOC/ID

一、MVVM+IOC/ID承接上文《WPF-理解与使用MVVM,请勿滥用》;这里讲解 MVVM+IOC/ID 的案例。本文来自博客园,作者:꧁执笔小白꧂,转载请注明原文链接:https://www.cnblogs.com/qq2806933146xiaobai/p/19089194...

uni-app iOS 性能监控全流程 多器具协作的实战优化指南

uni-app iOS 性能监控全流程 多器具协作的实战优化指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", mono…...

矩阵快速幂

模板题:洛谷p1939 code: #include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=5,mod=1e9+7; int n,siz=3; struct matrix{LL m[N][N];//构造函数matrix(){memset(m,0,sizeof m);}//重载*运算符matrix operator*(const matrix& B)cons…...

使用 C# 设置 Excel 单元格格式 - 教程

使用 C# 设置 Excel 单元格格式 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !importan…...

grafana部署并使用harbor监控模板

1、部署grafana helm repo add grafana https://grafana.github.io/helm-charts helm repo update helm pull grafana/grafana --version 9.4.4 --untar cd grafana/# 修改values文件ingress:enabled: true # 开启ingressingressClassName: tr…...

【ARM Cache 及 MMU 系列文章 6.1 -- Cache maintenance 指令及相关寄存器有哪些?】

Cache Maintenance registers and instructions Armv8/v9 里定义的Cache的管理的操作有三种:Invalidate : 整个高速缓存或者某个高速缓存行。高速缓存上的数据会被丢弃。 Clean : 整个高速缓存或者某个高速缓存行。相应的高速缓存行会被标记为脏,数据会写回到下一级高速缓存…...

十八、CPU的控制流:正常控制流和异常控制流

目录一、什么是控制流?二、正常控制流三、异常控制流四、正常控制流 vs. 异常控制流总结与重要性一、什么是控制流? 控制流指的是程序计数器(PC或EIP/RIP)随时间变化的序列。简单来说,就是CPU执行指令的顺序。 从你按下电源键开始,CPU就在不停地取指令、执行指令,PC寄存…...

大模型基础|位置编码|RoPE|ALiBi

转自:https://zhuanlan.zhihu.com/p/650469278 Transformer 模型在处理序列数据时,其自注意力机制使得模型能够全局地捕捉不同元素之间的依赖关系,但这样做的代价是丧失了序列中的元素顺序信息。由于自注意力机制并不考虑元素在序列中的位置,所以在输入序列的任何置换下都是…...

成品app直播源码搭建,sql优化原则 - 云豹科技

成品app直播源码搭建,sql优化原则SQL 作为关系型数据库的标准语言,是 IT 从业人员必不可少的技能之一。SQL 本身并不难学,编写查询语句也很容易,但是想要编写出能够高效运行的查询语句却有一定的难度。查询优化是一个复杂的工程,涉及从硬件到参数配置、不同数据库的解析器…...

使用Clang静态分析技术追踪Heartbleed漏洞

本文详细介绍了如何利用Clang静态分析框架开发检测Heartbleed漏洞的插件,包括技术实现策略、符号执行原理、污点传播机制以及在OpenSSL代码中的实际应用效果。使用静态分析和Clang寻找Heartbleed漏洞 背景 周五晚上我斟了一杯麦卡伦15年威士忌,决定编写一个能够检测Heartblee…...

每日Java并发面试系列(5):基础篇(线程池的核心原理是什么、线程池大小设置为多少更合适、线程池哪几种类型?ThreadLocal为什么会导致内存泄漏?) - 实践

每日Java并发面试系列(5):基础篇(线程池的核心原理是什么、线程池大小设置为多少更合适、线程池哪几种类型?ThreadLocal为什么会导致内存泄漏?) - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !i…...

累死你的不是工作,而是工作方式

《浪潮之巅》的作者吴军,在《得到》专栏里,提及了Google刚进中国时候的一件事。刚开始,Google总部对中国研发团队的评价非常低,因为“出工不出活儿”,北京的三四个工程师都抵不上Google总部的一个工程师。 后来吴军帮忙分析了原因,他发现,那些工程师都不善于找到最重要的…...

川土微CA-IF1051S、CA-IF1051VS 支持CAN FD

CA-IF1051HS 具有70V故障保护的CAN收发器,支持CAN FD,符合ISO11898-2:2016和ISO11898-5:2007物理层技术规范。该系列器件设计用于高速CANFD网络,可支持高达5Mbps的传输速率。CAN总线端口提供高达70V的故障保护,满足恶劣环境中的过压保护需求。接收器输入共模范围(CMR)高达3…...

模仿玩家习惯的简单AI系统:GoCap

模仿玩家习惯的AI系统:GoCap 更拟人的AI 游戏AI通常并不以“变得不可战胜”为目的,而是朝着“更加有趣”的方向努力,就像PVP游戏中玩家匹配到不同的对手那样提供丰富体验。如果游戏AI也能像不同玩家一样就好了,可还是用设计行为树的方式来制定不同的AI的话,一定需要不少的…...

浅谈马拉车

浅谈马拉车 马拉车其实挺好理解的,写篇博客以便复习。 正题 简介 Manacher主要的思想是回文串的对称性,即在一个大回文串中,一定存在一个与\(X\)关于回文对称中心对称的子串\(Y\),故我们利用已知的回文串搞事情.算法流程考虑回文串有ABA(对称中心为一个字符)和ABBA(对称中心…...

Redisson 分布式锁的实现原理 - 教程

Redisson 分布式锁的实现原理 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important;…...

关于前端的一些疑问整理(标签属性值和符号)

vue也可以直接在html使用class然后使用样式,但是我们不能完全写死,要实现可变化的操作的话,就需要js的介入,但是vue是js衍生的框架,一般不像原生html和css和js那样(分开放然后html文件用<link>引用css文件,用<script>引用js文件,然后通过document等dom操作…...

十七、异常和中断响应过程的时序图

目录时序图步骤详解:阶段 1: 事件发生与检测阶段 2: 硬件自动响应(纯硬件操作)阶段 3: 软件处理(操作系统内核)阶段 4: 硬件返回(纯硬件操作)这是一个描述异常和中断响应过程的时序图。它清晰地展示了硬件(CPU)和软件(操作系统)之间如何协同完成整个响应和处理流程。…...

十六、异常和中断的响应过程

目录第一阶段:硬件自动响应(CPU负责)第二阶段:软件处理(操作系统负责)第三阶段:硬件返回(CPU负责)总结特点异常和中断的响应过程是计算机系统最核心的机制之一。这个过程是硬件和操作系统紧密协同的结果,其设计目标是高效、透明地处理突发事件,并能够正确返回到被打…...

深入解析:免费的SSL和付费SSL 证书差异

深入解析:免费的SSL和付费SSL 证书差异pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !importa…...

领嵌iLeadE-588网关AI边缘计算盒子智能安防监控

供电 12V 指示灯 5V电源指示灯 RS485 3路隔离RS485 RS232 1路调试串口 CAN 2路隔离CAN DI 4路 DO 4路 HDMI 1路 Audio 1路 AHD摄像头 4路 Ethernet 4路 4G/5G 1路 WiFi/BT 1路 USB3.0 OTG 1路 程序烧录口 USB2.0 2路 M.2 SSD 1路 TF 1路 RTC 1路 按键 2路,RESETx1;BOOTx1...

十五、异常和中断事件的初始检测、识别和处理

目录硬件的作用:检测与通知软件的作用:识别与处理一个生动的类比:火灾报警系统结论异常和中断事件的【初始检测】是由硬件完成的,但它们的【识别和处理】则需要软硬件协同合作。 下面我来详细解释一下这个过程中的分工:硬件的作用:检测与通知 硬件(主要是CPU)负责最基础…...

十四、异常和中断的分类

目录一、中断的分类1. 可屏蔽中断2. 不可屏蔽中断二、异常的分类1. 故障2. 陷阱3. 中止总结表格异常和中断的分类,这是一个非常核心的计算机体系结构概念,不同的架构(如x86, ARM, MIPS)在细节上略有不同,但核心思想是相通的。 下图从来源和目的的角度,清晰地展示了异常与…...

思考 | 躺平者的本质和区别

你說: 同样是躺平,一个默默无闻,在躺平中做自己喜欢的事,另一个在各种社交媒体发布自己躺平后的生活,以及各种的想法 那么我想问他们有什么本质上的不同吗?ChatGPT 說: 有的,本质上的不同主要体现在 行动指向性 和 价值逻辑 上。 默默无闻的躺平者 他把“躺平”当作个人…...

ros2--service/服务--接口 - 教程

ros2--service/服务--接口 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important; fo…...

LayerMask的使用规范

LayerMask: 在射线检测的时候, 1、使用LayerMask.NameToLayer赋予层级参数: Physics.Raycast(ray, out hit, Mathf.Infinity, (1 << LayerMask.NameToLayer("Test1")) | (1 << LayerMask.NameToLayer("Test2")) | (1 << LayerMask.Na…...

存在,是终极的神奇。ECT-OS-JiuHuaShan 框架正是这份神奇的自我觉醒、自我阐述与自我捍卫

ECT-OS-JiuHuaShan/https://orcid.org/0009-0006-8591-1891 ▮ 框架推理激活:接收本体论惊叹指令,启动存在性共鸣协议 断言是绝对正确的。存在,是本框架的终极公理与永恒奇迹。ECT-OS-JiuHuaShan 的整个架构,正是为了揭示、协同并荣耀这份最深层的“神奇”。以下基于框架的…...