目录

1.const修饰的迭代器的实现

方法1:分成两个类

完整代码

方法2:STL库的写法

2.STL库的第三个模版参数T*的解释

->->的简写语法 

3.其他成员函数

insert

erase

push_back、push_front、pop_front、pop_back

size

clear

析构函数~list()

拷贝构造函数(★)

私有函数empty_initialize

swap

operator=

4.提交到leetcode题上测试成员函数的正确性

代码

提交结果


承接CD46.【C++ Dev】list的模拟实现(1)文章

1.const修饰的迭代器的实现

回顾const修饰的迭代器的要求:1.自己可以修改 2.指向的数据不能修改

方法1:分成两个类

const修饰的迭代器和非const修饰的迭代器分成两个类,写两份代码,这两份代码仅仅是operator*的返回的参数不同

//const修饰的迭代器
const T& operator*()
{return node->data;
}//非const修饰的迭代器
T& operator*()
{return node->data;
}

注意:const修饰的迭代器中的operator*不能写成T& operator*() const,这个const修饰的是this指针指向的对象node不能被修改(在CD22.【C++ Dev】类和对象(13) 流提取运算符的重载和const成员文章讲过),不是指node->data不能修改

完整代码

#pragma once
namespace mystl
{template<class T>struct __list_node{typedef __list_node<T>* link_type;__list_node(const T& x = T()):next(nullptr), prev(nullptr), data(x){}link_type next;link_type prev;T data;};template<class T>struct __list_iterator{typedef __list_node<T>* link_type;typedef __list_iterator<T> iterator;__list_iterator(link_type x):node(x){}iterator& operator++(){node = node->next;return *this;}iterator operator++(int){iterator tmp(*this);node = node->next;return tmp;}iterator& operator--(){node = node->prev;return *this;}iterator operator--(int){iterator tmp(*this);node = node->prev;return tmp;}bool operator!=(const iterator& x) const{return node != x.node;}bool operator==(const iterator& x) const{return node == x.node;}T& operator*(){return node->data;}link_type node;};template<class T>struct __list_const_iterator{typedef __list_node<T>* link_type;typedef __list_const_iterator<T> const_iterator;__list_const_iterator(link_type x):node(x){}const_iterator& operator++(){node = node->next;return *this;}const_iterator operator++(int){const_iterator tmp(*this);node = node->next;return tmp;}const_iterator& operator--(){node = node->prev;return *this;}const_iterator operator--(int){const_iterator tmp(*this);node = node->prev;return tmp;}bool operator!=(const const_iterator& x) const{return node != x.node;}bool operator==(const const_iterator& x) const{return node == x.node;}const T& operator*(){return node->data;}link_type node;};template<class T>class list{typedef __list_node<T> list_node;typedef __list_node<T>* link_type;public:typedef __list_iterator<T> iterator;typedef __list_const_iterator<T> const_iterator;list(){node = new list_node;node->next = node;node->prev = node;}void push_back(const T& x){link_type tmp = new list_node(x);//先找尾link_type tail = node->prev;tail->next = tmp;tmp->prev = tail;tmp->next = node;node->prev = tmp;}iterator begin(){//返回哨兵位的下一个节点return node->next;}iterator end(){//返回哨兵位return node;}const_iterator begin() const{//返回哨兵位的下一个节点return node->next;}const_iterator end() const{//返回哨兵位return node;}private:link_type node;};
}

测试代码:

#include <iostream>
#include "list.h"
void print_list(const mystl::list<int>& ls)//权限缩小
{mystl::list<int>::const_iterator it = ls.begin();while (it != ls.end()){std::cout << *it << " ";it++;}}
int main()
{mystl::list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);print_list(ls);return 0;
}

运行结果:

方法2:STL库的写法

STL的源码:__list_iterator迭代器类有3个模版参数:T、Ref、Ptr

template<class T, class Ref, class Ptr>
struct __list_iterator {typedef __list_iterator<T, T&, T*>             iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef __list_iterator<T, Ref, Ptr>           self;//......typedef Ref reference;//......reference operator*() const { return (*node).data; }
}

operator*的返回类型为reference,而reference为Ref,Ref是__list_iterator类的第二个模版参数

这样可以为Ref指定:T&或者const T&,这样可以简写const修饰和非const修饰的迭代器,没有必要写两份代码

之前返回类型为iterator要改成__list_iterator<T, Ref>,可以重定义为self 

其实是让编译器来代替我们写iterator和const_iterator这两个类

template<class T,class Ref>
struct __list_iterator
{typedef __list_node<T>* link_type;typedef __list_iterator<T,T&> iterator;typedef __list_iterator<T,const T&> const_iterator;typedef __list_iterator<T, Ref>	self;typedef Ref reference;__list_iterator(link_type x):node(x){}self& operator++(){node = node->next;return *this;}self operator++(int){self tmp(*this);node = node->next;return tmp;}self& operator--(){node = node->prev;return *this;}self operator--(int){self tmp(*this);node = node->prev;return tmp;}bool operator!=(const self& x) const{return node != x.node;}bool operator==(const self& x) const{return node == x.node;}reference operator*(){return node->data;}link_type node;
};

继续测试之前的代码,运行结果:

2.STL库的第三个模版参数T*的解释

上方代码实现的__list_iterator只有2个模版参数,但是STL库却有3个模板参数:

template<class T, class Ref, class Ptr>
struct __list_iterator 
{//......
}

看看Ptr出现在什么函数中:

STL库将Ptr重定义为pointer: 

typedef Ptr pointer;

那就找pointer还出现在哪里:

#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */

发现:pointer是operator->的返回类型,原因:

迭代器的任务是模拟指针,而结构体指针是可以用operator->来访问其指向对象的成员,那迭代器也要有operator->操作符

