list使用与模拟实现

目录

list使用

reverse

sort

unique

splice

list模拟实现

类与成员函数声明

节点类型的定义

非const正向迭代器的实现

list成员函数

构造函数

尾插

头插

头删

尾删

任意位置插入

任意位置删除

清空数据

析构函数

拷贝构造函数

赋值重载函数

const迭代器的设计

终极版正向迭代器的实现

终极版反向迭代器的实现

迭代器扩充小知识


list使用

list的诸多使用与前面博客讲解的string仍然类似,我们此处只讲解比较特殊的接口函数

list的底层是带头双向循环链表,在我的数据结构专栏博客 带头双向循环链表_CSDN博客 已经讲解过了,重点是体会带头双向循环链表与顺序表的不同,尤其是某个位置插入与删除数据的效率!

reverse

void test_list1()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);for (auto e : lt){cout << e << " "; //1 2 3 4 }cout << endl;lt.reverse(); //逆置链表for (auto e : lt){cout << e << " "; //4 3 2 1 }cout << endl;
}

sort

void test_list2()
{list<int> lt;lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(1);for (auto e : lt){cout << e << " "; //2 3 4 1 }cout << endl;//默认是升序 < less//lt.sort(); //降序: > greatergreater<int> gt;lt.sort(gt);lt.sort(greater<int>()); //匿名对象for (auto e : lt){cout << e << " "; //4 3 2 1}cout << endl;
}

注意: list的排序无法使用算法库中的sort,主要原因是list不支持随机访问的迭代器

迭代器类型按性质或者底层实现分为三种:

1.单向:只支持++, 单链表/哈希表
2.双向:++与--都支持,双向链表/红黑树(map和set)
3.随机:++/--/+/- vector/string/deque

注意: 2是兼容1的,3是兼容2的(本质是继承关系)

 unique

void test_list3()
{list<int> lt;lt.push_back(4);lt.push_back(1);lt.push_back(1);lt.push_back(2);lt.push_back(5);lt.push_back(5);lt.push_back(3);for (auto e : lt){cout << e << " "; //4 1 1 2 5 5 3}cout << endl;lt.sort();lt.unique(); //把相邻的重复去掉, 配合sort可以达到去重的功能for (auto e : lt){cout << e << " "; //1 2 3 4 5}cout << endl;
}

splice

void test_list5()
{list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);lt1.push_back(4);list<int> lt2;lt2.push_back(10);lt2.push_back(20);lt2.push_back(30);lt2.push_back(40);list<int>::iterator it = lt1.begin();++it;lt1.splice(it, lt2); //将lt2嫁接到lt1第2个位置之后, lt2就为空了!for (auto e : lt1){cout << e << " "; //1 10 20 30 40 2 3 4}cout << endl;for (auto e : lt2){cout << e << " "; //空}cout << endl;
}
void test_list5()
{list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);lt1.push_back(4);list<int> lt2;lt2.push_back(10);lt2.push_back(20);lt2.push_back(30);lt2.push_back(40);lt1.splice(lt1.begin(), lt2, lt2.begin()); //将lt2的第一个节点接到lt1开始for (auto e : lt1){cout << e << " "; //10 1 2 3 4 }cout << endl;for (auto e : lt2){cout << e << " "; //20 30 40}cout << endl;
}
void test_list5()
{list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);lt1.push_back(4);list<int> lt2;lt2.push_back(10);lt2.push_back(20);lt2.push_back(30);lt2.push_back(40);lt1.splice(lt1.begin(), lt2, lt2.begin(), lt2.end()); //将lt2的全部接到lt1开始for (auto e : lt1){cout << e << " "; //10 20 30 40 1 2 3 4}cout << endl;for (auto e : lt2){cout << e << " "; //空}cout << endl;
}

list模拟实现

关于带头双向链表的结构与实现可以直接看我之前的博客: 带头双向循环链表-CSDN博客

类与成员函数声明

