【C++】学习笔记——list

文章目录

  • 八、list
    • 1. list的介绍
    • 2. list的使用
    • 3. list的模拟实现
    • 4. list模拟实现的代码整合
      • 1. list.h
      • 2. test.cpp
  • 未完待续


八、list

list链接

1. list的介绍

在这里插入图片描述
是的, list 就是带头双向循环链表。

2. list的使用

通过 stringvector 的学习,我们差不多已经很了解容器的使用了,接下来要非常快速的过一遍了。

#include<iostream>
#include<list>
using namespace std;int main()
{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;for (auto e : lt){cout << e << " ";}cout << endl;return 0;
}

在这里插入图片描述
简简单单。
在这里插入图片描述
链表嘛,有头插、头删、尾插、尾删。也非常好使用,跟 push_back() 和 pop_back() 一样的用法。看到了 inserterase ,我们知道,vectorinserterase 可能会发生迭代器失效的问题,那 list 会出现吗?答案是不会发生,毕竟是链表嘛。
list 的大部分接口我们都了解了,我们就来看看一些之前没见过的东西。

在这里插入图片描述
首先我们来看看 reverse 。注意!是 reverse ,不是 reserve ,前者是逆置的意思,后者是保留,扩容的意思。sort 是排序的意思。
在这里插入图片描述
在这里插入图片描述

非常的简洁明了啊。

#include<iostream>
#include<list>
using namespace std;int main()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);for (auto e : lt){cout << e << " ";}cout << endl;lt.reverse();for (auto e : lt){cout << e << " ";}cout << endl;lt.sort();for (auto e : lt){cout << e << " ";}cout << endl;return 0;
}

在这里插入图片描述
sort 默认排的都是升序,若是想要排降序,需要用到 仿函数 ,这里先不过多介绍。listsort 效率比较低,当数据量大的时候,经量不要用 listsort 排序。

merge 是合并的意思,用的比较少。
在这里插入图片描述

unique 的作用是去重,去除重复元素,要求是必须先有序。
在这里插入图片描述

#include<iostream>
#include<list>
using namespace std;int main()
{list<int> lt;lt.push_back(2);lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(5);lt.push_back(1);lt.push_back(5);lt.push_back(4);lt.push_back(4);lt.push_back(4);lt.push_back(5);lt.push_back(1);lt.push_back(2);for (auto e : lt){cout << e << " ";}cout << endl;// 先排序lt.sort();for (auto e : lt){cout << e << " ";}cout << endl;// 再去重lt.unique();for (auto e : lt){cout << e << " ";}cout << endl;return 0;
}

在这里插入图片描述
remove 相当于 find + erase ,给你一个值,找到了就删,找不到就不删。

splice 这个接口很怪,它的作用是 转移
在这里插入图片描述
它可以将某一个链表,或者某个链表的某个值,或者某个链表的某一块区间转移到 position 位置 。也可以自己转移自己。

#include<iostream>
#include<list>
using namespace std;int main()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);for (auto e : lt){cout << e << " ";}cout << endl;// 将 lt 链表的 begin() 转移到 lt 链表的 end()lt.splice(lt.end(), lt, lt.begin());for (auto e : lt){cout << e << " ";}cout << endl;return 0;
}

在这里插入图片描述
确实将头部的 1 转移到 尾部的 5 后面了。转移的本质是改变节点的指向,并不是删除或创建节点

3. list的模拟实现

我们快速的搭一个 list 框架出来, 这个框架大致基于 STL库里的 list 。注意理解。

#pragma once#include<assert.h>namespace my
{// struct 成员默认全公开   节点结构体template<class T>struct ListNode{// 后继指针ListNode<T>* _next;// 前驱指针ListNode<T>* _prev;// 数据域T _data;// 构造函数ListNode(const T& x = T()):_next(nullptr),_prev(nullptr),_data(x){}};template<class T>class list{typedef ListNode<T> Node;public:// 默认构造list(){_head = new Node;_head->_next = _head;_head->_prev = _head;}private:// 指向头节点的指针Node* _head;};
}

写一个尾插操作:

// list类的 public域
void push_back(const T& x)
{// 实例化新节点Node* newnode = new Node(x);// 尾部节点Node* tail = _head->_prev;// 修改新节点的指向newnode->_next = _head;newnode->_prev = tail;// 修改指向新节点的指针tail->_next = newnode;_head->_prev = newnode;
}