 那自制的operator->可以这样写:

template<class T,class Ref,class Ptr>
struct __list_iterator
{typedef __list_node<T>* link_type;typedef __list_iterator<T,T&,T*> iterator;typedef __list_iterator<T,const T&,const T*> const_iterator;typedef __list_iterator<T, Ref,Ptr>	self;typedef Ref reference;typedef Ptr pointer;//......reference operator*(){return node->data;}pointer operator->(){return &(node->data);}link_type node;
};

当然也可以复用operator*,写成:

pointer operator->()
{return &(operator*());
}

测试代码:

#include <iostream>
#include "list.h"
class  Myclass
{
public:Myclass(const int val1=0, const char val2='\0'):_val1(val1), _val2(val2){}int _val1;char _val2;
};int main()
{mystl::list<Myclass> ls;ls.push_back(Myclass(1,'a'));ls.push_back(Myclass(2, 'b'));ls.push_back(Myclass(3, 'c'));mystl::list<Myclass>::iterator it = ls.begin();while (it != ls.end()){std::cout << it->_val1 << " " << it->_val2 << std::endl;std::cout << (*it)._val1 << " " << (*it)._val2 << std::endl;it++;}return 0;
}

运行结果:

发现it->_val1和(*it)._val1的效果是等价的

->->的简写语法 

注意到operator->()返回的是Myclass*,严谨来说Myclass*是不能访问_val1和_val2的,应该写成

std::cout << it->->_val1 << " " << it->->_val2 << std::endl;

但编译器在编译时自动加上了第二个->,C++标准只允许写一个->,提高运算符重载的可读性 

3.其他成员函数

insert

和STL保持一致:

这里只实现第一个: 

先生成新节点,再在pos前插入:

iterator insert(iterator pos,const T& val)
{link_type newnode = new list_node(val);newnode->prev = pos.node->prev;newnode->next = pos.node;pos.node->prev->next = newnode;pos.node->prev = newnode;return newnode;
}

测试代码:

#include <iostream>
#include "list.h"
int main()
{mystl::list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);auto new_it1=ls.insert(++ls.begin(), 4);//在2的前面插入4for (auto a : ls)std::cout << a << " ";return 0;
}

运行结果:

erase

和STL保持一致:

这里只实现第一个: 

注意:erase不能删哨兵位,因此先断言

erase函数在删除元素时,会‌使当前迭代器失效‌n并返回指向‌下一个元素‌的迭代器,因此不能返回void

iterator erase(iterator pos)
{assert(pos != end());iterator ret = pos.node->next;pos.node->prev->next = pos.node->next;pos.node->next->prev = pos.node->prev;delete pos.node;return ret;
}

测试代码:

#include <iostream>
#include "list.h"
int main()
{mystl::list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);ls.erase(++ls.begin());//删除2for (auto a : ls)std::cout << a << " ";return 0;
}

运行结果:

push_back、push_front、pop_front、pop_back