namespace dck
{//每个节点的类型template <class T>struct list_node{T _data; //数据域list_node<T>* _next; //前驱指针list_node<T>* _prev; //后继指针list_node(const T& x = T()); //构造函数};//非const迭代器template <class T>struct __list_iterator //前加_表示内部的实现{typedef list_node<T> Node;Node* _node;//构造函数__list_iterator(Node* node);//迭代器++(前置++)typedef __list_iterator<T> self;self& operator++();//迭代器--(前置--)self& operator--();//迭代器++(后置++)self operator++(int);//迭代器--(后置--)self operator--(int);//迭代器解引用T& operator*();T* operator->();//两个迭代器进行比较bool operator!=(const self& s);bool operator ==(const self& s);};//list的类型template <class T>class list{typedef list_node<T> Node;public:void empty_init(); //空初始化list(); //构造函数void push_back(const T& x); //尾插void push_front(const T& x); //头插void pop_front(); //头删void pop_back(); //尾删iterator insert(iterator pos, const T& x); //任意位置插入iterator erase(iterator pos); //任意位置删除iterator begin(); //起始位置迭代器iterator end(); //结束位置迭代器void clear(); //清空数据~list(); //析构函数list(const list<T>& lt); //拷贝构造函数list<T>& operator=(const list<T>& lt); //赋值重载函数传统写法void swap(list<T>& lt); //交换两个list, 赋值重载函数现代写法要调用swap函数list<T>& operator=(list<T> lt); //赋值重载函数现代写法private:Node* _head;size_t size; //记录链表中节点的个数,降低时间复杂度};
}

节点类型的定义

//每个节点的类型
template <class T>
struct list_node
{T _data;list_node<T>* _next;list_node<T>* _prev;list_node(const T& x = T()) :_data(x),_next(nullptr),_prev(nullptr){}
};

非const正向迭代器的实现

之前讲解的string与vector的迭代器都是原生指针,而list的迭代器不是原生指针,主要原因是因为list的底层是双向链表,如果用原生指针++,是无法到下一个节点的;直接解引用拿到的也不是具体的数据,而是整个节点对象;而迭代器的访问与遍历方式都是类似的,都是++, 解引用,判断!=, 所以我们只需要把list的迭代器设计成类,在类中对原生指针做封装

//迭代器的实现 --- 封装屏蔽了底层差异和细节,提供了统一的访问遍历修改方式!
template <class T>
struct __list_iterator //前加_表示内部的实现
{typedef list_node<T> Node;Node* _node;//构造函数__list_iterator(Node* node):_node(node){}//迭代器++(前置++)typedef __list_iterator<T> self;self& operator++(){_node = _node->_next;return *this;}//迭代器--(前置--)self& operator--(){_node = _node->_prev;return *this;}//迭代器++(后置++)self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}//迭代器--(后置--)self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}//迭代器解引用T& operator*(){return _node->_data;}T* operator->(){return &_node->_data;}//两个迭代器进行比较bool operator!=(const self& s){return _node != s._node;}bool operator ==(const self& s){return _node == s._node;}
};

注意: 当list中存放的是自定义类型的对象时,使用->解引用时,写法如下:

class AA
{
public:AA(int aa1 = 1, int aa2 = 1):_a1(aa1),_a2(aa2){}int _a1;int _a2;
};void test_list()
{list<AA> lt1;lt1.push_back(AA(1, 2));lt1.push_back(AA(3, 4));lt1.push_back(AA(5, 6));list<AA>::iterator it = lt1.begin();while (it != lt1.end()){//显式应该这么写,因为operator->()拿到的是原生指针,还要再次->解引用拿到数据cout << it.operator->()->_a1 << " " << it.operator->()->_a2 << endl;//本来应该 it->->_a1, 但是可读性不好,因此编译器特殊处理, 省略了一个->cout << it->_a1 << " " << it->_a2 << endl;++it;}cout << endl;
}

list成员函数

构造函数
//空初始化, 后续代码可能会用到,因此单独写出来
void empty_init()
{_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;
}//构造函数
list()
{empty_init();
}
尾插
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;//_size++;//调用insert函数insert(end(), x); 
}
头插
//头插
void push_front(const T& x)
{insert(begin(), x);
}
头删
//头删
void pop_front()
{erase(begin());
}
尾删
//尾删
void pop_back()
{erase(--end());
}
任意位置插入
//insert
//在pos位置之前插入
//list的迭代器不存在失效的问题,因为不涉及扩容
//参考库的实现,还是给insert带上返回值
iterator insert(iterator pos, const T& x)
{Node* cur = pos._node; //当前节点指针Node* prev = cur->_prev; //前一个节点指针Node* newnode = new Node(x); //开辟新节点//链接prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;return iterator(newnode); //返回新插入节点位置的迭代器
}
 任意位置删除