有了尾插,我们就想去测试一下,但是测试需要访问,list 本身不支持 下标 + [] 访问,只能通过迭代器访问。我们之前说过 迭代器是一个行为像指针的东西,但不一定是指针 。那么 list 这里的迭代器可以使用原生指针吗,我们发现,链表本身是不连续的,我们 ++指针 无法访问到到下一个元素,解引用指针 也访问不到元素的数据。
因此,这里的迭代器并不能使用原生指针来代替。我们知道,可以通过重载一系列运算符来改变类的行为 ,就像日期类一样,++日期 可以得到下一天的日期,那么我们也可以将迭代器封装成一个类,然后通过重载运算符来改变其行为。

// my命名空间内
// 迭代器模板
template<class T>
struct ListIterator
{typedef ListNode<T> Node;// 指向节点的指针Node* _node;// 构造函数ListIterator(Node* node):_node(node){}
};

我们只写了迭代器类的构造函数,并没有写迭代器的拷贝构造函数。我们没写,编译器会自动生成,编译器生成的拷贝构造是浅拷贝,但恰巧我们要的就是浅拷贝(新的节点也指向某个节点)。析构函数需要写吗?也不需要,因为在这个迭代器类里,只有一个指针而已,节点的空间资源并不属于这个类,所以也不需要这个类来释放。

先来控制迭代器的行为:

// 前置++
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;
}

接着是迭代器的解引用:迭代器解引用我们要得到什么?得到节点的值,所以要返回数据

// 可读可写
T& operator*()
{return _node->_data;
}

判断相等:

bool operator!=(const Self& it)
{return _node != it._node;
}bool operator==(const Self& it)
{return _node == it._node;
}

现在我们要实现 beginend 。请问这两个函数在哪里实现?在迭代器类里面实现吗?不对,迭代器类根本不知道链表的组成,这俩函数只能在 list类 里面实现。

// list类里面
iterator begin()
{// 匿名对象return iterator(_head->_next);
}iterator end()
{// 匿名对象 _head是最后一个节点的下一个节点return iterator(_head);
}

完事儿,迭代器的行为也写完了,我们把当前的完整代码给出来:

#pragma once#include<assert.h>namespace my
{// struct 成员默认全公开   节点结构体template<class T>struct ListNode{// 后继指针ListNode<T>* _next;// 前驱指针ListNode<T>* _prev;// 数据域T _data;ListNode(const T& x = T()):_next(nullptr),_prev(nullptr),_data(x){}};// 迭代器模板template<class T>struct ListIterator{typedef ListNode<T> Node;// self : 自己typedef ListIterator<T> Self;// 指向节点的指针Node* _node;ListIterator(Node* node):_node(node){}// 没写拷贝构造,因为这是内置类型,默认生成的拷贝构造是浅拷贝,我们要的就是浅拷贝// 也不需要写析构函数,迭代器只有访问权限,资源不属于迭代器// 前置++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;}// 可读可写,引用返回T& operator*(){return _node->_data;}bool operator!=(const Self& it){return _node != it._node;}bool operator==(const Self& it){return _node == it._node;}};// 链表类template<class T>class list{typedef ListNode<T> Node;public:typedef ListIterator<T> iterator;iterator begin(){// 匿名对象return iterator(_head->_next);}iterator end(){// 匿名对象return iterator(_head);}// 默认构造list(){_head = new Node;_head->_next = _head;_head->_prev = _head;}void push_back(const T& x){// 实例化新节点Node* newnode = new Node(x);// 尾部节点Node* tail = _head->_prev;// 修改新节点的指向newnode->_next = _head;newnode->_prev = tail;// 修改指向新节点的指针tail->_next = newnode;_head->_prev = newnode;}private:// 指向头节点的指针Node* _head;};// 测试区
}

我们来测试一下:

// 测试区
void test01()
{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()){std::cout << *it << " ";++it;}std::cout << std::endl;
}
// test.cpp
#include<iostream>
#include"list.h"int main()
{my::test01();return 0;
}

在这里插入图片描述
成功运行,我们的最基础的 list 框架可算是搭建好了。
接下来是 insert 。在 pos 位置前插入 val
在这里插入图片描述