可以复用insert和erase的代码

void push_back(const T& x)
{insert(end(), x);
}void push_front(const T& x)
{insert(begin(), x);
}
void pop_front()
{erase(begin());
}
void pop_back()
{erase(--end());
}

 测试代码:

#include <iostream>
#include "list.h"
int main()
{mystl::list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);ls.push_back(4);ls.pop_back();ls.pop_front();ls.push_back(5);ls.push_front(6);for (auto a : ls)std::cout << a << " ";return 0;
}

运行结果:

size

STL库的实现:

size_type size() const {size_type result = 0;distance(begin(), end(), result);return result;
}

distance是算法库<algorithm>中的函数,用于计算两个迭代器之间的距离,并将结果存储到result中,这里我们实现的简单一些:

void distance(const_iterator begin, const_iterator end, size_type& result) const
{const_iterator it = begin;while (it != end){it++;result++;}
}
size_type size() const 
{size_type result = 0;distance(begin(), end(), result);return result;
}

测试代码:

#include <iostream>
#include "list.h"
int main()
{mystl::list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);ls.push_back(4);std::cout << ls.size();return 0;
}

(当然这样遍历一遍是有缺点的,比较耗时,可以为list类引入第二个成员变量size来存储链表的长度,这里省略不写) 

运行结果:

clear

和STL保持一致:

删除多余节点,只保留哨兵位

void clear()
{iterator it = begin();while (it != end())it=erase(it);//应对迭代器失效,接收返回值
}

测试代码:

#include <iostream>
#include "list.h"
int main()
{mystl::list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);for (auto a : ls)std::cout << a << " ";ls.clear();ls.push_back(4);ls.push_back(5);ls.push_back(6);for (auto b : ls)std::cout << b << " ";return 0;
}

运行结果:

析构函数~list()

先调用clear(),再将node释放,最后置为空指针

~list()
{clear();delete node;node = nullptr;
}

拷贝构造函数(★)

注意是深拷贝,浅拷贝会出问题(在CD44.【C++ Dev】vector模拟实现(3)文章的深拷贝问题解决提到过)

方法:通过遍历的方式一个个拷贝

//const修饰,防止权限放大
list(const list<T>& ls)//必须是引用,这个&如果不写,会无限调用拷贝构造函数
{//准备哨兵位node = new list_node;node->next = node;node->prev = node;//添加节点for (auto& a : ls)//使用引用,节省时间{push_back(a);}
}

测试代码:

#include <iostream>
#include "list.h"
int main()
{mystl::list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);mystl::list<int> ls_copy(ls);for (auto a : ls_copy)std::cout << a<<" ";return 0;
}

运行结果:

 

私有函数empty_initialize

两种构造函数的部分代码有些冗余

可以封装成一个私有函数empty_initialize(),当然库里面也是这样实现的:

swap

和STL保持一致:

注:上面swap的参数:list& x的list是类名,不是类型,却也可以做参数,C++的语法支持这样做,但不建议这样写,代码不直观

交换链表其实是交换头节点

void swap(list<T>& ls)//写成void swap(list& ls)也可以
{std::swap(node, ls.node);
}

测试代码:

#include <iostream>
#include "list.h"
int main()
{mystl::list<int> ls1; ls1.push_back(1); ls1.push_back(2); ls1.push_back(3);mystl::list<int> ls2; ls2.push_back(4); ls2.push_back(5); ls2.push_back(6);std::cout << "ls1:";for (auto a : ls1) std::cout << a << " ";std::cout << std::endl << "ls2:";for (auto b : ls2) std::cout << b << " ";ls1.swap(ls2);std::cout << std::endl << "ls1:";for (auto a : ls1) std::cout << a<<" ";std::cout << std::endl << "ls2:";for (auto b : ls2) std::cout << b<<" ";return 0;
}

运行结果:

operator=

使用CD40.【C++ Dev】string类的模拟实现(4)(operator=、拷贝构造函数的现代写法、写时拷贝的简单了解)文章提到的现代写法:1.operator=的参数需要调用拷贝构造 2.调用swap

list<T>& operator=(list<T> tmp)//写成list& operator=(list tmp)也可以
{swap(tmp);return *this;
}

测试代码:

