深入理解C++ 中的list容器
目录
一、引言
二、list的基本介绍
2.1 底层结构
2.2 特性
三、list的使用
3.1 构造函数
3.2 迭代器的使用
3.3 容量相关操作
3.4 元素访问相关操作
3.5 修改器操作
3.6 迭代器失效问题
四、list的模拟实现
4.1 节点定义
4.2 迭代器实现
4.3 list类实现
五、list与vector的对比
表格
六、总结
一、引言
在C++ 的标准模板库(STL)中, list 是一种非常重要的序列式容器。它以其独特的底层结构和高效的操作接口,在许多场景下发挥着重要作用。今天,我们就来深入探讨一下 list 容器的方方面面。
二、list的基本介绍
2.1 底层结构
list 的底层是双向链表结构。每个元素存储在独立的节点中,节点通过指针指向前一个元素和后一个元素 ,并且是带头结点的双向循环链表。这意味着在链表中,头结点可以作为一个哨兵节点,方便进行插入和删除操作,同时循环的特性使得从链表的尾部可以无缝连接到头部。
2.2 特性
- 插入和删除高效:由于其链表结构,在任意位置进行插入和删除操作的时间复杂度为 O(1) ,不需要像 vector 那样移动大量元素。
- 双向迭代:支持前后双向迭代,提供了正向迭代器和反向迭代器,方便从不同方向遍历容器。
- 不支持随机访问:与 vector 不同, list 不支持任意位置的随机访问。如果要访问第 n 个元素,必须从已知位置(如头部或尾部)开始迭代,时间复杂度为 O(n) 。
三、list的使用
3.1 构造函数
list 提供了多种构造方式:
cpp#include <list>#include <iostream>int main() {// 构造包含n个值为val的元素的liststd::list<int> list1(5, 10); // 包含5个值为10的元素// 构造空的liststd::list<int> list2; // 拷贝构造std::list<int> list3(list1); // 用[first, last)区间中的元素构造liststd::list<int> list4(list1.begin(), list1.end()); for (const auto& num : list1) {std::cout << num << " ";}std::cout << std::endl;return 0;}
3.2 迭代器的使用
迭代器是访问 list 元素的关键工具。 list 提供正向迭代器 begin() 和 end() ,以及反向迭代器 rbegin() 和 rend() 。
cpp#include <list>#include <iostream>int main() {std::list<int> myList = {1, 2, 3, 4, 5};// 正向遍历for (auto it = myList.begin(); it != myList.end(); ++it) {std::cout << *it << " ";}std::cout << std::endl;// 反向遍历for (auto rit = myList.rbegin(); rit != myList.rend(); ++rit) {std::cout << *rit << " ";}std::cout << std::endl;return 0;}
需要注意的是, begin() 和 end() 是正向迭代器,对其执行 ++ 操作,迭代器向后移动; rbegin() 和 rend() 是反向迭代器,对其执行 ++ 操作,迭代器向前移动。
3.3 容量相关操作
- empty() :检测 list 是否为空,返回 true 或 false 。
- size() :返回 list 中有效节点的个数。
cpp#include <list>#include <iostream>int main() {std::list<int> myList;std::cout << "Is myList empty? " << (myList.empty()? "Yes" : "No") << std::endl;myList.push_back(1);std::cout << "Size of myList: " << myList.size() << std::endl;return 0;}
3.4 元素访问相关操作
- front() :返回 list 的第一个节点中值的引用。
- back() :返回 list 的最后一个节点中值的引用。
cpp#include <list>#include <iostream>int main() {std::list<int> myList = {10, 20, 30};std::cout << "First element: " << myList.front() << std::endl;std::cout << "Last element: " << myList.back() << std::endl;return 0;}
3.5 修改器操作
- push_front(val) :在 list 首元素前插入值为 val 的元素。
- pop_front() :删除 list 中第一个元素。
- push_back(val) :在 list 尾部插入值为 val 的元素。
- pop_back() :删除 list 中最后一个元素。
- insert(position, val) :在 list 的 position 位置中插入值为 val 的元素。
- erase(position) :删除 list 中 position 位置的元素。
- swap(other_list) :交换两个 list 中的元素。
- clear() :清空 list 中的有效元素。
cpp#include <list>#include <iostream>int main() {std::list<int> myList;myList.push_back(1);myList.push_back(2);myList.push_front(0);myList.pop_back();myList.pop_front();auto it = myList.begin();myList.insert(it, 10);myList.erase(it);std::list<int> anotherList = {3, 4};myList.swap(anotherList);myList.clear();return 0;}
3.6 迭代器失效问题
由于 list 的底层是双向链表,在插入元素时,不会导致迭代器失效。但在删除元素时,指向被删除节点的迭代器会失效,其他迭代器不受影响。例如:
cpp#include <list>#include <iostream>void TestListIterator() {int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};std::list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto it = l.begin();while (it != l.end()) {l.erase(it++); // 正确做法,erase后it已经指向下一个有效元素}}
如果写成 l.erase(it); ++it; ,在 erase 操作后 it 已经失效,再对其进行 ++ 操作就会出错。
四、list的模拟实现
4.1 节点定义
cpptemplate <typename T>struct ListNode {T data;ListNode* prev;ListNode* next;ListNode(const T& val) : data(val), prev(nullptr), next(nullptr){}};
4.2 迭代器实现
cpptemplate <typename T, typename Ref, typename Ptr>struct ListIterator {using iterator_category = std::bidirectional_iterator_tag;using value_type = T;using reference = Ref;using pointer = Ptr;using node = ListNode<T>;node* ptr;ListIterator(node* p) : ptr(p) {}reference operator*() { return ptr->data; }pointer operator->() { return &(ptr->data); }ListIterator& operator++() {ptr = ptr->next;return *this;}ListIterator operator++(int) {ListIterator temp = *this;ptr = ptr->next;return temp;}ListIterator& operator--() {ptr = ptr->prev;return *this;}ListIterator operator--(int) {ListIterator temp = *this;ptr = ptr->prev;return temp;}bool operator!=(const ListIterator& other) const { return ptr != other.ptr; }bool operator==(const ListIterator& other) const { return ptr == other.ptr; }};
4.3 list类实现
cpptemplate <typename T>class List {private:ListNode<T>* head;public:using iterator = ListIterator<T, T&, T*>;using const_iterator = ListIterator<T, const T&, const T*>;List() {head = new ListNode<T>(T());head->prev = head;head->next = head;}~List() {clear();delete head;}iterator begin() { return iterator(head->next); }iterator end() { return iterator(head); }const_iterator begin() const { return const_iterator(head->next); }const_iterator end() const { return const_iterator(head); }void push_back(const T& val) {insert(end(), val);}void push_front(const T& val) {insert(begin(), val);}iterator insert(iterator pos, const T& val) {ListNode<T>* newNode = new ListNode<T>(val);ListNode<T>* cur = pos.ptr;newNode->prev = cur->prev;newNode->next = cur;cur->prev->next = newNode;cur->prev = newNode;return iterator(newNode);}iterator erase(iterator pos) {ListNode<T>* cur = pos.ptr;ListNode<T>* nextNode = cur->next;cur->prev->next = cur->next;cur->next->prev = cur->prev;delete cur;return iterator(nextNode);}void clear() {iterator it = begin();while (it != end()) {it = erase(it);}}};
五、list与vector的对比
表格
特性 | vector | list |
底层结构 | 动态顺序表,一段连续空间 | 带头结点的双向循环链表 |
随机访问 | 支持随机访问,访问某个元素效率 O(1) | 不支持随机访问,访问某个元素效率 O(n) |
插入和删除 | 任意位置插入和删除效率低,需要搬移元素,时间复杂度为 O(n) ,插入时可能需要增容 | 任意位置插入和删除效率高,不需要搬移元素,时间复杂度为 O(1) |
空间利用率 | 底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高 | 底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低 |
迭代器 | 原生态指针 | 对原生态指针(节点指针)进行封装 |
迭代器失效 | 插入元素时,可能导致重新扩容,使原来迭代器失效;删除时,当前迭代器需要重新赋值否则会失效 | 插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响 |
使用场景 | 需要高效存储,支持随机访问,不关心插入删除效率 | 大量插入和删除操作,不关心随机访问 |
完整代码
#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include <iostream>
using namespace std;
#include <assert.h>
namespace ldg
{// List的节点类 template<class T>struct ListNode{ListNode(const T& val = T()): _prev(nullptr), _next(nullptr), _val(val){}ListNode<T>* _prev;ListNode<T>* _next;T _val;};/*List 的迭代器迭代器有两种实现方式,具体应根据容器底层数据结构实现:1. 原生态指针,比如:vector2. 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:1. 指针可以解引用,迭代器的类中必须重载operator*()2. 指针可以通过->访问其所指空间成员,迭代器类中必须重载oprator->()3. 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)至于operator--()/operator--(int)释放需要重载,根据具体的结构来抉择,双向链表可以向前 移动,所以需要重载,如果是forward_list就不需要重载--4. 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()*/template<class T, class Ref, class Ptr>class ListIterator{typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;// Ref 和 Ptr 类型需要重定义下,实现反向迭代器时需要用到 public:typedef Ref Ref;typedef Ptr Ptr;public:// // 构造 ListIterator(Node* node = nullptr): _node(node){}// // 具有指针类似行为 Ref operator*(){return _node->_val;}Ptr operator->(){return &(operator*());}// // 迭代器支持移动 Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self temp(*this);_node = _node->_next;return temp;}Self& operator--(){_node = _node->_prev;return *this;}Self operator--(int){Self temp(*this);_node = _node->_prev;return temp;}// // 迭代器支持比较 bool operator!=(const Self& l)const{return _node != l._node;}bool operator==(const Self& l)const{return _node != l._node;}Node* _node;};template<class Iterator>class ReverseListIterator{// 注意:此处typename的作用是明确告诉编译器,Ref是Iterator类中的一个类型,而不是静态成员变量 // 否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员变量 // 因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的 public:typedef typename Iterator::Ref Ref;typedef typename Iterator::Ptr Ptr;typedef ReverseListIterator<Iterator> Self;public:// // 构造 ReverseListIterator(Iterator it): _it(it){}// // 具有指针类似行为 Ref operator*(){Iterator temp(_it);--temp;return *temp;}Ptr operator->(){return &(operator*());}// // 迭代器支持移动 Self& operator++(){--_it;return *this;}Self operator++(int){Self temp(*this);--_it;return temp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self temp(*this);++_it;return temp;}// // 迭代器支持比较 bool operator!=(const Self& l)const{return _it != l._it;}bool operator==(const Self& l)const{return _it != l._it;}Iterator _it;};template<class T>class list{typedef ListNode<T> Node;public:// 正向迭代器 typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;// 反向迭代器 typedef ReverseListIterator<iterator> reverse_iterator;typedef ReverseListIterator<const_iterator> const_reverse_iterator;public:/// // List的构造 list(){CreateHead();}list(int n, const T& value = T()){CreateHead();for (int i = 0; i < n; ++i)push_back(value);}template <class Iterator>list(Iterator first, Iterator last){CreateHead();while (first != last){push_back(*first);++first;}}list(const list<T>& l){CreateHead();// 用l中的元素构造临时的temp,然后与当前对象交换 list<T> temp(l.begin(), l.end());this->swap(temp);}list<T>& operator=(list<T> l){this->swap(l);return *this;}~list(){clear();delete _head;_head = nullptr;}/// // List的迭代器 iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin()const{return const_iterator(_head->_next);}const_iterator end()const{return const_iterator(_head);}reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}const_reverse_iterator rbegin()const{return const_reverse_iterator(end());}const_reverse_iterator rend()const{return const_reverse_iterator(begin());}/// // List的容量相关 size_t size()const{Node* cur = _head->_next;size_t count = 0;while (cur != _head){count++;cur = cur->_next;}return count;}bool empty()const{return _head->_next == _head;}void resize(size_t newsize, const T& data = T()){size_t oldsize = size();if (newsize <= oldsize){// 有效元素个数减少到newsize while (newsize < oldsize){pop_back();oldsize--;}}else{while (oldsize < newsize){push_back(data);oldsize++;}}}// List的元素访问操作 // 注意:List不支持operator[] T& front(){return _head->_next->_val;}const T& front()const{return _head->_next->_val;}T& back(){return _head->_prev->_val;}const T& back()const{return _head->_prev->_val;}// List的插入和删除 void push_back(const T& val){insert(end(), val);}void pop_back(){erase(--end());}void push_front(const T& val){insert(begin(), val);}void pop_front(){erase(begin());}// 在pos位置前插入值为val的节点 iterator insert(iterator pos, const T& val){Node* pNewNode = new Node(val);Node* pCur = pos._node;// 先将新节点插入 pNewNode->_prev = pCur->_prev;pNewNode->_next = pCur;pNewNode->_prev->_next = pNewNode;pCur->_prev = pNewNode;return iterator(pNewNode);}// 删除pos位置的节点,返回该节点的下一个位置 iterator erase(iterator pos){// 找到待删除的节点 Node* pDel = pos._node;Node* pRet = pDel->_next;// 将该节点从链表中拆下来并删除 pDel->_prev->_next = pDel->_next;pDel->_next->_prev = pDel->_prev;delete pDel;return iterator(pRet);}void clear(){Node* cur = _head->_next;// 采用头删除删除 while (cur != _head){_head->_next = cur->_next;delete cur;cur = _head->_next;}_head->_next = _head->_prev = _head;}void swap(ldg::list<T>& l){std::swap(_head, l._head);}private:void CreateHead(){_head = new Node;_head->_prev = _head;_head->_next = _head;}private:Node* _head;};
}
///
// 对模拟实现的list进行测试
// 正向打印链表
template<class T>
void PrintList(const ldg::list<T>& l)
{auto it = l.begin();while (it != l.end()){cout << *it << " ";++it;}cout << endl;
}
// 测试List的构造
void TestBiteList1()
{ldg::list<int> l1;ldg::list<int> l2(10, 5);PrintList(l2);int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };ldg::list<int> l3(array, array + sizeof(array) / sizeof(array[0]));PrintList(l3);ldg::list<int> l4(l3);PrintList(l4);l1 = l4;PrintList(l1);
}
// PushBack()/PopBack()/PushFront()/PopFront()
void TestBiteList2()
{// 测试PushBack与PopBack ldg::list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);PrintList(l);l.pop_back();l.pop_back();PrintList(l);l.pop_back();cout << l.size() << endl;// 测试PushFront与PopFront l.push_front(1);l.push_front(2);l.push_front(3);PrintList(l);l.pop_front();l.pop_front();PrintList(l);l.pop_front();cout << l.size() << endl;
}// 测试insert和erase
void TestBiteList3()
{int array[] = { 1, 2, 3, 4, 5 };ldg::list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto pos = l.begin();l.insert(l.begin(), 0);PrintList(l);++pos;l.insert(pos, 2);PrintList(l);l.erase(l.begin());l.erase(pos);PrintList(l);// pos指向的节点已经被删除,pos迭代器失效 cout << *pos << endl;auto it = l.begin();while (it != l.end()){it = l.erase(it);}cout << l.size() << endl;
}// 测试反向迭代器 void TestBiteList4()
{int array[] = { 1, 2, 3, 4, 5 };ldg::list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto rit = l.rbegin();while (rit != l.rend()){cout << *rit << " ";++rit;}cout << endl;const ldg::list<int> cl(l);auto crit = l.rbegin();while (crit != l.rend()){cout << *crit << " ";++crit;}cout << endl;
}
六、总结
list 容器凭借其独特的双向链表结构,在插入和删除操作上具有高效性,适用于需要频繁进行这些操作的场景。通过深入理解其接口和实现原理,我们可以在实际编程中更好地运用它,同时与 vector 等其他容器对比,能更清晰地知道在不同需求下如何选择合适的容器。希望这篇博客能帮助大家对 list 容器有更全面、深入的认识。
相关文章:
深入理解C++ 中的list容器
目录 一、引言 二、list的基本介绍 2.1 底层结构 2.2 特性 三、list的使用 3.1 构造函数 3.2 迭代器的使用 3.3 容量相关操作 3.4 元素访问相关操作 3.5 修改器操作 3.6 迭代器失效问题 四、list的模拟实现 4.1 节点定义 4.2 迭代器实现 4.3 list类实现 五、lis…...
附赠二张图,阐述我对大模型的生态发展、技术架构认识。
文章精炼,用两张图说明大模型发展业态方向,以及大模型主体技术架构。(目前还需要进一步验证我的Thought && ideas,等待机会吧.........) 图一:探究大模型三个层次应用方向,浅层次入门简…...
Java实现加密(七)国密SM2算法的签名和验签(附商用密码检测相关国家标准/国密标准下载)
目录 一、国密标准中,关于SM2签名验签的定义二、SM2签名和验签的实现原理1. 前置知识2. 签名生成过程3. 验签过程4. 数学正确性证明5. 安全性与注意事项 三、带userId、不带userId的区别1. 核心区别2.算法区别(1) 哈希计算过程(2) 签名验签流程 四、Java代码实现1. …...
贪心算法~~
目录 一、理论基础 二、题目练习 (1)455. 分发饼干 (2)53. 最大子数组和 - 力扣 (3)122. 买卖股票的最佳时机 II - 力扣(LeetCode) (4)860. 柠檬水找零…...
XYNU2024信安杯-REVERSE(复现)
前言 记录记录 1.Can_you_find_me? 签到题,秒了 2.ea_re 快速定位 int __cdecl main_0(int argc, const char **argv, const char **envp) {int v4; // [esp0h] [ebp-1A0h]const char **v5; // [esp4h] [ebp-19Ch]const char **v6; // [esp8h] [ebp-198h]char v7;…...
NLP系列【自然语言处理的深度学习模型综述】
自然语言处理的深度学习模型 摘要传统自然语言处理模型(略 不作重点)神经网络自然语言处理模型经典神经网络CNN网络模型Word2Vec模型RNN模型GPT网络模型BERT网络模型 BERT变体模型提升模型性能模型压缩 摘要 在自然语言处理任务方面,依据语料…...
【差分隐私】basic primitive的含义
在差分隐私领域,“basic primitive”一词具有特定的技术含义,需从单词本义及学科背景两个层面解析: 一、单词本义解析 “Primitive”在计算机科学中通常指代基础构建单元或核心组件,例如编程语言中的基本数据类型(如整…...
数字浪潮下的算力担当:GPU 服务器的多元应用、核心价值
在当今数据洪流和信息爆炸的时代,算力已成为衡量国家、行业乃至企业发展水平的关键指标。而算力服务器,特别是 GPU 服务器,作为算力的核心载体,正以其卓越性能深刻改变着世界的运行逻辑与模式。从数据处理到云计算,从人…...
【Echarts】使用echarts绘制多个不同类型的中国地图
一、需求 在同一页面上绘制多个不同类型的中国地图,如果是在同一页面上绘制多个同一种类型的地图可以直接引用一个china.js文件,设置两个独立的div分别用于放置两个地图,并实例化配置相关参数即可,但是如果在同一个页面上绘制多个…...
WEB漏洞-XSS跨站原理分类
本文主要内容 原理 XSS漏洞产生原理? XSS漏洞危害影响? 分类 反射型、存储型、DOM型 手法 XSS平台使用 XSS工具使用 XSS结合其他漏洞 靶场搭建 pikachu 靶场搭建(完整版)-CSDN博客https://blog.csdn.net…...
PR第二课--混剪
1.音乐打点 1.1 手动打点 按钮(如图),或者,快捷键M(如果在已有打点处,再次按M键会进入对标记点的设置界面,如下下图) 1.2 插件打点 一段音乐中,有明显的鼓点时,可以使用打点插件,快捷打点;如果鼓点不明显的话,最好还是手动打点,用插件打点会打出大量的标记点,…...
Kafka和flume整合
需求1:利用flume监控某目录中新生成的文件,将监控到的变更数据发送给kafka,kafka将收到的数据打印到控制台: 在flume/conf下添加.conf文件, vi flume-kafka.conf # 定义 Agent 组件 a1.sourcesr1 a1.sinksk1 a1.c…...
Linux 内核网络协议栈中 inet_stream_ops 与 tcp_prot 的深度解析
在 Linux 内核网络协议栈中,TCP 协议的实现依赖于多个关键结构体的协作。其中,inet_stream_ops 和 tcp_prot 是两个核心结构体,它们分别属于不同的层次,共同完成从用户态系统调用到底层协议处理的完整链路。本文将从功能定位、协作关系、代码示例及设计哲学等方面,深入分析…...
flume整合kafka
需求一: 启动flume 启动kafka消费者,验证数据写入成功 新增测试数据 需求二: 启动Kafka生产者 启动Flume 在生产者中写入数据...
EasyRTC音视频实时通话嵌入式SDK,打造社交娱乐低延迟实时互动的新体验
一、方案背景 在数字化时代,社交娱乐已经成为人们生活中不可或缺的一部分。随着移动互联网和智能设备的普及,用户对实时互动的需求越来越高。EasyRTC作为一款基于WebRTC技术的实时音视频通信解决方案,凭借其低延迟、高稳定性和跨平台兼容性&…...
制作一款打飞机游戏21:自定义工具
关于如何在Pico 8中创建我们自己的编辑器。 外部编辑器的需求 首先,我想谈谈为什么我们需要外部编辑器。外部编辑器通常用于编辑游戏中的数据。例如,一个游戏卡或程序通常包含一些代码,但也会包含数据,比如静态信息,…...
面向高性能运动控制的MCU:架构创新、算法优化与应用分析
摘要:现代工业自动化、汽车电子以及商业航天等领域对运动控制MCU的性能要求不断提升。本文以国科安芯的MCU芯片AS32A601为例,从架构创新、算法优化到实际应用案例,全方位展示其在高性能运动控制领域的优势与潜力。该MCU以32位RISC-V指令集为基…...
LWIP中两种重要的数据结构pbuf和pcb详细介绍
LWIP(Lightweight IP)是为嵌入式系统设计的轻量级TCP/IP协议栈。pbuf(Packet Buffer)和PCB(Protocol Control Block)是LwIP中两个核心数据结构,分别负责数据包管理和协议状态维护。 1. pbuf&…...
embedding_model模型通没有自带有归一化层该怎么处理?
embedding_model 是什么: 嵌入式模型(Embedding)是一种广泛应用于自然语言处理(NLP)和计算机视觉(CV)等领域的机器学习模型,它可以将高维度的数据转化为低维度的嵌入空间࿰…...
【蓝桥杯选拔赛真题104】Scratch回文数 第十五届蓝桥杯scratch图形化编程 少儿编程创意编程选拔赛真题解析
目录 scratch回文数 一、题目要求 1、准备工作 2、功能实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、解题思路 四、程序编写 五、考点分析 六、推荐资料 1、scratch资料 2、python资料 3、C++资料 scratch回文数 第十五届青少年蓝桥杯scratch编…...
1.2-1.3考研408计算机组成原理第一章 计算机系统概述
计算机组成原理第一章 计算机系统概述 一、计算机的层次结构 1.1 计算机系统组成 计算机系统由硬件系统和软件系统两大部分构成: 硬件系统:包括运算器、控制器、存储器、输入设备和输出设备五大核心部件(冯诺依曼体系结构)。软…...
【QQmusic自定义控件实现音乐播放器核心交互逻辑】第三章
🌹 作者: 云小逸 🤟 个人主页: 云小逸的主页 🤟 motto: 要敢于一个人默默的面对自己,强大自己才是核心。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前,其次就是现在&…...
基于图扑 HT 实现的智慧展馆数字孪生应用
在当今数字化时代,智慧展览馆作为传统展览场所的创新升级形态,借助前沿科技与现代化管理理念,实现了全方位的数字化、智能化转型。图扑软件凭借其自主研发的 HT 技术在智慧展馆领域取得了卓越成果,为城市基础设施数字化应用带来了…...
从线性到非线性:简单聊聊神经网络的常见三大激活函数
大家好,我是沛哥儿,我们今天一起来学习下神经网络的三个常用的激活函数。 引言:什么是激活函数 激活函数是神经网络中非常重要的组成部分,它引入了非线性因素,使得神经网络能够学习和表示复杂的函数关系。 在神经网络…...
重生之--js原生甘特图实现
需求: 一个树形结构,根据子节点的时间范围显示显示进度 ,不同的时间范围对应不同的颜色 数据类型大概是这个样子的 甘特图 dom部分 首先要计算所有节点的 最大时间和最小时间 然后再计算每个甘特图的宽度 再计算他的偏移量 再计算颜色...
pnpm monoreop 打包时 node_modules 内部包 typescript 不能推导出类型报错
报错信息如下: ../../packages/antdv/components/pro-table/src/form-render.vue:405:1 - error TS2742: The inferred type of default cannot be named without a reference to .pnpm/scroll-into-view-if-needed2.2.31/node_modules/scroll-into-view-if-needed…...
告别默认配置!Xray自定义POC开发指南
文章涉及操作均为测试环境,未授权时切勿对真实业务系统进行测试! 下载与解压 官网地址: Xray GitHub Releases 根据系统选择对应版本: Windows:xray_windows_amd64.exe.zipLinux:xray_linux_amd64.zipmacOS:xray_darwin_amd64.zip解压后得到可执行文件(如 xray_linux_…...
websheet之 自定义函数
在线代码 {.is-success} 一、自定义函数约定 必须遵守本控件的自定函数约定才可以正常使用。 {.is-warning} 约定如下: 自定义类名称与函数名称一致。(强制)该类方法名称与函数名称一致,该方法是函数的入口。(强制&am…...
Jenkins Pipeline 构建 CI/CD 流程
文章目录 jenkins 安装jenkins 配置jenkins 快速上手在 jenkins 中创建一个新的 Pipeline 作业配置Pipeline运行 Pipeline 作业 Pipeline概述Declarative PipelineScripted Pipeline jenkins 安装 安装环境: Linux CentOS 10:Linux CentOS9安装配置Jav…...
电脑技巧:路由器内部元器件介绍
目录 1. 处理器(CPU) 2. 内存(RAM) 3. 固态存储(Flash Memory) 4. 网络接口卡(NIC) 5. 电源模块 6. 散热系统 7. 无线天线 结语 路由器是我们日常上网的重要设备,今天我们就来深入了解路由器内部的各个元器件,了解它们是如何协同工作,一起来看看吧。 1. 处理器(CPU…...
ArrayUtils:数组操作的“变形金刚“——让你的数组七十二变
各位数组操控师们好!今天给大家带来的是Apache Commons Lang3中的ArrayUtils工具类。这个工具就像数组界的"孙悟空",能让你的数组随心所欲地变大、变小、变长、变短,再也不用对着原生数组的"死板"叹气了! 一…...
电脑温度怎么看 查看CPU温度的方法
监测电脑温度对于保持硬件健康非常重要,特别是在进行高强度运算、游戏或超频等操作时。过高的温度可能导致硬件性能下降,甚至损坏。本篇文章将介绍查看电脑温度的4种方法。 一、使用Windows内置工具查看CPU温度 Windows系统本身并不直接提供查看CPU温度…...
【合新通信】---浸没式液冷光模块化学兼容性测试方法
一、测试目的与核心挑战 测试目标 验证冷媒(氟化液、矿物油等)与光模块材料的化学稳定性,确保长期浸没环境下无腐蚀、溶胀或性能衰减。关键风险点:密封材料(如硅胶、环氧树脂)的溶解或老化;金…...
shell 循环
shell 循环while语句,shell循环until语句在上一篇shell流程控制 1.shell循环until语句 until 条件 #当后面的条件表达式为假的时候的才循环,为真的时候就停止了 do 循环体 done [root@linux-server script]# cat until.sh (1) #!/bin/bash x=1 until [ $x -ge 10 ] 大于…...
【产品经理】常见的交互说明撰写方法
在产品原型设计中,交互说明是确保开发团队准确理解设计意图的关键文档。以下是常见的交互说明撰写方法及其应用场景,帮助您系统化地传达交互逻辑: 文字描述法 方法:用自然语言详细描述操作流程、反馈及规则。 适用场景ÿ…...
使用kubeadmin 部署k8s集群
成功搭建一个 Kubernetes 1.28.2 集群,包含以下组件和状态: 集群拓扑 1 个 Master 节点 IP:10.1.1.100 角色:control-plane 2 个 Worker 节点 Node2:10.1.1.101 Node3:10.1.1.102 核心组件状态 所有节点通过 kubectl get nodes 显示为 Ready。 核心 Pod(如 etc…...
二项式分布html实验
二项式分布html实验 本文将带你一步步搭建一个纯前端的二项分布 Monte-Carlo 模拟器。 只要一个 HTML 文件,打开就能运行: 动态输入试验次数 n、成功概率 p 与重复次数 m点击按钮立刻得到「模拟频数 vs 理论频数」柱状图随着 m 增大,两组柱状…...
[基础] Windows PCIe设备驱动框架与开发实践深度解析
Windows PCIe设备驱动框架与开发实践深度解析 1. PCIe设备驱动技术背景 PCI Express(Peripheral Component Interrupt Express)作为现代计算机系统的核心互连标准,其驱动程序开发涉及复杂的内核模式编程。Windows系统通过模块化的驱动架构支…...
面向智能家居安全的异常行为识别与应急联动关键技术研究与系统实现(源码+论文+部署讲解等)
需要资料,请文末系 一、平台介绍 3D家庭实景 - 动热力图 多模态看板 跌倒行为分析 二、论文内容 在这里插入图片描述](https://i-blog.csdnimg.cn/direct/2dfe7f45d3ce42399e0df9535870d26d.png) bash 摘要 Abstract第一章 绪论 1.1 研究背景与动机 o1.1.1…...
根据JSON动态生成表单表格
根据JSON动态生成表单表格 一. 子组件 DynamicFormTable.vue1,根据JSON数据动态生成表单表格,支持表单验证JS部分1.1,props数据1.2,表单数据和数据监听1.3,自动验证1.4,表单验证1.5,获取表单数据1.6,事件处理1.7,暴露方法给父组件2,HTML部分二,父组件1, 模拟数据2,…...
spring OncePerRequestFilter 作用
概要 OncePerRequestFilter 是 Spring Web 提供的一个抽象滤器基类,用于保证在一次 HTTP 请求的整个分派过程中,该滤器仅执行一次,无论该请求经历了多少次内部转发(forward)、包含(include)或错…...
关于开源大模型(如 LLaMA、InternLM、Baichuan、DeepSeek、Qwen 等)二次开发或训练经验的关键点和概述
以下是适合初学者理解的关于开源大模型(如 LLaMA、InternLM、Baichuan、DeepSeek、Qwen 等)二次开发或训练经验的关键点和概述,: 关键点: 研究表明,二次开发通常涉及微调模型以适应特定任务,需…...
promethus基础
1.下载prometheus并解压 主要配置prometheus.yml文件 在scrape_configs配置项下添加配置(hadoop202是主机名): scrape_configs: job_name: ‘prometheus’ static_configs: targets: [‘hadoop202:9090’] 添加 PushGateway 监控配置 job_name: ‘pushgateway’…...
26考研 | 王道 | 数据结构 | 第八章 排序
第八章 排序 文章目录 第八章 排序**8.1** 排序的基本概念**8.2 插入排序****8.2.1 直接插入排序****8.2.2 折半插入排序****8.2.3 希尔排序** 8.3 交换排序8.3.1 冒泡排序8.3.2 快速排序 8.4 选择排序8.4.1 简单选择排序8.4.2 堆排序堆的概念:建立大根堆的代码堆排…...
SecMulti-RAG:兼顾数据安全与智能检索的多源RAG框架,为企业构建不泄密的智能搜索引擎
本文深入剖析SecMulti-RAG框架,该框架通过集成内部文档库、预构建专家知识以及受控外部大语言模型,并结合保密性过滤机制,为企业提供了一种平衡信息准确性、完整性与数据安全性的RAG解决方案,同时有效控制部署成本。 企业环境中A…...
kubesphere 单节点启动 etcd 报错
kubekey安装 ./kk create cluster -f config-sample.yaml --with-local-storage 时报错 etcd health check failed: Failed to exec command: sudo -E /bin/bash -c "export ETCDCTL_API2;export ETCDCTL_CERT_FILE/etc/ssl/etcd/ssl/admin-node1.pem;export ETCDCTL_KEY_…...
femap许可常见问题及解决方案
在使用Femap进行电磁仿真分析时,许可证管理是一个关键环节。然而,许多用户在许可证使用过程中可能会遇到各种问题。本文旨在解答关于Femap许可的常见疑问,并提供相应的解决方案,帮助您更顺畅地使用Femap许可证。 一、常见问题 许…...
游戏引擎学习第244天: 完成异步纹理下载
启动并运行游戏,注意到我们的纹理没有被下载 我们将继续完成游戏的开发。昨天,我们已经实现了多线程的纹理下载,但并没有时间调试它,因此纹理下载功能目前并没有正常工作。我们只是写了相关的代码,但由于大部分时间都…...
【安全扫描器原理】TCP/IP协议编程
【安全扫描器原理】TCP/IP协议编程 1.概述2.Windows Socket结构3.Windows socket转换类函数4.Windows Socket通信类函数 1.概述 TCP/IP协议是目前网络中使用最广泛的协议,Socket称为“套接口”,最早出现在Berkeley Unix中,最初只支持TCP/I…...
Cuda-GDB Frame Unwind 管理(未完.)
在计算机编程中,Frame Unwind(栈展开) 是指函数调用栈的逆向操作,即在函数返回或异常发生时,系统逐层释放栈帧(Stack Frame)、恢复调用上下文的过程。以下是详细解释及其在 GPU编程(…...