void insert(iterator pos, const T& val)
{// 目标节点Node* cur = pos._node;// 待插入的节点Node* newnode = new Node(val);// 目标节点的上一个节点Node* prev = cur->_prev;newnode->_prev = prev;newnode->_next = cur;prev->_next = newnode;cur->_prev = newnode;
}

还有 erase
在这里插入图片描述

iterator erase(iterator pos)
{Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;// 返回下一个节点的迭代器,避免迭代器失效return iterator(next);
}

有了 inserterase ,我们就可以把 push_back 给复用一下,然后我们再将其他插入删除给顺便完成了。

void push_back(const T& x)
{insert(end(), x);
}void push_front(const T& x)
{insert(begin(), x);
}void pop_back()
{// 必须是 -- ,不能是 - 1,因为迭代器不支持 - ,支持 --erase(--end());
}void pop_front()
{erase(begin());
}

来测试一下:

// 测试区
void test02()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_front(3);lt.push_front(4);lt.push_back(5);list<int>::iterator it = lt.begin();while (it != lt.end()){std::cout << *it << " ";++it;}std::cout << std::endl;lt.pop_back();lt.pop_front();for (auto e : lt){std::cout << e << " ";}std::cout << std::endl;
}
#include<iostream>
#include"list.h"int main()
{my::test02();return 0;
}

在这里插入图片描述
同样符合预期。
size :遍历一遍即可。

size_t size() const
{Node* begin = _head;size_t num = 0;while (begin->_next != _head){++num;begin = begin->_next;}return num;
}

list类 实现的差不多了,我们接着完善 迭代器类
我们新增一个自定义类型 A

struct A
{int _a1;int _a2;A(int a1 = 0, int a2 = 0):_a1(a1),_a2(a2){}
};
//测试区
void test03()
{list<A> lt;A aa1(1, 1);// 有名对象lt.push_back(aa1);// 匿名对象lt.push_back(A(2, 2));// 多参数的隐式类型转换 {}lt.push_back({ 3,3 });for (auto e : lt){std::cout << e << " ";}std::cout << std::endl;
}

我们会发现不能运行。
在这里插入图片描述
因为内置类型可以使用流插入,自定义类型没写重载流插入就用不了,所以该怎么遍历呢?由于这里的成员变量都是共有的,所以直接访问成员变量就可以了。

// 测试区
void test03()
{list<A> lt;A aa1(1, 1);// 有名对象lt.push_back(aa1);// 匿名对象lt.push_back(A(2, 2));// 多参数的隐式类型转换 {}lt.push_back({ 3,3 });list<A>::iterator it = lt.begin();while (it != lt.end()){std::cout << (*it)._a1 << (*it)._a2 << " ";++it;}std::cout << std::endl;
}
#include<iostream>
#include"list.h"int main()
{my::test03();return 0;
}

在这里插入图片描述
就可以遍历了。但是,既然可以 (*it)._a1 那就要可以 it->_a1 。所以我们还需要给迭代器类再重载一个运算符。

T* operator->()
{return &_node->_data;
}

有人会说,欸?这里怎么返回的是data的地址啊,那咋能访问到 _a1 啊?

void test04()
{list<A> lt;A aa1(1, 1);// 有名对象lt.push_back(aa1);// 匿名对象lt.push_back(A(2, 2));// 多参数的隐式类型转换 {}lt.push_back({ 3,3 });list<A>::iterator it = lt.begin();while (it != lt.end()){std::cout << it->_a1 << it->_a2 << " ";++it;}std::cout << std::endl;
}

在这里插入图片描述

但确实能跑了。其实是这里编译器做了相关的优化。咱们写的 it->_a1 编译器自动识别成 it->->_a1 ,也就是 it.operator->()->_a1 ,就是 &_data->_a1 。这下终于理解了,原理编译器帮我们省略了一个 ->
我们来实现一个 const迭代器 。最简单粗暴的方式就是 再定义一个const迭代器类 然后将其 解引用重载函数->重载函数 前面加上 const 就能够完成任务,但是如果就这两处不同的话,那普通迭代器和const迭代器代码相似度也太高了,有点冗余,该怎么合并呢?可以用类模板。

// Ref就是引用返回,Ptr就是指针返回
template<class T, class Ref, class Ptr>
struct ListIterator
{//
};// list类里
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&, const T*> const_iterator;