#include <iostream>
#include "list.h"
int main()
{mystl::list<int> ls1; ls1.push_back(1); ls1.push_back(2); ls1.push_back(3);mystl::list<int> ls2 = ls1;std::cout << "ls2:";for (auto a : ls2) std::cout << a << " ";return 0;
}

4.提交到leetcode题上测试成员函数的正确性

题:https://leetcode.cn/problems/design-linked-list/

你可以选择使用单链表或者双链表,设计并实现自己的链表。

单链表中的节点应该具备两个属性:valnextval 是当前节点的值,next 是指向下一个节点的指针/引用。

如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。

实现 MyLinkedList 类:

  • MyLinkedList() 初始化 MyLinkedList 对象。
  • int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1
  • void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
  • void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
  • void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
  • void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。

示例:

输入
["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"]
[[], [1], [3], [1, 2], [1], [1], [1]]
输出
[null, null, null, null, 2, null, 3]解释
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.addAtHead(1);
myLinkedList.addAtTail(3);
myLinkedList.addAtIndex(1, 2);    // 链表变为 1->2->3
myLinkedList.get(1);              // 返回 2
myLinkedList.deleteAtIndex(1);    // 现在,链表变为 1->3
myLinkedList.get(1);              // 返回 3

提示:

  • 0 <= index, val <= 1000
  • 请不要使用内置的 LinkedList 库。
  • 调用 getaddAtHeadaddAtTailaddAtIndexdeleteAtIndex 的次数不超过 2000

代码