//erase之后,迭代器pos失效,因为当前节点已经被释放了!
//因此我们给erase带上返回值
iterator erase(iterator pos)
{Node* cur = pos._node; //当前节点指针Node* prev = cur->_prev; //前一个节点指针Node* next = cur->_next; //后一个节点指针delete cur; //释放当前节点//链接前一个节点和后一个节点prev->_next = next; next->_prev = prev;--_size;return iterator(next); //返回释放节点的下一个位置
}

迭代器接口

iterator begin()
{//return iterator(_head->_next);return _head->_next;  //单参数的构造函数支持隐式类型转化
}iterator end()
{//return iterator(_head);return _head;  //单参数的构造函数支持隐式类型转化
}
清空数据
//清空数据(不清除带哨兵位的头节点)
void clear()
{iterator it = begin();while (it != end()){it = erase(it);}
}
析构函数
//析构函数
~list()
{clear();delete _head;_head = nullptr;
}
拷贝构造函数
//拷贝构造
list(list<T>& lt)
{empty_init();for (auto e : lt){push_back(e);}
}
赋值重载函数

传统写法

//赋值重载传统写法
list<T>& operator=(const list<T>& lt)
{if (this != &lt){clear(); for (auto e : lt){push_back(e);}}return *this;
}

现代写法

//赋值重载现代写法
void swap(list<T>& lt)
{std::swap(_head, lt._head);std::swap(_size, lt._size);
}list<T>& operator=(list<T> lt)
{swap(lt);return *this;
}

const迭代器的设计

上述代码实现了非const迭代器,本质就是封装了一个类,提供了对应的接口,而const迭代器本质就是迭代器指向的内容不可修改,因此不可以直接写const iterator,  这个const修饰的是迭代器本身不能被修改,那迭代器如何++访问数据呢?? 因此非const迭代器应该是一个独立的类

//非const迭代器
template <class T>
struct __list_const_iterator //前加_表示内部的实现
{typedef list_node<T> Node;Node* _node;//构造函数__list_const_iterator(Node* node):_node(node){}//迭代器++(前置++)typedef __list_const_iterator<T> self;self& operator++(){_node = _node->_next;return *this;}//迭代器--(前置--)self& operator--(){_node = _node->_prev;return *this;}//迭代器++(后置++)self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}//迭代器--(后置--)self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}//迭代器解引用const T& operator*() const{return _node->_data;}const T* operator->() const{return &_node->_data;}//两个迭代器进行比较bool operator!=(const self& s){return _node != s._node;}bool operator ==(const self& s){return _node == s._node;}
};

list类中提供const迭代器的begin和end接口即可:

//list的类型
template <class T>
class list
{typedef list_node<T> Node;
public://提供迭代器typedef __list_iterator<T> iterator;typedef __list_const_iterator<T> const_iterator;const_iterator begin() const{//return iterator(_head->_next);return _head->_next;  //单参数的构造函数支持隐式类型转化}const_iterator end() const{//return iterator(_head);return _head;  //单参数的构造函数支持隐式类型转化}
};

但是上面的写法太冗余了,非const迭代器和const迭代器都是封装了类,类中的实现大同小异,参考了STL库中的实现以后,其实只需要一个类+增加模板参数即可,  实现如下:

终极版正向迭代器的实现

//迭代器
template <class T, class Ref, class Ptr>
struct __list_iterator //前加_表示内部的实现
{typedef list_node<T> Node;Node* _node;typedef __list_iterator<T, Ref, Ptr> self;//构造函数__list_iterator(Node* node):_node(node){}//迭代器++(前置++)self& operator++(){_node = _node->_next;return *this;}//迭代器--(前置--)self& operator--(){_node = _node->_prev;return *this;}//迭代器++(后置++)self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}//迭代器--(后置--)self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}//迭代器解引用Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}//两个迭代器进行比较bool operator!=(const self& s){return _node != s._node;}bool operator ==(const self& s){return _node == s._node;}
};

终极版反向迭代器的实现

反向迭代器完全可以再设计一个类,在类内部把迭代器的操作都实现一遍,但是没有必要,因为我们已经有了正向迭代器,因此只需要用正向迭代器适配出反向迭代器即可, 关于容器的适配器在我的下一篇博客中有提及, 大家可以参考一下:stack 与 queue 与 priority_queue 与 仿函数 与 模板进阶-CSDN博客

