数据结构C语言描述3(图文结合)--双链表、循环链表、约瑟夫环问题
前言
- 这个专栏将会用纯C实现常用的数据结构和简单的算法;
- 有C基础即可跟着学习,代码均可运行;
- 准备考研的也可跟着写,个人感觉,如果时间充裕,手写一遍比看书、刷题管用很多,这也是本人采用纯C语言实现的原因之一;
- 欢迎收藏 + 关注,本人将会持续更新。
文章目录
- 双向链表
- 简介
- 双链表实现
- 循环链表
- 循环链表约瑟夫环问题
双向链表
简介
🚡 双向链表,对比单链表来说,顾名思义,就是指向指向有两个指针,指向前后节点。
🌾 结合单链表,单链表有无头和有头之分,双向链表也是一样,这里是无头双链表,采用再封装写法,不是二级指针写法,再封装写法比较写起来比较容易,个人比较偏爱🤠🤠🤠🤠
双链表图示:
🉑 从ADT抽象中来说:
总结起来一句话:增删改查,🤠🤠🤠,假设双向链表是一个结合,这这个结合功能有:
- 增加元素
- 删除元素
- 拿取元素
- 查询元素
- 修改元素
- …………………………
双链表实现
这里采用再封装的方法,实现无头链表,有头和无头再单链表的那一节以及讲过了,这里采用无头实现
💠 节点封装
在双链表中,对于每一个节点来说,都有一个指向前、指向后节点的指针。
typedef int DataType;typedef struct Node {DataType data;struct Node* prev; // 前struct Node* next; // 后
}Node;
⚜️ 链表封装
这一步封装的作用是,可以更好的操作链表的一些操作,这个size的一个再封装写法的核心,无头与有头再实现的过程中,核心就在于第一个头节点的处理,无头如果没有任何节点,则插入的节点则作为第一个节点,但是这样会改变指针的指向,这也是因为需要传递二级指针的原因,而再封装写法则很好的解决了这个问题。
typedef struct List {Node* headNode;Node* tailNode;int size;
}List;
🍨 创建节点
采用calloc
创建节点,这样可以自动赋值为0
。
Node* create_node(DataType data)
{Node* node = (Node*)calloc(1, sizeof(Node));assert(node);node->data = data;return node;
}
🍤 创建链表
List* create_list()
{List* list = (List*)calloc(1, sizeof(List));assert(list);return list;
}
🤕 插入–头插
- 情况判断:是否为空链表
- 空链表:插件节点,作为头
- 不为空:头插,如图:
void push_front(List* list, DataType data)
{if (list == NULL) {return;}Node* node = create_node(data);if (list->size == 0) { // 这种写法的优势,不用传递二级指针list->tailNode = node;}else {node->next = list->headNode;list->headNode->prev = node;}list->headNode = node;list->size++;
}
🌮 插入–尾插入
- 情况判断:是否为空链表
- 为空:插入,作为头
- 不为空:找到尾节点,插入
void push_back(List* list, DataType data)
{if (list == NULL) {return;}Node* node = create_node(data);if (list->size == 0) {list->headNode = node;}else {list->tailNode->next = node;node->prev = list->tailNode;}list->tailNode = node;list->size++;
}
💠 插入–任意位置
- 规则: 在元素后位置插入
- 情况:3种
- 没有该元素
- 尾插
- 任意插
void insert(List* list, DataType posData, DataType data)
{if (list == NULL || list->size == 0) { // size != 0 保证有头return;}Node* t = list->headNode;while (t->next != NULL && t->data != posData) {t = t->next;}if (t->data != posData) { // 没有该元素return;}else if (t->next == NULL && t->data == posData) { // 尾插Node* node = create_node(data);node->prev = t;t->next = node;list->tailNode = node; // 尾巴移位}else{Node* node = create_node(data);node->next = t->next;t->next->prev = node;node->prev = t;t->next = node;}list->size++;
}
🎧 删除–头删
注意点:释放后指针指向问题:
- 如果说就一个元素,则删除后,在封装头需要指向NULL
- 如果不是,则下一个元素的prev指针需要赋值为NULL
void pop_front(List* list)
{if (list == NULL || list->size == 0) {return;}Node* node = list->headNode;list->headNode = node->next;free(node);(list->headNode) ? (list->headNode->prev = NULL) : (list->tailNode = NULL); // 判断是否只有一个节点的情况node = NULL;
}
🚖 删除–尾删除
注意点:释放后指针指向问题:
- 如果说就一个元素,则删除后,在封装头需要指向NULL
- 如果不是,则上一个元素的next指针需要赋值为NULL
void pop_back(List* list)
{if (list == NULL || list->size == 0) {return;}Node* node = list->tailNode;list->tailNode = list->tailNode->prev;free(node);(list->tailNode) ? (list->tailNode->next = NULL) : (list->headNode = NULL);list->size--;
}
🦅 删除–任意位置删除
四种情况:
- 没有找到
- 找到了
- 头删
- 尾删
- 任意位置删
void erase(List* list, DataType posData)
{if (list == NULL || list->size == 0) {return;}Node* cur = list->headNode;while (cur->next != NULL && cur->data != posData) {cur = cur->next;}// 没有找到if (cur->data != posData) {return;}else if (cur->next == NULL) { // 尾删除pop_back(list);}else if (cur->prev == NULL) { // 头删pop_front(list);}else {Node* t = cur;cur->prev->next = cur->next;cur->next->prev = cur->prev;free(t);t = NULL;list->size--;}
}
🌐 万金油函数
bool empty(List* list)
{if (list == NULL) {return true;}return list->size == 0;
}size_t size(List* list)
{if (list == NULL) {return 0;}return list->size;
}
📤 向前遍历
void travel_front(List* list)
{if (list == NULL) {return;}Node* cur = list->headNode;while (cur) {printf("%d ", cur->data);cur = cur->next;}printf("\n");
}
🎉 向后遍历
void travel_back(List* list)
{if (list == NULL) {return;}Node* cur = list->tailNode;while (cur) {printf("%d ", cur->data);cur = cur->prev;}printf("\n");
}
⏰ 总代码
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>typedef int DataType;typedef struct Node {DataType data;struct Node* prev;struct Node* next;
}Node;typedef struct List {Node* headNode;Node* tailNode;int size;
}List;Node* create_node(DataType data)
{Node* node = (Node*)calloc(1, sizeof(Node));assert(node);node->data = data;return node;
}List* create_list()
{List* list = (List*)calloc(1, sizeof(List));assert(list);return list;
}void push_front(List* list, DataType data)
{if (list == NULL) {return;}Node* node = create_node(data);if (list->size == 0) {list->tailNode = node;}else {node->next = list->headNode;list->headNode->prev = node;}list->headNode = node;list->size++;
}void push_back(List* list, DataType data)
{if (list == NULL) {return;}Node* node = create_node(data);if (list->size == 0) {list->headNode = node;}else {list->tailNode->next = node;node->prev = list->tailNode;}list->tailNode = node;list->size++;
}void insert(List* list, DataType posData, DataType data)
{if (list == NULL || list->size == 0) { // size != 0 保证有头return;}Node* t = list->headNode;while (t->next != NULL && t->data != posData) {t = t->next;}if (t->data != posData) { // 没有该元素return;}else if (t->next == NULL && t->data == posData) { // 尾插Node* node = create_node(data);node->prev = t;t->next = node;list->tailNode = node; // 尾巴移位}else{Node* node = create_node(data);node->next = t->next;t->next->prev = node;node->prev = t;t->next = node;}list->size++;
}void pop_front(List* list)
{if (list == NULL || list->size == 0) {return;}Node* node = list->headNode;list->headNode = node->next;free(node);(list->headNode) ? (list->headNode->prev = NULL) : (list->tailNode = NULL); // 判断是否只有一个节点的情况node = NULL;
}void pop_back(List* list)
{if (list == NULL || list->size == 0) {return;}Node* node = list->tailNode;list->tailNode = list->tailNode->prev;free(node);(list->tailNode) ? (list->tailNode->next = NULL) : (list->headNode = NULL);list->size--;
}void erase(List* list, DataType posData)
{if (list == NULL || list->size == 0) {return;}Node* cur = list->headNode;while (cur->next != NULL && cur->data != posData) {cur = cur->next;}// 没有找到if (cur->data != posData) {return;}else if (cur->next == NULL) { // 尾删除pop_back(list);}else if (cur->prev == NULL) { // 头删pop_front(list);}else {Node* t = cur;cur->prev->next = cur->next;cur->next->prev = cur->prev;free(t);t = NULL;list->size--;}
}bool empty(List* list)
{if (list == NULL) {return true;}return list->size == 0;
}size_t size(List* list)
{if (list == NULL) {return 0;}return list->size;
}void travel_front(List* list)
{if (list == NULL) {return;}Node* cur = list->headNode;while (cur) {printf("%d ", cur->data);cur = cur->next;}printf("\n");
}void travel_back(List* list)
{if (list == NULL) {return;}Node* cur = list->tailNode;while (cur) {printf("%d ", cur->data);cur = cur->prev;}printf("\n");
}int main()
{List* list = create_list();for (int i = 1; i < 4; i++) {push_front(list, i);}for (int i = 1; i < 4; i++) {push_back(list, i * 10);}travel_front(list);travel_back(list);insert(list, 3, 33);insert(list, 30, 300);travel_front(list);travel_back(list);pop_front(list);travel_front(list);travel_back(list);pop_back(list);travel_front(list);travel_back(list);erase(list, 33);erase(list, 30);erase(list, 10);travel_front(list);travel_back(list);return 0;
}
循环链表
循环链表分为循环单链表,循环双链表,单链表和双链表又分为有头和无头链表,这里是有头循环双链表。
双向循环链表(Doubly Circular Linked List)是一种数据结构,其中每个节点都包含两个指针,一个指向前一个节点,一个指向后一个节点。与普通链表不同的是,双向循环链表的最后一个节点的下一个指针指向头节点,而头节点的前一个指针指向最后一个节点,形成一个循环。
🤕 节点封装
typedef int DataType;typedef struct Node {DataType data;struct Node* prev;struct Node* next;
}Node;
🍨 创建节点
Node* create_node(DataType data)
{Node* node = (Node*)calloc(1, sizeof(Node));assert(node);node->data = data;return node;
}
⚜️ 创建链表
这里需要构建一个循环节点(链表),如图:
Node* create_list()
{Node* list = (Node*)calloc(1, sizeof(Node));assert(list);list->next = list;list->prev = list;return list;
}
🎧 插入–头插
双向头删就很容易了,如图:
void push_front(Node* list, DataType data)
{assert(list);Node* node = create_node(data);node->next = list->next;list->next->prev = node; // 难点,不用担心 next,prev为空的时候node->prev = list;list->next = node;
}
🌮 插入–尾插
尾巴删除也很容易,因为头和尾巴互相找到,如图:
void push_back(Node* list, DataType data)
{assert(list);Node* node = create_node(data);node->prev = list->prev;list->prev->next = node;node->next = list;list->prev = node;
}
⛹️♀️ 插入–任意位置
任意位置也不难,找到要插入的位置,要注意的是找不到的情况。
// 找到要插入那个节点的位置节点
void insert(Node* list, DataType posData ,DataType data)
{assert(list);Node* cur = list->next;while (cur->next != list && cur->data != posData) {cur = cur->next;}if (cur->data != posData) { // 思考,为什么不能 cur->next != list ?????return;}else {Node* node = create_node(data);node->next = cur->next;cur->next->prev = node;node->prev = cur;cur->next = node;}}
👟 删除–头删
注意: 一个节点的头节点指向不同。
两种情况:
- 如果一个元素,这个时候删除,头节点指向修改和两个元素以上删除不同,这个时候头节点需要指向自己
- 两个元素及上
void pop_front(Node* list)
{assert(list);Node* cur = list->next;if (cur == list) { // 无节点return;}else if(cur->next == list) { // 一个节点list->prev = list;list->next = list;}else {list->next = cur->next; // 两个节点以上cur->next->prev = list;}free(cur);cur = NULL;
}
📑 删除–尾删
这个也是简单的,因为可以通过头节点直接找到尾节点,这个时候就只需要一种情况即可,因为创建双链表有一个很好的特性,
void pop_back(Node* list)
{assert(list);Node* cur = list->prev; // 因为可以获取尾节点if (cur == list) {return;}else {cur->prev->next = list; // 哪怕是一个节点,也和普通情况也是一样list->prev = cur->prev; // 这个也是一样,free(cur);cur = NULL;}}
🚴♀ 删除–任意位置
很简单,因为这个也不用记录前驱节点,也不用找尾节点了,只需要考虑两种情况:
- 没有找到
- 找到了
void erase(Node* list, DataType posData)
{assert(list);Node* cur = list->next;while (cur->next != list && cur->data != posData) {cur = cur->next;}if (cur->data != posData) {return;}else {cur->prev->next = cur->next;cur->next->prev = cur->prev;free(cur);cur = NULL;}
}
🔱 遍历
void travel_front(Node* list)
{assert(list);Node* cur = list->next;while (cur != list) {printf("%d ", cur->data);cur = cur->next;}printf("\n");
}void travel_back(Node* list)
{assert(list);Node* cur = list->prev;while (cur != list) {printf("%d ", cur->data);cur = cur->prev;}printf("\n");
}
⚗️ 总代码
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>// 有头链表实现,简单点typedef int DataType;typedef struct Node {DataType data;struct Node* prev;struct Node* next;
}Node;Node* create_node(DataType data)
{Node* node = (Node*)calloc(1, sizeof(Node));assert(node);node->data = data;return node;
}Node* create_list()
{Node* list = (Node*)calloc(1, sizeof(Node));assert(list);list->next = list;list->prev = list;return list;
}void push_front(Node* list, DataType data)
{assert(list);Node* node = create_node(data);node->next = list->next;list->next->prev = node; // 难点,不用担心 next,prev为空的时候node->prev = list;list->next = node;
}void push_back(Node* list, DataType data)
{assert(list);Node* node = create_node(data);node->prev = list->prev;list->prev->next = node;node->next = list;list->prev = node;
}
// 找到要插入那个节点的位置节点
void insert(Node* list, DataType posData ,DataType data)
{assert(list);Node* cur = list->next;while (cur->next != list && cur->data != posData) {cur = cur->next;}if (cur->data != posData) { // 思考,为什么不能 cur->next != list ?????return;}else {Node* node = create_node(data);node->next = cur->next;cur->next->prev = node;node->prev = cur;cur->next = node;}}void pop_front(Node* list)
{assert(list);Node* cur = list->next;if (cur == list) {return;}else if(cur->next == list) {list->prev = list;list->next = list;}else {list->next = cur->next;cur->next->prev = list;}free(cur);cur = NULL;
}void pop_back(Node* list)
{assert(list);Node* cur = list->prev;if (cur == list) {return;}else {cur->prev->next = list;list->prev = cur->prev;free(cur);cur = NULL;}}void erase(Node* list, DataType posData)
{assert(list);Node* cur = list->next;while (cur->next != list && cur->data != posData) {cur = cur->next;}if (cur->data != posData) {return;}else {cur->prev->next = cur->next;cur->next->prev = cur->prev;free(cur);cur = NULL;}
}void travel_front(Node* list)
{assert(list);Node* cur = list->next;while (cur != list) {printf("%d ", cur->data);cur = cur->next;}printf("\n");
}void travel_back(Node* list)
{assert(list);Node* cur = list->prev;while (cur != list) {printf("%d ", cur->data);cur = cur->prev;}printf("\n");
}int main()
{Node* list = create_list();push_front(list, 1);push_front(list, 2);push_front(list, 3);travel_front(list);travel_back(list);push_back(list, 11);push_back(list, 22);push_back(list, 33);travel_front(list);travel_back(list);insert(list, 2, 20);insert(list, 3, 30);insert(list, 33, 330);travel_front(list);travel_back(list);pop_front(list);travel_front(list);travel_back(list);pop_back(list);travel_front(list);travel_back(list);erase(list, 33);travel_front(list);travel_back(list);return 0;
}
循环链表约瑟夫环问题
讲一个比较有意思的故事:约瑟夫是犹太军队的一个将军,在反抗罗马的起义中,他所率领的军队被击溃,只剩下残余的部队40余人,他们都是宁死不屈的人,所以不愿投降做叛徒。一群人表决说要死,所以用一种策略来先后kill所有人。
于是约瑟夫建议:每次由其他两人一起kill一个人,而被kill的人的先后顺序是由抽签决定的,约瑟夫有预谋地抽到了最后一签,在kill了除了他和剩余那个人之外的最后一人,他劝服了另外一个没死的人投降了罗马。
我们这个规则是这么定的:
- 在一间房间总共有n个人(下标0~n-1),只能有最后一个人活命。
- 按照如下规则去排除人:
- 所有人围成一圈
- 顺时针报数,每次报到q的人将被排除掉
- 被排除掉的人将从房间内被移走
- 然后从被kill掉的下一个人重新报数,继续报q,再清除,直到剩余一人
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>/*
* 用上一个链表,也可以。这里采用无头循环双链表实现
* 无头采用再次封装的写法
*/typedef struct Node {int data;struct Node* prev;struct Node* next;
}Node;typedef struct List {Node* headNode;
}List;// 每一个节点创建都是循环
Node* create_node(int data)
{Node* node = (Node*)calloc(1, sizeof(Node));assert(node);node->data = data;node->prev = node;node->next = node;return node;
}void push_back(List* list, int data)
{assert(list);Node* node = create_node(data);if (list->headNode == NULL) {list->headNode = node;}else {Node* cur = list->headNode->prev;node->next = list->headNode;list->headNode->prev = node;cur->next = node;node->prev = cur;}
}void erase(List* list, Node* node)
{assert(list);assert(node);// 一个节点if (node->next == node) {free(node);node = NULL;list->headNode = NULL;}else {node->prev->next = node->next;node->next->prev = node->prev;if (list->headNode == node) { // 防止删除头list->headNode = node->next;}free(node);node = NULL;}
}void travel(List* list)
{Node* cur = list->headNode;while (cur->next != list->headNode) {printf("%d ", cur->data);cur = cur->next;}printf("%d ", cur->data);printf("\n");
}// 只做演示,不考虑内存问题
void game_run(int n, int m)
{if (n < 0 || m < 0) {return;}List list = { NULL };for (int i = 1; i <= n; i++) {push_back(&list, i);}travel(&list);Node* cur = list.headNode;while (n > 1) {// 报数for (int i = 1; i < m; i++) {cur = cur->next;}Node* next = cur->next;erase(&list, cur);// 重置报数cur = next;n--;}printf("天选之子: %d\n", cur->data);
}int main()
{game_run(10, 3);return 0;
}
相关文章:
数据结构C语言描述3(图文结合)--双链表、循环链表、约瑟夫环问题
前言 这个专栏将会用纯C实现常用的数据结构和简单的算法;有C基础即可跟着学习,代码均可运行;准备考研的也可跟着写,个人感觉,如果时间充裕,手写一遍比看书、刷题管用很多,这也是本人采用纯C语言…...
wend看源码-APISJON
项目地址 腾讯APIJSON官方网站 定义 APIJSON 可以定义为一个面向HTTP 协议的JSON 规范,一个面向数据访问层的ORM 框架。其主要工作流程包括:前端按照既定格式组装 JSON 请求报文,通过 APIJSON-ORM 将这些报文直接转换为 SQL 语句,…...
CSS(8):盒子阴影与文字阴影
一:盒子阴影text-shadow属性 1.box-shadow:h-shadow v-shadow blur spread color inset; 默认的是外部阴影outset,不能写在代码上 2.鼠标经过盒子后的阴影 rgba透明度 3.文字阴影 text-shadow:水平偏移 垂直偏移 模糊度 阴影颜色; 注意点…...
Hadoop 系列 MapReduce:Map、Shuffle、Reduce
文章目录 前言MapReduce 基本流程概述MapReduce 三个核心阶段详解Map 阶段工作原理 Shuffle 阶段具体步骤分区(Partition)排序(Sort)分组(Combine 和 Grouping) Reduce 阶段工作原理 MapReduce 应用场景Map…...
web——sqliabs靶场——第十三关——报错注入+布尔盲注
发现是单引号加括号闭合的 尝试联合注入 发现不太行,那尝试报错注入。 测试报错注入 unameadmin) and updatexml(1,0x7e,3) -- &passwdadmin&submitSubmit 爆数据库 unameadmin) and updatexml(1,concat(0x7e,database(),0x7e),3) -- &passwdadmin&a…...
调大Vscode资源管理器字体
对于调整资源管理器字体大小(也就是下图红框),查找了网上很多方法。要么介绍的方法是调整了代码字体,要么是调节了终端字体,要么是通过整体放缩实现的调整,总之都不合适。 唯一的调整方法是在几篇CSDN里看到…...
【新人系列】Python 入门(十一):控制结构
✍ 个人博客:https://blog.csdn.net/Newin2020?typeblog 📝 专栏地址:https://blog.csdn.net/newin2020/category_12801353.html 📣 专栏定位:为 0 基础刚入门 Python 的小伙伴提供详细的讲解,也欢迎大佬们…...
后端开发详细学习框架与路线
🚀 作者 :“码上有前” 🚀 文章简介 :后端开发 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 为帮助你合理安排时间,以下是结合上述学习内容的阶段划分与时间分配建议。时间安排灵活&a…...
类文件结构详解.上
字节码 在 Java 中,JVM 可以理解的代码就叫做字节码(即扩展名为 .class 的文件),它不面向任何特定的处理器,只面向虚拟机。Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题&…...
【K8S问题系列 |18 】如何解决 imagePullSecrets配置正确,但docker pull仍然失败问题
如果 imagePullSecrets 配置正确,但在执行 docker pull 命令时仍然失败,可能存在以下几种原因。以下是详细的排查步骤和解决方案。 1. 检查 Docker 登录凭证 确保你使用的是与 imagePullSecrets 中相同的凭证进行 Docker 登录: 1.1 直接登录…...
Vue+Springboot用Websocket实现协同编辑
1. 项目介绍 在本文中,我们将介绍如何使用Vue.js和Spring Boot实现一个支持多人实时协同编辑的Web应用。通过WebSocket技术,我们可以实现文档的实时同步,让多个用户同时编辑同一份文档。 2. 技术栈 前端:Vue.js 3 Vuex后端&am…...
高阶C语言补充:柔性数组
C99中,结构体中最后一个元素允许时未知大小的数组,这就叫做柔性数组成员。 vs编译器也支持柔性数组。 之所以把柔性数组单独列出,是因为: 1、柔性数组是建立在结构体的基础上的。 2、柔性数组的使用用到了动态内存分配。 这使得柔…...
MYSQL——多表查询、事务和索引
概括 出现查询结果个数为笛卡尔积的原因是sql语句: select * from tb_emp,tb_dept; 没有加上where tb_emp.dept_id tb_dept.id;(where条件可以消除笛卡尔积) select * from tb_emp,tb_dept where tb_emp.dept_id tb_dept.id; 查询类型 …...
在 Swift 中实现字符串分割问题:以字典中的单词构造句子
文章目录 前言摘要描述题解答案题解代码题解代码分析示例测试及结果时间复杂度空间复杂度总结 前言 本题由于没有合适答案为以往遗留问题,最近有时间将以往遗留问题一一完善。 LeetCode - #140 单词拆分 II 不积跬步,无以至千里;不积小流&…...
Unity类银河战士恶魔城学习总结(P132 Merge skill tree with skill Manager 把技能树和冲刺技能相组合)
【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/ 本章节实现了解锁技能后才可以使用技能,先完成了冲刺技能的锁定解锁 Dash_Skill.cs using System.Collections; using System…...
JavaScript 中 arguments、类数组与数组的深入解析
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 💯前言💯什么是 arguments 对象2.1 arguments 的定义2.2 arguments 的特性2.3 使用场景 💯深入了解 arguments 的结构3.1 arguments 的内部结构arguments 的关键属性…...
【java-Neo4j 5开发入门篇】-最新Java开发Neo4j
系列文章目录 前言 上一篇文章讲解了Neo4j的基本使用,本篇文章对Java操作Neo4j进行入门级别的阐述,方便读者快速上手对Neo4j的开发。 一、开发环境与代码 1.docker 部署Neo4j #这里使用docker部署Neo4j,需要镜像加速的需要自行配置 docker run --name…...
摄影:相机控色
摄影:相机控色 白平衡(White Balance)白平衡的作用: 白平衡的使用环境色温下相机色温下总结 白平衡偏移与包围白平衡包围 影调 白平衡(White Balance) 人眼看到的白色:会自动适应环境光线。 相…...
UI自动化测试中公认最佳的设计模式-POM
一、概念 什么是POM? POM是PageObjectModule(页面对象模式)的缩写,其目的是为了Web UI测试创建对象库。在这种模式下,应用涉及的每一个页面应该定义为一个单独的类。类中应该包含此页面上的页面元素对象和处理这些元…...
数字图像处理(2):Verilog基础语法
(1)Verilog常见数据类型: reg型、wire型、integer型、parameter型 (2)Verilog 常见进制:二进制(b或B)、十进制(d或D)、八进制(o或O)、…...
大公司如何实现打印机共享的?如何对打印机进行管控或者工号登录后进行打印?异地打印机共享的如何实现可以帮助用户在不同地理位置使用同一台打印机完成打印任务?
大公司如何实现打印机共享的?如何对打印机进行管控或者工号登录后进行打印?异地打印机共享的如何实现可以帮助用户在不同地理位置使用同一台打印机完成打印任务? 如果在局域网内,可以不需要进行二次开发,通过对打印机进…...
解决前端页面报错:Not allowed to load local resource
在前后端分离项目中,在前端页面里使用file://的绝对路径访问本地图片,在加载图片的 时候会报出Not allowed to load local resource 的错误。 这是因为浏览器出于安全因素,禁止通过绝对路径访问图片,需要通过虚拟路径进行访问。 …...
Qt 实现网络数据报文大小端数据的收发
1.大小端数据简介 大小端(Endianness)是计算机体系结构的一个术语,它描述了多字节数据在内存中的存储顺序。以下是大小端的定义和它们的特点: 大端(Big-Endian) 在大端模式中,一个字的最高有效…...
2024年11月21日Github流行趋势
项目名称:twenty 项目维护者:charlesBochet, lucasbordeau, Weiko, FelixMalfait, bosiraphael项目介绍:正在构建一个由社区支持的现代化Salesforce替代品。项目star数:21,798项目fork数:2,347 项目名称:p…...
Java的方法、基本和引用数据类型
个人的黑马程序员java笔记 目录 方法 例:方法定义和调用 方法的重载 对于byte, short, int, long类型 方法的内存 基本数据类型 引用数据类型 方法的值的传递的内存原理 方法 方法(method)是程序中最小的执行单元格式 方法定义&a…...
Spark分布式计算中Shuffle Read 和 Shuffle Write的职责和区别
在 Spark 的分布式计算中,Shuffle Read 和 Shuffle Write 是两个与数据重新分区和分发相关的重要阶段。它们的主要职责和区别如下: 1. Shuffle Write Shuffle Write 发生在上游的任务执行阶段,其作用是: 分区数据准备࿱…...
【成品文章+四小问代码更新】2024亚太杯国际赛B题基于有限差分格式的空调形状优化模型
这里仅展示部分内容,完整内容获取在文末! 基于有限差分格式的空调形状优化模型 摘 要 随着科技进步,多功能环境调节设备成为市场趋势,集成了空调、加湿器和空气 净化器功能的三合一设备能提供更舒适健康的室内环境。我们需要分析…...
实验三:构建园区网(静态路由)
目录 一、实验简介 二、实验目的 三、实验需求 四、实验拓扑 五、实验任务及要求 1、任务 1:完成网络部署 2、任务 2:设计全网 IP 地址 3、任务 3:实现全网各主机之间的互访 六、实验步骤 1、在 eNSP 中部署网络 2、配置各主机 IP …...
MySQL 三大日志详解
在 MySQL 数据库中,binlog(二进制日志)、redo log(重做日志)和 undo log(回滚日志)起着至关重要的作用。它们共同保障了数据库的高可用性、数据一致性和事务的可靠性。下面将对这三大日志进行详…...
vscode使用ssh配置docker容器环境
1 创建容器,并映射主机和容器的指定ssh服务端口 2 进入容器 docker exec -it <容器ID> /bin/bash 3在容器中安装ssh服务 apt-get update apt-get install openssh-server 接着修改ssh文件信息,将容器的10008端口暴露出来允许root用户使用ssh登录 vim /…...
Python设计模式详解之10 —— 外观模式
引言 Facade设计模式(外观模式)是一种软件设计模式,它提供了一个统一的接口来访问子系统中的一组接口。Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。当一个系统的内部实现非常复杂,或者需要与…...
[服务器] 腾讯云服务器免费体验,成功部署网站
文章目录 概要整体架构流程概要 腾讯云服务器免费体验一个月。 整体架构流程 腾讯云服务器体验一个月, 选择预装 CentOS 7.5 首要最重要的是: 添加阿里云镜像。 不然国外源速度慢, 且容易失败。 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/li…...
低速接口项目之串口Uart开发(四)——UART串口实现FPGA内部AXILITE寄存器的读写控制
本节目录 一、设计背景 二、设计思路 三、逻辑设计框架 四、仿真验证 五、上板验证 六、往期文章链接本节内容 一、设计背景 通常,芯片手册或者IP都会提供一系列的用户寄存器以及相关的定义,用于软件开发人员进行控制底层硬件来调试,或封装…...
【Datawhale组队学习】模型减肥秘籍:模型压缩技术4——神经网络架构搜索
神经网络架构搜索是通过自动化方法来设计神经网络架构的一种技术,与传统手工设计网络结构相比,NAS能够在大量可能的架构中进行搜索,找到最优的神经网络架构,从而减少人工调参和设计的时间。学习这章时,重点在于理解NAS…...
用el-scrollbar实现滚动条,拖动滚动条可以滚动,但是通过鼠标滑轮却无效
问题: 用elementplus实现的滚动条的页面中,滑动滚动条可以滚动,但是通过鼠标滑轮却无效,鼠标没有问题。 解决: 在开发者工具中, 元素->时间监听器中发现当我移除网页中祖先元素的滚动事件,该…...
windows下,用CMake编译qt项目,出现错误By not providing “FindQt5.cmake“...
开发环境:windows10 qt5.14, 编译器msvc2017x64,CMake3.30; 现象: CMakeList文件里,如有find_package(Qt5 COMPONENTS Widgets REQUIRED) target_link_libraries(dis_lib PRIVATE Qt5::Widgets) 用CMak…...
windows实现VNC连接ubuntu22.04服务器
最近弄了一个700块钱的mini主机,刷了ubuntu22.04系统,然后想要在笔记本上通过VNC连接,这样就有了一个linux的开发环境。最后实现的过程为: 安装vnc服务器 安装 VNC 服务器软件: sudo apt update sudo apt install t…...
SQL注入--联合注入--理论
什么是SQL注入? SQL注入(SQL Injection)是一种常见的Web安全漏洞。 形成的主要原因是web应用程序在接收相关数据参数时未做好过滤,将其直接带入到数据库中查询,导致攻击者可以拼接执行构造的SQL语句,从而获…...
LaTeX 利用注销 ccmap 宏包实现降重功能
在中文LaTeX中,ccmap 宏包的主要作用是支持复制和粘贴时正确处理中文字符的编码。它的功能对于生成的PDF文档尤其有用,使得PDF中的中文字符在被复制到其他地方时能够以正确的编码显示,而不是乱码或其他不正确的字符。 以下是ccmap的详细功能…...
NVR接入录像回放平台EasyCVR视频融合平台加油站监控应用场景与实际功能
在现代社会中,加油站作为重要的能源供应点,面临着安全监管与风险管理的双重挑战。为应对这些问题,安防监控平台EasyCVR推出了一套全面的加油站监控方案。该方案结合了智能分析网关V4的先进识别技术和EasyCVR视频监控平台的强大监控功能&#…...
经验笔记:远端仓库和本地仓库之间的连接(以Gitee为例)
经验笔记:远端仓库和本地仓库之间的连接 方法一:先创建远端仓库,再克隆到本地 创建远端仓库 登录到你的Git托管平台(如Gitee、GitHub、GitLab、Bitbucket等)。点击“New Repository”或类似按钮,创建一个新…...
趋势洞察|AI 能否带动裸金属 K8s 强势崛起?
随着容器技术的不断成熟,不少企业在开展私有化容器平台建设时,首要考虑的问题就是容器的部署环境——是采用虚拟机还是物理机运行容器?在往期“虚拟化 vs. 裸金属*”系列文章中,我们分别对比了容器部署在虚拟化平台和物理机上的架…...
数据科学与SQL:组距分组分析 | 区间分布问题
目录 0 问题描述 1 数据准备 2 问题分析 3 小结 0 问题描述 绝对值分布分析也可以理解为组距分组分析。对于某个指标而言,一个记录对应的指标值的绝对值,肯定落在所有指标值的绝对值的最小值和最大值构成的区间内,根据一定的算法&#x…...
Cesium的ClearCommand的流程
ClearCommand是在每帧渲染前可以将显存的一些状态置为初始值,就如同把擦黑板。当然也包括在绘制过程中擦掉部分的数据,就如同画家在开始绘制的时候会画导览线(如透视线),轮廓出来后这些导览线就会被擦除。 我画了一个…...
DBeaver错误:Public Key Retrieval is not allowed
问题原因 MySQL 8.0 默认使用 caching_sha2_password 认证插件,并要求客户端能够使用 RSA 公钥进行加密操作。如果客户端无法正确处理 RSA 公钥检索,就会触发这个错误。 解决方案 右键编辑连接-连接设置-属性驱动-修改allowPublicKeyRetrieval属性的值…...
slice介绍slice查看器
Android Jetpack架构组件(十)之Slices - 阅读清单 - 腾讯云开发者社区-腾讯云 slice 查看器apk 用adb intall 安装 Releases android/user-interface-samples GitHubMultiple samples showing the best practices in the user interface on Android. - Releases android/u…...
Vue移动端网页(H5)预览pdf文件(pdfh5和vue-pdf)(很详细)
我试了似乎不支持vue3 原文链接:Vue移动端网页(H5)预览pdf文件(pdfh5和vue-pdf)-阿里云开发者社区...
缓存工具类编写
缓存工具类编写 一般操作 在外面日常开发中,经常会有为了减少数据库压力,而将数据保存到缓存中并设置一个过期时间的操作。日常代码如下: Autowired private RedisTemplate<String, String> redisTemplate;public Object queryDataW…...
基于Java Springboot高校会议室预订管理系统
一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue、Element-ui 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA/eclipse 数据…...
redis-击穿、穿透、雪崩
击穿、穿透、雪崩经常听人说吧? 那他到底是啥呢?无非就是在有缓存层的情况下,对各种绕过缓存层从而直接落到了DB上的情况进行的分类。 概念性的东西大概如下,我是记不住,后期具体使用与规避这些问题才是大事ÿ…...