关于标准库中的反向迭代器

   什么是迭代器?        

           迭代器(iterator)有时又称光标(cursor)是程序设计的软件设计模式,可在容器对象(container,例如list或vector)上遍历访问的接口,通常来说就是访问容器(数据结构中保存)的元素。并且迭代器是分类型的,STL中的名字是类型的暗示(比如Inputiterator),迭代器的使用属性是正向访问以及反向访问;还有特性属性,严格来说还分单向双向随机,单链表的迭代器特性就是一个单向的,它只能++,不能--,双向链表的迭代器特性就是双向的,不仅能++,还能--。随机就是不仅能++,--,还能+,-,像string,vector就是随机的特性。

 注:

iterator:迭代器/正向迭代器
reverse_iterator:反向迭代器
const_iterator:const迭代器/const正向迭代器
const_reverse_iterator:const反向迭代器

反向迭代器的实现:

以 list 的迭代器为例:建议先看一下list迭代器的底层,再来看此文章会更通俗易懂。

                                                                                                     list.h - iterator的实现:

    template<class T, class Ref, class Ptr>struct __list_iterator{public:typedef list_node<T> node;typedef __list_iterator<T, Ref, Ptr> self;node* _node;__list_iterator(node* x):_node(x){}Ptr operator->(){return &_node->_data;}Ref operator*(){return _node->_data;}self& operator++(){_node = _node->_next;return *this;}bool operator!=(const self& s){return _node != s._node;}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& s){return _node == s._node;}};

这里实现正向迭代器的逻辑是左闭右开:

所以我们认为反向也应该是如此左闭右开:从最后一个有效元素开始访问,反向的++就是正向的--