反向迭代器的实现:

//用正向迭代器适配反向迭代器
template <class Iterator, class Ref, class Ptr>
class ReverseIterator
{
public:typedef ReverseIterator<Iterator, Ref, Ptr> Self;ReverseIterator(Iterator it):_it(it){}Self& operator++(){--_it;return *this;}Ref operator*(){return *_it;}Ptr operator->(){return _it.operator->();}bool operator!=(const Self& s){return _it != s._it;}private:Iterator _it;
};


list类:

template <class T>
//list的类型
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 ReverseIterator<iterator, T&, T*> reverse_iterator;typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;reverse_iterator rbegin(){return reverse_iterator(--end());}reverse_iterator rend(){return reverse_iterator(end());}const_reverse_iterator rbegin() const{return const_reverse_iterator(--end());}const_reverse_iterator rend() const{return const_reverse_iterator(end());}iterator begin(){//return iterator(_head->_next);return _head->_next;  //单参数的构造函数支持隐式类型转化}iterator end(){//return iterator(_head);return _head;  //单参数的构造函数支持隐式类型转化}const_iterator begin() const{//return iterator(_head->_next);return _head->_next;  //单参数的构造函数支持隐式类型转化}const_iterator end() const{//return iterator(_head);return _head;  //单参数的构造函数支持隐式类型转化}
};

值得一说的是库中反向迭代器的实现和我们不一样,不一样的地方在于库中反向迭代器的rbegin与rend位置和我们自己写的不一样,下图rbegin和rend的位置是库中的实现,是呈现对称结构的,而库中迭代器解引用访问的是前一个数据,也就是先让原生指针--, 然后解引用访问数据! 

下面是我们模拟库中rbegin与rend的位置实现的反向迭代器:

反向迭代器的实现:

//用正向迭代器适配反向迭代器
template <class Iterator, class Ref, class Ptr>
class ReverseIterator
{
public:typedef ReverseIterator<Iterator, Ref, Ptr> Self;ReverseIterator(Iterator it):_it(it){}Self& operator++(){--_it;return *this;}Self& operator--(){++_it;return *this;}Ref operator*(){Iterator cur = _it;return *(--cur);}Ptr operator->(){return &(operator*());}bool operator!=(const Self& s){return _it != s._it;}private:Iterator _it;
};

list类:

template <class T>
//list的类型
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 ReverseIterator<iterator, T&, T*> reverse_iterator;typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;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());}iterator begin(){//return iterator(_head->_next);return _head->_next;  //单参数的构造函数支持隐式类型转化}iterator end(){//return iterator(_head);return _head;  //单参数的构造函数支持隐式类型转化}const_iterator begin() const{//return iterator(_head->_next);return _head->_next;  //单参数的构造函数支持隐式类型转化}const_iterator end() const{//return iterator(_head);return _head;  //单参数的构造函数支持隐式类型转化}
};

迭代器扩充小知识

场景1:想实现一个打印函数,  无论list的节点是什么类型都能打印

template <class T>
void Print(const list<T>& lt)
{//list<T>为未实例化的类模板,编译器不能直接去他里面去找//编译器无法识别list<T>::const_iterator是内嵌类型还是静态成员变量//前面加一个typename就是告诉编译器,这里是一个类型,等list<T>实例化再去类里面去取typename list<T>::const_iterator it = lt.begin(); while (it != lt.end()){cout << *it << " ";it++;}cout << endl;
}void test_list5()
{list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);lt1.push_back(4);lt1.push_back(5);Print(lt1);//list不会存在浅拷贝的问题,因为不涉及扩容list<string> lt2;lt2.push_back("1111111111111111");lt2.push_back("1111111111111111");lt2.push_back("1111111111111111");lt2.push_back("1111111111111111");lt2.push_back("1111111111111111");Print(lt2);
}

场景2:想实现一个打印函数, 无论是哪个STL,都能使用同一个打印函数