这就相当于:我们写了一个类模板,编译器帮我们实例化生成了普通迭代器类和const迭代器类

list 到这里基本差不多了,我们最后收尾一下。
list 的清理:

void clear()
{iterator it = begin();while (it != end()){it = erase(it);}
}~list()
{clear();delete _head;_head = nullptr;
}

判空:

bool empty()
{return size() == 0;
}

拷贝构造:

list(const list<T>& lt)
{// 初始的头结点_head = new Node;_head->_next = _head;_head->_prev = _head;for (auto& e : lt){push_back(e);}
}

复制重载:

void swap(list<T> lt)
{std::swap(_head, lt._head);
}list<T>& operator=(list<T> lt)
{swap(lt);return *this;
}

现在大部分接口都已经手到擒来了。

4. list模拟实现的代码整合

1. list.h

#pragma once#include<assert.h>namespace my
{// struct 成员默认全公开   节点结构体template<class T>struct ListNode{// 后继指针ListNode<T>* _next;// 前驱指针ListNode<T>* _prev;// 数据域T _data;ListNode(const T& x = T()):_next(nullptr),_prev(nullptr),_data(x){}};// 迭代器模板template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T> Node;// self : 自己typedef ListIterator<T, Ref, Ptr> Self;// 指向节点的指针Node* _node;ListIterator(Node* node):_node(node){}// 没写拷贝构造,因为这是内置类型,默认生成的拷贝构造是浅拷贝,我们要的就是浅拷贝// 也不需要写析构函数,迭代器只有访问权限,资源不属于迭代器// 前置++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;}// 可读可写//T& operator*()Ref operator*(){return _node->_data;}//T* operator->()Ptr operator->(){return &_node->_data;}bool operator!=(const Self& it){return _node != it._node;}bool operator==(const Self& it){return _node == it._node;}};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;iterator begin(){// 匿名对象return iterator(_head->_next);}iterator end(){// 匿名对象return iterator(_head);}// 迭代器指向的内容不能修改,const iterator不是我们要的const迭代器const_iterator begin() const{return iterator(_head->_next);}const_iterator end() const{return iterator(_head);}// 默认构造list(){_head = new Node;_head->_next = _head;_head->_prev = _head;}list(const list<T>& lt){// 初始的头结点_head = new Node;_head->_next = _head;_head->_prev = _head;for (auto& e : lt){push_back(e);}}void swap(list<T> lt){std::swap(_head, lt._head);}list<T>& operator=(list<T> lt){swap(lt);return *this;}bool empty(){return size() == 0;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}~list(){clear();delete _head;_head = nullptr;}//void push_back(const T& x)//{//	// 实例化新节点//	Node* newnode = new Node(x);//	// 尾部节点//	Node* tail = _head->_prev;//	// 修改新节点的指向//	newnode->_next = _head;//	newnode->_prev = tail;//	// 修改指向新节点的指针//	tail->_next = newnode;//	_head->_prev = newnode;//}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_back(){// 必须是 -- ,不能是 - 1,因为迭代器不支持 - ,支持 --erase(--end());}void pop_front(){erase(begin());}iterator insert(iterator pos, const T& val){// 目标节点Node* cur = pos._node;// 待插入的节点Node* newnode = new Node(val);// 目标节点的上一个节点Node* prev = cur->_prev;newnode->_prev = prev;newnode->_next = cur;prev->_next = newnode;cur->_prev = newnode;return iterator(newnode);}iterator erase(iterator pos){Node* cur = pos._node;Node* prev = cur->_prev; Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;// 返回下一个节点的迭代器,避免迭代器失效return iterator(next);}size_t size() const{Node* begin = _head;size_t num = 0;while (begin->_next != _head){++num;begin = begin->_next;}return num;}private:// 指向头节点的指针Node* _head;};struct A{int _a1;int _a2;A(int a1 = 0, int a2 = 0):_a1(a1),_a2(a2){}};void test01(){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()){std::cout << *it << " ";++it;}std::cout << std::endl;}void test02(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_front(3);lt.push_front(4);lt.push_back(5);list<int>::iterator it = lt.begin();while (it != lt.end()){std::cout << *it << " ";++it;}std::cout << std::endl;lt.pop_back();lt.pop_front();for (auto e : lt){std::cout << e << " ";}std::cout << std::endl;std::cout << lt.size();}void test03(){list<A> lt;A aa1(1, 1);// 有名对象lt.push_back(aa1);// 匿名对象lt.push_back(A(2, 2));// 多参数的隐式类型转换 {}lt.push_back({ 3,3 });list<A>::iterator it = lt.begin();while (it != lt.end()){std::cout << (*it)._a1 << (*it)._a2 << " ";++it;}std::cout << std::endl;}void test04(){list<A> lt;A aa1(1, 1);// 有名对象lt.push_back(aa1);// 匿名对象lt.push_back(A(2, 2));// 多参数的隐式类型转换 {}lt.push_back({ 3,3 });list<A>::iterator it = lt.begin();while (it != lt.end()){std::cout << it->_a1 << it->_a2 << " ";++it;}std::cout << std::endl;}
}