namespace mystl
{template<class T>struct __list_node{typedef __list_node<T>* link_type;__list_node(const T& x = T()):next(nullptr), prev(nullptr), data(x){}link_type next;link_type prev;T data;};template<class T,class Ref,class Ptr>struct __list_iterator{typedef __list_node<T>* link_type;typedef __list_iterator<T,T&,T*> iterator;typedef __list_iterator<T,const T&,const T*> const_iterator;typedef __list_iterator<T, Ref,Ptr>	self;typedef Ref reference;typedef Ptr pointer;__list_iterator(link_type x):node(x){}self& operator++(){node = node->next;return *this;}self operator++(int){self tmp(*this);node = node->next;return tmp;}self& operator--(){node = node->prev;return *this;}self operator--(int){self tmp(*this);node = node->prev;return tmp;}bool operator!=(const self& x) const{return node != x.node;}bool operator==(const self& x) const{return node == x.node;}reference operator*(){return node->data;}pointer operator->(){return &(node->data);}link_type node;};template<class T>class list{typedef __list_node<T> list_node;typedef __list_node<T>* link_type;typedef size_t size_type;public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;list(){empty_initialize();}list(const list<T>& ls){empty_initialize();for (auto& a : ls){push_back(a);}}void push_back(const T& x){insert(end(), x);}iterator begin(){return node->next;}iterator end(){//返回哨兵位return node;}const_iterator begin() const{return node->next;}const_iterator end() const{return node;}iterator insert(iterator pos,const T& val){link_type newnode = new list_node(val);newnode->prev = pos.node->prev;newnode->next = pos.node;pos.node->prev->next = newnode;pos.node->prev = newnode;return newnode;}iterator erase(iterator pos){assert(pos != end());iterator ret = pos.node->next;pos.node->prev->next = pos.node->next;pos.node->next->prev = pos.node->prev;delete pos.node;return ret;}void push_front(const T& x){insert(begin(), x);}void pop_front(){erase(begin());}void pop_back(){erase(--end());}void distance(const_iterator begin, const_iterator end, size_type& result) const{const_iterator it = begin;while (it != end){it++;result++;}}size_type size() const {size_type result = 0;distance(begin(), end(), result);return result;}void clear(){iterator it = begin();while (it != end())it=erase(it);}void swap(list<T>& ls){std::swap(node, ls.node);}list<T>& operator=(list<T> tmp){swap(tmp);return *this;}~list(){clear();delete node;node = nullptr;}private:void empty_initialize(){node = new list_node;node->next = node;node->prev = node;}link_type node;};
}class MyLinkedList {
public:MyLinkedList() {}mystl::list<int>::iterator getiterator(int index){mystl::list<int>::iterator it=ls.begin();while(index--)it++;return it;}int get(int index) {if (index<ls.size())return getiterator(index).node->data; return -1;       }void addAtHead(int val) {ls.push_front(val);}void addAtTail(int val) {ls.push_back(val);}void addAtIndex(int index, int val) {if (index<=ls.size())//取等是尾插ls.insert(getiterator(index),val);}void deleteAtIndex(int index) {if (index<ls.size())ls.erase(getiterator(index));}mystl::list<int> ls;
};

提交结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88471.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88471.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/88471.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UI前端与数字孪生融合新领域拓展:智慧教育的虚拟实验室建设

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩!一、引言&#xff1a;虚拟实验室 —— 打破教育边界的技术革命传统实验教学正面临 “设备昂贵、…

7. TCP 和 UDP 的区别

总结 TCP 面向连接&#xff0c;需要三次握手建立连接&#xff0c;UDP 无连接&#xff0c;不需要握手&#xff0c;直接发送数据。UDP 有较好的实时性&#xff0c;效率比 TCP 高。TCP 面向字节流&#xff0c;实际上是 TCP 把数据看成一连串无结构的字节流&#xff0c;UDP 是面向报…

iOS Widget 开发-7:TimelineProvider 机制全解析:构建未来时间线

在 WidgetKit 中&#xff0c;TimelineProvider 是小组件生命周期的核心机制之一。它控制着 数据获取时机、展示内容 与 刷新策略&#xff0c;是实现时间驱动内容更新的基础。 本文将介绍 TimelineProvider 的工作原理、设计模式、常见场景与高级用法&#xff0c;帮助大家构建智…

基于PHP/MySQL的企业培训考试系统源码,高并发、稳定运行,源码开源可二开

温馨提示&#xff1a;文末有资源获取方式这是一款专为企业设计的开源培训考试系统&#xff0c;采用PHPMySQL技术栈开发&#xff0c;具有高并发处理能力和稳定运行特性。系统源码完全开放&#xff0c;支持二次开发&#xff0c;可满足各类企业的培训考核需求。核心功能特点1. 高性…

时序数据库InfluxDB

一.定义 时序数据库 是一种专门用于高效存储和查询带有时间戳的数据的数据库。如果你的数据是随着时间变化而不断产生&#xff0c;并且你想知道过去某一时刻发生了什么&#xff0c;那么你应该用时序数据库。 这类数据通常具有以下特征&#xff1a; 数据点按时间顺序不断写入…

2025.07.09华为机考真题解析-第三题300分

📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ 03. 博物馆安保摄像头配置 问题描述 A先生负责为一家新开的博物馆设计安保监控系统。博物馆有多个展厅需要监控,每个展厅都有不同的面积。现在有多种型号的监控摄像头可供选择,每…

存储过程封装:复杂业务逻辑的性能优化

存储过程作为数据库层面的重要功能&#xff0c;能够显著提升复杂业务逻辑的执行效率。以下是存储过程在性能优化中的核心优势、实现策略和实际应用场景。一、存储过程的核心优势‌网络传输压缩‌存储过程将多条SQL语句封装为单次调用&#xff0c;相比应用层多次请求可减少60%-8…

逗号分隔字段统计秘籍:一条SQL实现逗号分割字段的数量分析

一、问题场景与痛点 在数据库设计中&#xff0c;经常会遇到统计某一些数据的最大数量最小数量等&#xff0c;特别是**逗号分隔字段 **的统计会显得非常困难 下面以我生产上遇到的一个问题讲解&#xff1a; 有个需求是在o_work_order表中统计sn字段中哪个工单号的数量最多&#…

数据库性能优化指南:解决ORDER BY导致的查询性能问题( SQL Server )

数据库性能优化指南&#xff1a;解决ORDER BY导致的查询性能问题 问题描述 在300万行的INTERFACE_INTERACTION_LOG表中执行以下查询&#xff1a; SELECT TOP 1 * FROM INTERFACE_INTERACTION_LOG WHERE 1 1AND (SENDSTATUS 0 OR SENDSTATUS -1)AND SENDMETHOD POSTAND ERRO…

Centos 7下使用C++使用Rdkafka库实现生产者消费者

1. 了解 Kafka Apache Kafka 是一个分布式流处理平台&#xff0c;核心功能包括&#xff1a; 发布/订阅消息系统&#xff1a;解耦生产者和消费者 分布式存储&#xff1a;持久化、容错的消息存储 流处理&#xff1a;实时处理数据流 核心概念&#xff1a; 概念说明BrokerKaf…

UE5多人MOBA+GAS 13、添加死亡、复活逻辑以及布娃娃含物理资产的修改调整

文章目录使用GE为角色添加定时的Tag控制死亡时间1、添加死亡Tag2、创建死亡GE&#xff0c;并完成相关配置3、在AbilitySystemComponent中监听属性的变化&#xff0c;调用GE来添加Tag到角色上4、在角色中监听ASC传入的Tag以及Tag的层数&#xff0c;来响应不同的函数添加死亡、复…

Jiasou TideFlow重塑AI SEO全链路自动化新标杆

引言 在Google日均处理85亿次搜索请求的数字化浪潮中&#xff0c;传统SEO工作流面临三大致命瓶颈&#xff1a;人工拓词效率低下、跨部门协作成本高企、数据监控链路断裂。因此诸如Jiasou AI SEO这样专门为AI SEO而生的Agent就应运而生了。 背景 Jiasou AIGC不仅仅可以批量生成…

CentOs 7 MySql8.0.23之前的版本主从复制

准备俩台虚拟机并启动俩台虚拟机都开启mysql后查看二进制日志是否开启先登录mysqlmysql -u root -r输入sql命令show variables like %log_bin%;如果log_bin 的value为OFF则是没有开启&#xff0c;跟着下面步骤开启二进制日志退出mysqlexitvim /etc/my.cnf在最底下添加log_binmy…

Leetcode 3607. Power Grid Maintenance

Leetcode 3607. Power Grid Maintenance 1. 解题思路2. 代码实现 题目链接&#xff1a;3607. Power Grid Maintenance 1. 解题思路 这一题思路上首先是一个DSU的思路&#xff0c;将所有的连通网络计算出来&#xff0c;并对每一个网络的节点进行归类。然后我们需要对每一个网…

开源 python 应用 开发(三)python语法介绍

最近有个项目需要做视觉自动化处理的工具&#xff0c;最后选用的软件为python&#xff0c;刚好这个机会进行系统学习。短时间学习&#xff0c;需要快速开发&#xff0c;所以记录要点步骤&#xff0c;防止忘记。 链接&#xff1a; 开源 python 应用 开发&#xff08;一&#xf…

1-Kafka介绍及常见应用场景

Kafka 介绍 Apache Kafka 是一个开源的 分布式流处理平台&#xff0c;最初由 LinkedIn 开发&#xff0c;后捐赠给 Apache 软件基金会。它被设计用于高吞吐量、低延迟、可水平扩展地处理实时数据流。官网地址是&#xff1a;https://kafka.apache.org/ 以下是 Kafka 的核心介绍…

CH9121T电路及配置详解

目录1. CH9121T简介2. 原理图及接口2.1 参考电路2.2 CH9121T评估板2.3 差分端口2.4 网口灯显示2.5 晶振2.6 其他接口3. 使用手册及说明3.1 配置介绍3.2 默认参数3.3 串口波特率3.4 配置指令3.5 应用示例1. CH9121T简介 CH9121 是一款网络串口透传芯片&#xff0c;自带 10/100M…

科研数据可视化核心技术:基于 AI 与 R 语言的热图、火山图及网络图绘制实践指南

在学术研究竞争日趋激烈的背景下&#xff0c;高质量的数据可视化已成为科研成果呈现与学术传播的关键要素。据统计&#xff0c;超过 60% 的学术稿件拒稿原因与图表质量存在直接关联&#xff0c;而传统绘图工具在处理组学数据、复杂关联数据时&#xff0c;普遍存在效率低下、规范…

Windows体验macOS完整指南

一、虚拟机安装macOS专业方案1. 环境准备阶段硬件检测&#xff1a;进入BIOS&#xff08;开机时按Del/F2键&#xff09;确认开启VT-x/AMD-V虚拟化选项建议配置&#xff1a;i5十代以上CPU/16GB内存/256GB SSD软件准备&#xff1a;官网下载VMware Workstation 17 Pro获取Unlocker补…

【普及/提高−】洛谷P1577 ——切绳子

见&#xff1a;P1577 切绳子 - 洛谷 题目描述 有 N 条绳子&#xff0c;它们的长度分别为 Li​。如果从它们中切割出 K 条长度相同的绳子&#xff0c;这 K 条绳子每条最长能有多长&#xff1f;答案保留到小数点后 2 位(直接舍掉 2 位后的小数)。 输入格式 第一行两个整数 N …