//模板(泛型编程)本质: 本来应该由我们做的事情交给编译器去做了!
template <typename Container>
void print_container(const Container& con)
{typename Container::const_iterator it = con.begin();while (it != con.end()){cout << *it << " ";it++;}cout << endl;
}void test_list5()
{list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);lt1.push_back(4);lt1.push_back(5);print_container(lt1);//list不会存在浅拷贝的问题,因为不涉及扩容list<string> lt2;lt2.push_back("1111111111111111");lt2.push_back("1111111111111111");lt2.push_back("1111111111111111");lt2.push_back("1111111111111111");lt2.push_back("1111111111111111");print_container(lt2);vector<string> v;v.push_back("2222222222222222");v.push_back("2222222222222222");v.push_back("2222222222222222");v.push_back("2222222222222222");v.push_back("2222222222222222");print_container(v);
}

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

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

相关文章

【c++】初阶模版与STL简单介绍

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章介绍一下模版和对STL进行简单的介绍&#xff0c;后续我们进入对STL的学习&#xff01; 目录 模版1.泛型编程2.函数模板2.1函数模板的原理2.2模版的实例化…

159 Linux C++ 通讯架构实战14,epoll 函数代码实战

ngx_epoll_init函数的调用 //&#xff08;3.2&#xff09;ngx_epoll_init函数的调用&#xff08;要在子进程中执行&#xff09; //四章&#xff0c;四节 project1.cpp&#xff1a;nginx中创建worker子进程&#xff1b; //nginx中创建worker子进程 //官方nginx ,一个…

深入解析Python的lxml库:高效处理XML和HTML的利器

更多Python学习内容&#xff1a;ipengtao.com Python中的lxml库是一个强大的XML和HTML处理库&#xff0c;它基于libxml2和libxslt库&#xff0c;提供了高效的XML解析和处理功能。本文将详细介绍lxml库的安装、特性、基本功能、高级功能、实际应用场景和总结&#xff0c;帮助读者…

phpstorm设置头部注释和自定义注释内容

先说设置位置&#xff1a; PhpStorm中文件、类、函数等注释的设置在&#xff1a;setting-》Editor-》FIle and Code Template-》Includes-》PHP Function Doc Comment下设置即可&#xff0c;其中方法的默认是这样的&#xff1a; /** ${PARAM_DOC} #if (${TYPE_HINT} ! "…

Linux第4课 Linux的基本操作

文章目录 Linux第4课 Linux的基本操作一、图形界面介绍二、终端界面介绍 Linux第4课 Linux的基本操作 一、图形界面介绍 本节以Ubuntu系统的GUI为例进行说明&#xff0c;Linux其他版本可自行网搜。 图形系统进入后&#xff0c;左侧黄框内为菜单栏&#xff0c;右侧为桌面&…

[HackMyVM]靶场Birthday

难度:Hard kali:192.168.56.104 靶机:192.168.56.149 端口扫描 ┌──(root㉿kali2)-[~/Desktop] └─# nmap 192.168.56.149 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-06 10:39 CST Nmap scan report for 192.168.56.149 Host is up (0.00016s latency). N…

硬件-1、体系架构

cpu 处理器 arm处理器的七种工作模式 arm寄存器 两张图是一样的&#xff0c;r0---r12是通用寄存器。其他寄存器可参考图一&#xff0c;cpu架构。 程序状态寄存器psr&#xff08;cpsr/spsr&#xff09; 程序异常处理 理解示例 当使用swi&#xff08;软中断指令&#xff09;指令…

【VMware Workstation】启动虚拟机报错“此主机支持 AMD-V,但 AMD-V 处于禁用状态”

问题出现步骤&#xff1a; 打开虚拟机&#xff1a; 然后报错&#xff1a; “此主机支持 AMD-V&#xff0c;但 AMD-V 处于禁用状态。 如果已在 BIOS/固件设置中禁用 AMD-V&#xff0c;或主机自更改此设置后从未重新启动&#xff0c;则 AMD-V 可能被禁用。 (1) 确认 BIOS/固件设…

机器学习KNN最邻近分类算法

文章目录 1、KNN算法简介2、KNN算法实现2.1、调用scikit-learn库中KNN算法 3、使用scikit-learn库生成数据集3.1、自定义函数划分数据集3.2、使用scikit-learn库划分数据集 4、使用scikit-learn库对鸢尾花数据集进行分类5、什么是超参数5.1、实现寻找超参数5.2、使用scikit-lea…

Zabbix6 - Centos7部署Grafana可视化图形监控系统配置手册手册