2. test.cpp

#include<iostream>
#include"list.h"int main()
{my::test03();return 0;
}

未完待续

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

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

相关文章

基于TL431和CSA的恒压与负压输出

Hello uu们,51去那里玩了呀?该收心回来上班了,嘿嘿! 为什么会有这个命题,因为我的手头只有这些东西如何去实现呢?让我们一起来看电路图吧.电路图如下图1所示 图1:CSA恒压输出电路 图1中,R1给U2提供偏置,Q1给R1提供电流,当U1-VOUT输出大于2.5V时候,U2内部的三极管CE导通,使得…

第四百九十二回

文章目录 1. 概念介绍2. 使用方法2.1 SegmentedButton2.2 ButtonSegment 3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"SearchBar组件"相关的内容&#xff0c;本章回中将介绍SegmentedButton组件.闲话休提&#xff0c;让我们一起Talk …

Qt扫盲-Qt D-Bus概述

Qt D-Bus概述 一、概述二、总线三、相关概念1. 消息2. 服务名称3. 对象的路径4. 接口5. 备忘单 四、调试五、使用Qt D-Bus 适配器1. 在 D-Bus 适配器中声明槽函数1. 异步槽2. 只输入槽3. 输入输出槽4. 自动回复5. 延迟回复 一、概述 D-Bus是一种进程间通信(IPC)和远程过程调用…

分布式与一致性协议之ZAB协议(四)

ZAB协议 ZooKeeper是如何选举领导者的。 首先我们来看看ZooKeeper是如何实现成员身份的&#xff1f; 在ZooKeeper中&#xff0c;成员状态是在QuorumPeer.java中实现的&#xff0c;为枚举型变量 public enum ServerState { LOOKING, FOLLOWING, LEADING, OBSERVING }其实&…

【JAVA入门】Day03 - 数组

【JAVA入门】Day03 - 数组 文章目录 【JAVA入门】Day03 - 数组一、数组的概念二、数组的定义2.1 数组的静态初始化2.2 数组的地址值2.3 数组元素的访问2.4 数组遍历2.5 数组的动态初始化2.6 数组的常见操作2.7 数组的内存分配2.7.1 Java内存分配2.7.2 数组的内存图 一、数组的概…

【数据结构】--- 深入剖析二叉树(中篇)--- 认识堆堆排序Topk

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; 数据结构之旅 文章目录 &#x1f3e0; 初识堆 &#x1f4d2; 堆的概念 &#x1f4d2; 堆的性质 &#x1f3e0; 向上调整算法 && 向下调整算…

【云原生】Pod 的生命周期(一)

【云原生】Pod 的生命周期&#xff08;一&#xff09;【云原生】Pod 的生命周期&#xff08;二&#xff09; Pod 的生命周期&#xff08;一&#xff09; 1.Pod 生命期2.Pod 阶段3.容器状态3.1 Waiting &#xff08;等待&#xff09;3.2 Running&#xff08;运行中&#xff09;3…

《Python编程从入门到实践》day20

#尝试在python3.11文件夹和pycharm中site-packages文件夹中安装&#xff0c;最终在scripts文件夹中新建py文件成功导入pygame运行程序 #今日知识点学习 import sysimport pygameclass AlienInvasion:"""管理游戏资源和行为的类"""def __init__(…

memory consistency