这里怎样实现呢?很简单,再写一个类,修改下正向迭代器就可以了:

                                                                                list.h - reverse_iterator① 的实现:

    template<class T, class Ref, class Ptr>struct __list_reverse_iterator{public:typedef list_node<T> node;typedef  __list_reverse_iterator<T, Ref, Ptr> self;node* _node;__list_reverse_iterator(node* x):_node(x){}Ptr operator->(){return &_node->_data;}Ref operator*(){return _node->_data;}self& operator++(){_node = _node->_prev;return *this;}bool operator!=(const self& s){return _node != s._node;}self& operator++(int){self tmp(*this);_node = _node->_prev;return tmp;}self& operator--(){_node = _node->_next;return *this;}self& operator--(int){self tmp(*this);_node = _node->_next;return tmp;}bool operator==(const self& s){return _node == s._node;}

这里我们会发现有大量重复的代码,而c++又很讨厌这种代码的臃肿性,所以这里可以看一下stl的底层:

stl源码:

                                                                                                   stl_list.h部分源码

template <class T, class Alloc = alloc>
class list {
protected:typedef void* void_pointer;typedef __list_node<T> list_node;typedef simple_alloc<list_node, Alloc> list_node_allocator;
public:      typedef T value_type;typedef value_type* pointer;typedef const value_type* const_pointer;typedef value_type& reference;typedef const value_type& const_reference;typedef list_node* link_type;typedef size_t size_type;typedef ptrdiff_t difference_type;public:typedef __list_iterator<T, T&, T*>             iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;#ifdef __STL_CLASS_PARTIAL_SPECIALIZATIONtypedef reverse_iterator<const_iterator> const_reverse_iterator;typedef reverse_iterator<iterator> reverse_iterator;
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */typedef reverse_bidirectional_iterator<const_iterator, value_type,const_reference, difference_type>const_reverse_iterator;typedef reverse_bidirectional_iterator<iterator, value_type, reference,difference_type>reverse_iterator; 
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */

这里可以发现,c++是使用类模板封装了正向迭代器,这里我们再继续往下看:

                                                                                                stl_iterator.h部分源码

template <class Iterator>
class reverse_iterator 
{
protected:Iterator current;
public:typedef typename iterator_traits<Iterator>::iterator_categoryiterator_category;typedef typename iterator_traits<Iterator>::value_typevalue_type;typedef typename iterator_traits<Iterator>::difference_typedifference_type;typedef typename iterator_traits<Iterator>::pointerpointer;typedef typename iterator_traits<Iterator>::referencereference;typedef Iterator iterator_type;typedef reverse_iterator<Iterator> self;public:reverse_iterator() {}explicit reverse_iterator(iterator_type x) : current(x) {}reverse_iterator(const self& x) : current(x.current) {}
#ifdef __STL_MEMBER_TEMPLATEStemplate <class Iter>reverse_iterator(const reverse_iterator<Iter>& x) : current(x.current) {}
#endif /* __STL_MEMBER_TEMPLATES */iterator_type base() const { return current; }reference operator*() const {Iterator tmp = current;return *--tmp;}#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */self& operator++() {--current;return *this;}self operator++(int) {self tmp = *this;--current;return tmp;}self& operator--() {++current;return *this;}self operator--(int) {self tmp = *this;++current;return tmp;}self operator+(difference_type n) const {return self(current - n);}self& operator+=(difference_type n) {current -= n;return *this;}self operator-(difference_type n) const {return self(current + n);}self& operator-=(difference_type n) {current += n;return *this;}reference operator[](difference_type n) const { return *(*this + n); }  
}; 

         可以看到stl底层 reverse_iterator 的实现,其实是使用了正向迭代器来进行封装,反向迭代器的 ++ 就是正向迭代器的 -- ,反向迭代器的 -- 就是正向迭代器的 ++ 。

                                                                                                stl_list.h部分源码

protected:link_type node;public:list() { empty_initialize(); }iterator begin() { return (link_type)((*node).next); //node是头指针,也就是_head}const_iterator begin() const { return (link_type)((*node).next); }iterator end() { return node; //头指针}const_iterator end() const { return node; }reverse_iterator rbegin() { return reverse_iterator(end()); }const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }reverse_iterator rend() { return reverse_iterator(begin()); }const_reverse_iterator rend() const { return const_reverse_iterator(begin());} 

这时,我们发现,stl 底层 rbegin() rend()  的位置与我们预料的不同:

我们实现的:rbegin() 是在最后一个有效数据位

实际上 stl 底层库:

这里很明显,c++更追求一种对称的效果,那么这样的话,在实现 operator*()  的时候就不能按照我们的思路,先来看看底层stl是怎样实现的:

这里我们会发现,stl 库里在实现 operator*() 的时候,返回的是迭代器当前位置的前一个位置

所以接下来我们需要重新实现一个类:因为stl 库里面是采用萃取来实现,太过于复杂,这里实现方式不同,我采用的是新增模板参数。

                                ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        reverse_iterator.h

    template<class Iterator, class Ref, class Ptr>struct ReverseIterator //为了和库里进行区分,选择驼峰法{typedef ReverseIterator<Iterator, Ref, Ptr> Self;Iterator _cur;ReverseIterator(Iterator it):_cur(it){}Ref operator*(){Iterator tmp = _cur;--tmp;return *tmp;}Self& operator++(){--_cur;return *this;}Self& operator--(){++_cur;return *this;}bool operator!=(const Self& s){return _cur != s._cur;}Self& operator++(int){Self tmp(*this);--_cur;return tmp;}Self& operator--(int){Self tmp(*this);++_cur;return tmp;}bool operator==(const Self& s){return _cur == s._cur;}};

        写到这里,也许很多人都会有一个疑问,这也是实现一个类,好像跟reverse_iterator①没有什么不同,代码上并没有节省,还不如reverse_iterator① 来的更通俗易懂,为什么要如此大费周章?


        其实这里反向迭代器采用适配器的模式其实是为了复用,仔细想想list 的反向迭代器可以拷贝一份正向迭代器进行修改,那vector呢(注:具体可以查看vector的底层实现,这里iterator采用的原生指针),而实现 reverse_iterator.h 不仅仅是list可以使用,在这里只要是任何一个双向迭代器的容器都可以进行复用 。例如:

         至此,我们需要明白反向迭代器就是正向迭代器,不过是用类来进行封装。反向迭代器去封装正向迭代器,跟正向迭代器去封装指针没有任何本质的区别,物理空间上没都没有进行改变,都是对应那个地址,只是类型决定了是正向还是反向,而类型里面的 operator++() ,operator--() , operator*() ,这些都是根据使用者的需求来定义的,这套类的规则是使用者来定义的。

附上所有示例代码:

                                                                                                        reverse_iterator.h

#pragma oncenamespace dwr
{template<class Iterator, class Ref, class Ptr>struct ReverseIterator //为了和库里进行区分,选择驼峰法{typedef ReverseIterator<Iterator, Ref, Ptr> Self;Iterator _cur;ReverseIterator(Iterator it):_cur(it){}Ref operator*(){Iterator tmp = _cur;--tmp;return *tmp;}Self& operator++(){--_cur;return *this;}Self& operator--(){++_cur;return *this;}bool operator!=(const Self& s){return _cur != s._cur;}Self& operator++(int){Self tmp(*this);--_cur;return tmp;}Self& operator--(int){Self tmp(*this);++_cur;return tmp;}bool operator==(const Self& s){return _cur == s._cur;}};}

                                                                                                                        list.h

#pragma once
#include "reverse_iterator.h"
namespace dwr
{template<class T>struct list_node //链表节点{list_node<T>* _prev;list_node<T>* _next;T _data;list_node(const T& x = T()):_prev(nullptr), _next(nullptr), _data(x){}};template<class T, class Ref, class Ptr>struct __list_iterator{public:typedef list_node<T> node;typedef __list_iterator<T, Ref, Ptr> self;node* _node;__list_iterator(node* x):_node(x){}Ptr operator->(){return &_node->_data;}Ref operator*(){return _node->_data;}self& operator++(){_node = _node->_next;return *this;}bool operator!=(const self& s){return _node != s._node;}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& s){return _node == s._node;}};/*template<class T, class Ref, class Ptr>struct __list_reverse_iterator{public:typedef list_node<T> node;typedef  __list_reverse_iterator<T, Ref, Ptr> self;node* _node;__list_reverse_iterator(node* x):_node(x){}Ptr operator->(){return &_node->_data;}Ref operator*(){return _node->_data;}self& operator++(){_node = _node->_prev;return *this;}bool operator!=(const self& s){return _node != s._node;}self& operator++(int){self tmp(*this);_node = _node->_prev;return tmp;}self& operator--(){_node = _node->_next;return *this;}self& operator--(int){self tmp(*this);_node = _node->_next;return tmp;}bool operator==(const self& s){return _node == s._node;}};*/template<class T>class list{typedef list_node<T> node;public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;//typedef __list_reverse_iterator<T, T&, T*> reverse_iterator;typedef ReverseIterator<iterator, T&, T*> reverse_iterator;typedef ReverseIterator<iterator, const T&, const T*> const_reverse_iterator;reverse_iterator rbegin(){reverse_iterator tmp(end());return tmp;}reverse_iterator rend(){return reverse_iterator(begin());}/*reverse_iterator rbegin(){reverse_iterator tmp(_head->_prev);return tmp;}reverse_iterator rend(){return reverse_iterator(_head);}*/void empty_init() //初始化头节点{_head = new node;_head->_next = _head;_head->_prev = _head;}list(){empty_init();}void swap(list<T>& tmp){std::swap(_head, tmp._head);}//现代写法list(const list<T>& lt){empty_init();list<T> tmp(lt.begin(), lt.end());swap(tmp);}template<class Iterator>list(Iterator first, Iterator last){empty_init();while (first != last){push_back(*first);first++;}}//lt2 = lt1list<T>& operator=(list<T> lt){swap(lt);return *this;}iterator begin(){iterator tmp(_head->_next);return tmp;}iterator end(){return iterator(_head);}const_iterator begin() const{const_iterator tmp(_head->_next);return tmp;}const_iterator end() const{return const_iterator(_head);}void push_back(const T& x){node* tail = _head->_prev;node* newnode = new node(x);tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;}void push_front(const T& x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator erase(iterator pos){assert(pos != end());node* next = pos._node->_next;node* prev = pos._node->_prev;next->_prev = prev;prev->_next = next;delete pos._node;return iterator(next);}void insert(iterator pos, const T& x){node* cur = pos._node;node* prev = cur->_prev;node* new_node = new node(x);prev->_next = new_node;new_node->_next = cur;new_node->_prev = prev;cur->_prev = new_node;}void clear(){iterator it = begin();while (it != end()){erase(it++);}}~list(){clear();delete _head;_head = nullptr;}private:node* _head;};//------------------------------------------------void print_list(const list<int>& lt){list<int>::const_iterator it = lt.begin();while (it != lt.end()){//(*it) *= 2;cout << *it << " ";++it;}cout << endl;}void list_test1(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;}void list_test2(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);list<int>::reverse_iterator rit = lt.rbegin();while (rit != lt.rend()){cout << *rit << " ";++rit;}cout << endl;}
}

                                                                                                                vector.h

#pragma once#include "reverse_iterator.h"
namespace dwr
{template <class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;typedef ReverseIterator<iterator, T&, T*> reverse_iterator;typedef ReverseIterator<iterator, const T&, const T*> const_reverse_iterator;reverse_iterator rbegin(){reverse_iterator tmp(end());return tmp;}reverse_iterator rend(){return reverse_iterator(begin());}iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}vector(){}vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; ++i){push_back(val);}}vector(int n, const T& val = T()){reserve(n);for (int i = 0; i < n; ++i){push_back(val);}}//[first,last)template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);first++;}}void reserve(size_t n){if (n > capacity()){T* tmp = new T[n];size_t sz = size();if (_start){for (size_t i = 0; i < sz; ++i){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}}void resize(size_t n, T val = T()){if (n < size()){//删除数据_finish = _start + n;}else{if (n > capacity()){reserve(n);}while (_finish != _start + n){//注:这里如果实现逻辑是使用内存池,需要使用定位new来对已有空间进行初始化*_finish = val;++_finish;}}}iterator insert(iterator& pos, const T& val){assert(pos >= _start && pos <= _finish);if (_finish == _end_of_storage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);//扩容后 更新pospos = pos + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;_finish++;return pos;}iterator erase(iterator pos){assert(pos >= _start && pos <= _finish);iterator remove = pos + 1;while (remove != _finish){*(remove - 1) = remove;remove++;}--_finish;return pos;}void push_back(const T& x){if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;_finish++;}void pop_back(){assert(!empty());--_finish;}bool empty(){return _start == _finish;}T& operator[](size_t pos){assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}size_t size() const{return _finish - _start;}size_t capacity() const{return _end_of_storage - _start;}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}vector<T>& operator=(vector<T> v){swap(v);return *this;}vector(const vector<T>& v){_start = new T[v.capacity()];for (size_t i = 0; i < v.size(); ++i){_start[i] = v._start[i];}_finish = _start + v.size();_end_of_storage = _start + v.capacity();}//vector(const vector<T>& v)//{//	vector<T> tmp(v.begin(), v.end());//	swap(tmp);//}~vector(){//cout << _start << endl;delete[] _start;_start = _finish = _end_of_storage;}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;};void test_vector(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);for (auto e : v){cout << e << " ";}cout << endl;for (size_t i = 0; i < v.size(); ++i){cout << v[i] << " ";}cout << endl;vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;}void test_vector2(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);vector<int>::reverse_iterator rit = v.rbegin();while (rit != v.rend()){cout << *rit << " ";++rit;}cout << endl;}}

                                                                                                                test.cpp

#include <iostream>#include <assert.h>#include <vector>#include <list>#include <algorithm>using namespace std;#include "list.h"#include "vector.h"#include "reverse_iterator.h"int main()
{dwr::list_test();dwr::test_vector();dwr::list_test2();dwr::test_vector2();return 0;
}

以上仅代表个人观点,欢迎讨论

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

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

相关文章

Ps:图框工具

图框工具 Frame Tool是自 Ps 2019 版开始新增的一个工具。 图框 Frame可用于限制图像的显示范围&#xff0c;在设计过程中&#xff0c;还常常可起到占位符的功能。 快捷键&#xff1a;K 使用图框工具&#xff0c;对于快速相册排版、创建某种形式的特效等有一定的帮助。比起使用…

ctfshow 杂项签到

ctfshow的杂项签到题&#xff0c;下载压缩包之后里面有图片。 直接将图片用010editor打开&#xff0c;检索ctfshow可以看到答案。

Frequency-domain MLPs are More EffectiveLearners in Time Series Forecasting

本论文来自于 37th Conference on Neural Information Processing Systems (NeurIPS 2023) Abstract 时间序列预测在金融、交通、能源、医疗等不同行业中发挥着关键作用。虽然现有文献设计了许多基于 RNN、GNN 或 Transformer 的复杂架构&#xff08;注意力机制的计算太占用资…

.net6使用Sejil可视化日志

&#xff08;关注博主后&#xff0c;在“粉丝专栏”&#xff0c;可免费阅读此文&#xff09; 之前介绍了这篇.net 5使用LogDashboard_.net 5logdashboard rootpath-CSDN博客 这篇文章将会更加的简单&#xff0c;最终的效果都是可视化日志。 在程序非常庞大的时候&…

blender scripting 编写

blender scripting 编写 一、查看ui按钮对应的代码二、查看或修改对象名称三、案例&#xff1a;渲染多张图片并导出对应的相机参数 一、查看ui按钮对应的代码 二、查看或修改对象名称 三、案例&#xff1a;渲染多张图片并导出对应的相机参数 注&#xff1a;通过ui交互都设置好…

GEE数据集——USGS全球地震数据集

美国地质勘探局全球地震数据集 美国地质调查局地震灾害计划 (EHP) 提供全面的地震数据集&#xff0c;为全球监测、研究和地震防备提供宝贵资源。该数据集包含来自各种来源的地震信息&#xff0c;包括地震台、卫星图像和地面观测。持续更新&#xff0c;截至 2023 年 10 月 10 日…

跨境电商新纪元:无人驾驶技术如何颠覆物流未来

在全球化蓬勃发展的今天&#xff0c;跨境电商作为商业模式的一种新范式&#xff0c;正以前所未有的速度崛起。与此同时&#xff0c;无人驾驶技术作为物流领域的创新力量&#xff0c;正在为跨境电商带来翻天覆地的变革。本文将深入研究跨境电商新纪元下&#xff0c;无人驾驶技术…

Linux之文件目录

pwd 显示当前工作目录的绝对路径 ls显示目录中的内容 语法&#xff1a;ls [选项] 目录或文件常用选项&#xff1a; -a : 显示当前目录的所有文件和目录&#xff0c;包括隐藏的-l : 以列表的方式显示信息 cd切换目录 语法&#xff1a;cd [参数] &#xff08;切换到指定路径&…

Odoo16 实用功能之在Form视图控制字段的显示以及禁止编辑和禁止创建

目录 1、控制字段的显示 2、禁止编辑和禁止创建 1、控制字段的显示 在第一个字段没有选择的时候&#xff0c;让第二个字段不显示&#xff0c;选择之后第二个字段才显示&#xff0c;这个如何实现的&#xff1f; 以下是一个示例&#xff0c;假设disk_type是一个Selection字段&am…

数据通信网络基础华为ICT网络赛道

目录 前言&#xff1a; 1.网络与通信 2.网络类型与网络拓扑 3.网络工程与网络工程师 前言&#xff1a; 数据通信网络基础是通信领域的基本概念&#xff0c;涉及数据传输、路由交换、网络安全等方面的知识。华为ICT网络赛道则是华为公司提出的一种技术路径&#xff0c;旨在通…

python爬虫进阶篇:Scrapy中使用Selenium+Firefox浏览器爬取国债逆回购并发送QQ邮件通知

一、前言 每到年底国债逆回购的利息都会来一波高涨&#xff0c;利息会比银行的T0的理财产品的利息高&#xff0c;所以可以考虑写个脚本每天定时启动爬取逆回购数据&#xff0c;实时查看利息&#xff0c;然后在利息高位及时去下单。 二、环境搭建 详情请看《python爬虫进阶篇…

AI数字人克隆系统OEM:为未来创造更多可能

随着科技的发展&#xff0c;人工智能&#xff08;AI&#xff09;在各个领域取得了重要突破。其中&#xff0c;一个备受关注的领域是AI数字人克隆系统。作为一种创新的技术&#xff0c;它引发了人们的浓厚兴趣。本文将以探秘AI数字人克隆系统OEM源码为主题&#xff0c;深入了解这…

如何从0到1搭建一个SpringBoot项目

SpringBoot是大家使用最多的一个Java框架了&#xff0c;今日就来详细介绍一下如何去创建一个SpringBoot项目 一、准备工作 首先要来看你的IDEA版本&#xff0c;如果你的IDEA是【专业版】的&#xff0c;那么你就无需安装任何的插件&#xff0c;直接就可以创建SpringBoot的项目了…

【MIMO 从入门到精通】[P4]【MIMO Communications】

前言&#xff1a; Explains the main approaches to multi-input multi-output (MIMO) communications, including Beamforming, Zero Forcing, and MMSE. * Note that at the 9:19min mark, I made a slight "voice typo", where I should have said: "you nee…

世界首款配备M.2固态硬盘的树莓派Pi 5工业计算机发布!

多年来&#xff0c;上海晶珩一直秉承创新理念&#xff0c;持续不断地推陈出新。在成功推出一系列基于树莓派 Raspberry Pi CM4 的工业计算机后&#xff0c;现推出了全球首款搭载 M.2 固态硬盘的 Raspberry Pi 5 工业计算机ED-IPC3020系列。 ED-IPC3020搭载强大的Broadcom BCM27…

交换机vlan划分方法,学会这三招就够!

你们好&#xff0c;我的网工朋友。 交换机的配置我们说过很多&#xff0c;总有一些朋友会提到vlan的划分&#xff0c;今天就给你说下具体的应用。 关于vlan的划分方法有很多&#xff0c;项目应用中较多的方法就是基于端口划分vlan、基于mac地址划分vlan、基于ip地址划分vlan……

Redis相关的那些事(一)

背景 目前工作所负责的工作主要是投放业务&#xff0c;属于读高并发场景&#xff0c;记录一下之前碰到的redis相关的问题。 热点大值Key&缓存击穿问题 问题表现 在某次流量峰值过程中&#xff0c;redis的CPU突然飙升&#xff0c;从监控看起来就是CPU飙升到一定程度&…

如何使用Jellyfin结合内网穿透搭建私人影音平台远程可访问

作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家如何使用Jellyfin结合内网穿透搭建私人影音平台远程可访问&#xff0c;希望大家能觉得实用&#xff01; 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f496; 前言…

ARM 汇编语言知识积累

博文参考&#xff1a; arm中SP&#xff0c;LR&#xff0c;PC寄存器以及其它所有寄存器以及处理器运行模式介绍 arm平台根据栈进行backtrace的方法-腾讯云开发者社区-腾讯云 (tencent.com) 特殊功能寄存器&#xff1a; SP&#xff1a; 即 R13&#xff0c;栈指针&#xff0c;…

JuiceSSH结合内网穿透实现公网远程访问本地Linux虚拟机

文章目录 1. Linux安装cpolar2. 创建公网SSH连接地址3. JuiceSSH公网远程连接4. 固定连接SSH公网地址5. SSH固定地址连接测试 处于内网的虚拟机如何被外网访问呢?如何手机就能访问虚拟机呢? cpolarJuiceSSH 实现手机端远程连接Linux虚拟机(内网穿透,手机端连接Linux虚拟机) …