Zabbix6 - Centos7部署Grafana可视化图形监控系统配置手册手册 概述&#xff1a; Grafana是一个开源的数据可视化和监控平台。其特点&#xff1a; 1&#xff09;丰富的可视化显示插件&#xff0c;包括热图、折线图、饼图&#xff0c;表格等&#xff1b; 2&#xff09;支持多数据…

【MySQL】增删改查操作(基础)

文章目录 1、新增操作&#xff08;Create&#xff09;1.1单行数据全列插入1.2多行数据指定列插入 2、查询操作&#xff08;Retrieve&#xff09;2.1全列查询2.2指定列查询2.3指定列查询2.4别名&#xff08;as&#xff09;2.5去重&#xff08;distinct&#xff09;2.6排序&#…

机器学习实战18-机器学习中XGBClassifier分类器模型的应用实战,以及XGBClassifier分类器的调优策略

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下机器学习实战18-机器学习中XGBClassifier分类器模型的应用实战&#xff0c;以及XGBClassifier分类器的调优策略。XGBClassifier是基于eXtreme Gradient Boosting (XGBoost)算法的分类器模型&#xff0c;在机器学习领…

[Semi-笔记]Switching Temporary Teachers for Semi-Supervised Semantic Segmentation

目录 概要创新一&#xff1a;Dual Temporary Teacher挑战&#xff1a;解决&#xff1a; 创新二&#xff1a;Implicit Consistency Learning&#xff08;隐式一致性学习&#xff09;挑战&#xff1a;解决&#xff1a; 实验结果小结论文地址代码地址 分享一篇2023年NeurIPS的文章…

python 利用xpath 爬取一周天气

需求&#xff1a; 爬取 中国天气网指定城市一周的天气&#xff0c;以天津为例 实现&#xff1a; 1&#xff0c;先找到一周的数据位置。 divs html.xpath("//div[classhanml]") 2&#xff0c;再遍历每天。 trs div.xpath("./div/div[2]/table//tr[position…

PC发送指令给单片机控制LED(与上一篇文章相反)

此时要重新配置寄存器 &#xff0c;实现电脑往单片机传输数据 1、配置SCON寄存器的REN 即 REN 1 2、有TI&#xff08;发送中断&#xff09;就有RI&#xff08;接收中断&#xff09; 3、优化 发现发送 o 时&#xff0c;D5亮灯会有延迟 下面就是做到真正的无延迟的全双工通信 …

深入理解计算机系统 家庭作业 2.85

A 7111.01.11*V E2,M1.11,f0.11 位表示: exp:10000...001其中0有k-2个.frac:1100...000其中0有n-2个 B 有个默认条件就是E>n, En,M1.111...(小数部分n个1),f0.1111(n个1),V exp:111...11其中1有n-1个.frac:111...111其中1有n个 C有个默认条件就是没有符号位.最小的规格…

JS详解-设计模式

工厂模式&#xff1a; 单例模式&#xff1a; // 1、定义一个类class SingleTon{// 2、添加私有静态属性static #instance// 3、添加静态方法static getInstance(){// 4、判断实例是否存在if(!this.#instance){// 5、实例不存在&#xff0c;创建实例this.#instance new Single…

Android 关于apk反编译d2j-dex2jar classes.dex失败的几种方法

目录 确认路径正确直接定位到指定目录确定目录正确&#xff0c;按如下路径修改下面是未找到相关文件正确操作 确认路径正确 &#xff0c;即d2j-dex2jar和classes.dex是否都在一个文件夹里&#xff08;大部分的情况都是路径不正确&#xff09; 直接定位到指定目录 路径正确的…

第12届蓝桥杯省赛 ---- C/C++ C组

文章目录 1. ASC2. 空间3. 卡片4. 相乘5. 路径6.时间显示7.最少砝码8. 杨辉三角形9. 左孩子右兄弟 第12届蓝桥杯省赛&#xff0c;C/C C组真题&#xff0c;第10题不是很清楚&#xff0c;题解不敢乱放&#x1f601;&#x1f601;&#x1f601; 1. ASC 额。。。。 #include <i…

Java NIO Selector选择器源码分析

文章目录 前言Selector类结构Selector抽象类AbstractSelectorSelectorImplWindowsSelectorImpl三种SelectionKey集合 前言 Java NIO&#xff08;New I/O&#xff09;的Selector选择器是一个用于多路复用&#xff08;Multiplexing&#xff09;的I/O操作的关键组件。它允许一个单…