memory consistency model 定义了对于programmer和implementor来说&#xff0c;访问shared memory system的行为&#xff1b; 对于programmer而言&#xff0c;他知道期望值是什么&#xff0c; 知道会返回什么样的数据&#xff1b;&#xff1b; 对于implementro而言&#xff0c;…

微信小程序原生代码实现小鱼早晚安打卡小程序

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 小鱼早晚安打卡小程序&#xff1a;开启健康生活&#xff0c;共享正能量 在这个快节奏的时代&#xff0c;我们常常被各种琐事和压力所困扰&#xff0c;以至于忽略了对健康生活方式的追求。然…

【探秘地球宝藏】矿产资源知多少?

当我们仰望高楼林立的城市&#xff0c;乘坐便捷的交通工具&#xff0c;享受各种现代生活的便利时&#xff0c;你是否曾想过这一切背后的支撑力量&#xff1f;答案就藏在我们脚下——矿产资源&#xff0c;这些大自然赋予的宝贵财富&#xff0c;正是现代社会发展的基石。今天&…

OpenHarmony 实战开发——ABI

OpenHarmony系统支持丰富的设备形态&#xff0c;支持多种架构指令集&#xff0c;支持多种操作系统内核&#xff1b;为了应用在各种OpenHarmony设备上的兼容性&#xff0c;本文定义了"OHOS" ABI&#xff08;Application Binary Interface&#xff09;的基础标准&#…

idea中取消自动导包顺序

1、取消自动导入 2、取消导包顺序设置

Python学习笔记------处理数据和生成折线图

给定数据&#xff1a; jsonp_1629344292311_69436({"status":0,"msg":"success","data":[{"name":"美国","trend":{"updateDate":["2.22","2.23","2.24",&qu…

奶爸预备 |《P.E.T.父母效能训练:让亲子沟通如此高效而简单:21世纪版》 / 托马斯·戈登——读书笔记

目录 引出致中国读者译序前言第1章 父母总是被指责&#xff0c;而非受训练第2章 父母是人&#xff0c;不是神第3章 如何听&#xff0c;孩子才会说&#xff1a;接纳性语言第4章 让积极倾听发挥作用第5章 如何倾听不会说话的婴幼儿第6章 如何听&#xff0c;孩子才肯听第8章 通过改…

保研面试408复习 3——操作系统

文章目录 1、操作系统一、进程有哪几种状态&#xff0c;状态之间的转换、二、调度策略a.处理机调度分为三级&#xff1a;b.调度算法 标记文字记忆&#xff0c;加粗文字注意&#xff0c;普通文字理解。 为什么越写越少&#xff1f; 问就是在打瓦。(bushi) 1、操作系统 一、进程…

设计模式Java实现-建造者模式

楔子 小七在2019年的时候&#xff0c;就想写一个关于设计模式的专栏&#xff0c;但是最终却半途而废了。粗略一想&#xff0c;如果做完一件事要100分钟&#xff0c;小七用3分钟热情做的事&#xff0c;最少也能完成10件事情了。所以这一次&#xff0c;一定要把他做完&#xff0…

Windows常用快捷键与CMD常用命令

1.win系列快捷键使用 WinD&#xff0c;快速进入桌面 WinE&#xff0c;打开我的电脑&#xff08;文件资源管理器&#xff09; WinI&#xff0c;打开设置界面 WinL&#xff0c;快速锁屏 WinM&#xff0c;最小化所有窗口 WinShiftM&#xff0c;还原最小化的窗口 WinV&#…

为什么下载卡在idealTree:NodeJS: sill idealTree buildDeps

可能使用的是npm config set registry https://registry.npm.taobao.org而这个镜像文件已经过期了 解决方法如下&#xff1a; 先使用 npm cache clean --force 清除缓存 再切换镜像源 再使用npm config get registry 进行查看是否换源成功 再使用 npm install -g vue/cli 就…

【算法】滑动窗口——长度最小的子数组

本篇文章是用一个实例来介绍常用算法之一“滑动窗口”的相关概念&#xff0c;有需要借鉴即可。 目录 1.题目2.暴力求解2.1暴力求解思路&#xff1a;2.2时间复杂度是多少&#xff1f; 3.暴力求解的优化3.1固定left的情况下&#xff0c;优化right的次数。3.2sum求值优化3.3不同组…