list的模拟实现(万字解读+由浅入深)
先申明一下本篇总体介绍过程是按照逐步深入去写的,所以可能有些同样类型不在一块!
前言:
写这篇博客的时候,我是边思考边写它!自己其中感觉自己对于list的理解更加的深入,其中提出的很多问题让我明白了list为什么要这么设计,以及代码为啥要这么写!希望我的这篇博客不仅让我受益匪浅,也能对你有所帮助!若您发现了其中有什么地方有问题,希望评论区您能提出来。如果你有更好的理解思路,也希望您能不吝赐教!最后写博客不易,还望给一个赞!
💡💡追着光,跟着光,成为光,发散光!
目录
一、list 介绍
二、list 基本框架
2.1 结点
2.2 迭代器框架
2.3 链表类框架
三、模拟实现list
3.1 先提前写好的list函数
3.1.1 默认构造函数list() (构建哨兵结点)
💡💡3.1.2 返回(非const)迭代器的begin() end()
3.1.3 迭代器价值+类封装价值
3.2 挪动数据的函数
之前先说明如何查找位置?标准库的find()函数!
3.2.1 insert() 任意位置插入 (往指定位置的前面插入)
3.2.2 erase() 任意位置删除结点 ( 迭代器失效问题)
3.2.3 push_back() 尾插
3.2.4 pop_back() 尾删
3.2.5 push_front() 头插
3.2.5 pop_front() 头删
3.3 构造函数
3.3.1 迭代器区间构造
3.3.2 拷贝构造(现代写法)
💡💡引入const 迭代器(非常重要!)
3.3.4 赋值拷贝(现代写法)
3.4 释放空间函数
3.4.1 clear() 释放list非哨兵结点其余结点
3.4.2 ~list() 析构函数
四、模拟实现的list
一、list 介绍
1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
2. list的底层是带头双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
3. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
4. 与其他序列式容器相比,list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)
💡强调一下head是哨兵结点,本身不存储数据,作用只是指向头和尾!
二、list 基本框架
2.1 结点
//结点
template<class T>
struct list_node
{//结点构造函数list_node(const T& val = T()):prev(nullptr), next(nullptr), data(val){}
public:list_node* prev;//接前list_node* next;//接后T data;//存储数据
};
这里对于T()说明一下!这里是匿名构造,对于传来的参数类型不确定,可能是内置类型,也可能是类对象!所以不能想当然比如说默认赋值0!
2.2 迭代器框架
template<class T,class ref,class ptr>struct list_iterator{typedef list_node<T> node;typedef list_iterator<T, ref, ptr> Self;node* pnode;list_iterator(node* p):pnode(p){}ref operator*()ptr operator->()//前置Self& operator++()//后置Self operator++(int)//前置Self& operator--()//后置Self operator--(int)bool operator!=(const Self& it)bool operator==(const Self& it)};
2.3 链表类框架
class list{public:typedef list_node<T> node;typedef list_iterator<T,T&,T*> iterator;typedef list_iterator<T, const T&,const T*> const_iterator;iterator begin()const_iterator begin()constconst_iterator end()constiterator end()void clear()~list()void empty_initialize()list()template <class InputIterator>list(InputIterator first, InputIterator end)void swap(list<T>& lt)list(const list<T>& lt)list<T>& operator=(list<T> tmp)void push_back(const T& x)void push_front(const T& x)void pop_front()void pop_back()void insert(iterator pos,const T& x)iterator erase(iterator pos)private:node* head;//底层是一个哨兵结点};
这里问一个问题,等你看完这篇文章理解很多的时候,回来比较这三个类的是否手动析构,手动写拷贝构造!深入自己想想为啥是上面的结果!
三、模拟实现list
3.1 先提前写好的list函数
这些函数是后面写的基础!后面会频繁调用,所以先写出来!
3.1.1 默认构造函数list() (构建哨兵结点)
💡强调一下head是哨兵结点,本身不存储数据,作用只是指向头和尾!
后面要多次用到这个empty_initialize()内代码 ,所以就用函数了!
void empty_initialize()
{head = new node;//用new对象,可以直接调用对象的构造函数head->next = head;head->prev = head;
}
list()
{empty_initialize();
}
💡💡3.1.2 返回(非const)迭代器的begin() end()
首先我们需要将封装的迭代器需要实现的功能函数写好!
❓❓首先我们要问自己一个问题,链表的迭代器能不能像vector string 那样直接单纯地用解引用和++?
我们不妨回顾一下vector string 的迭代器,其底层是指针数组的原生指针!而它们容器的存储空间是连续的,解引用可以直接拿到数组数据,++可以直接加上类型的步长!
而list的呢?list是不连续的!它们通过前后指针链接!直接++不能找到后一个结点!解引用不是直接拿到存储数据,而是一个结点结构体!我们需要的是里面的Data!
怎么办? 系统的* ++ 不能满足我们需要的结果!
💡必须重载运算符!所以我们得将迭代器封装成一个类!
现在再问自己一个问题! 他的类成员变量是谁? 联系一下我们的目的和链表容器结构!
我们想到一个指向node 的指针就可以解决了,++不就是next,--不就是prev *不就是data!
!这里单独将->符号拿出来说明一下! 想用->访问数据,->左边是什么? 是结构体地址!
也就是说如果我们list 存储的数据是结构体或者类!里面有多个变量,那么我们访问数据就不能单纯的解引用!必须使用->来访问数据!
下面上代码~
template<class T>
struct list_iterator
{typedef list_node<T> node;//结点类typedef list_iterator<T> Self;//迭代器类node* pnode;//成员变量//构造函数 list_iterator(node* p):pnode(p){}T& operator*(){return pnode->data;}T* operator->(){return &pnode->data;//返回结构体地址}Self& operator++(){pnode = pnode->next;return *this;}Self& operator--(){pnode = pnode->prev;return *this;}bool operator!=(const Self& it){return pnode != it.pnode;}
};
现在迭代器功能基本完善!我们通过链表函数构建迭代器!
//再强调一下,迭代器被封装成类!!!
typedef list_iterator<T> iterator;iterator begin()
{//匿名对象返回!这里调用了迭代器的构造函数return iterator(head->next);
}iterator end()
{//这里千万记住,返回的是哨兵结点!不是尾结点!return iterator(head);
}
现在看看如何使用迭代器!
3.1.3 迭代器价值+类封装价值
迭代器是一种可以遍历数组的抽象接口!
1.封装底层实现,不暴露底层实现原理
2.有了迭代器,可以不关心底层实现原理,而是注重使用!
我们上面用的*符号,看似简单几个字母,可底层却是返回Data!我们不需要知道它返回的具体是什么,我们只要知道*符号代表着就是获取容器数据的方式!
类封装价值是什么?
1.因为不同容器实现原理不同,vector,list同样是*符号,对于vector,*号是原生指针!解引用可以直接获取数据,但是对于list,解引用实现不了我们直接获取数据的方法!(前面说过)有了类封装,我们就可以重载*号,让它的意义改变!有了封装,让我们使得同样的符号,对于不同实现原理的容器,可以有同样的效果!
2.我们可以注意到,即使是封装了迭代器,它的物理消耗内存仍只有一个指针大小!也就是说即使是类,他没有过多消耗内存!
3.2 挪动数据的函数
有了迭代器,它的成员变量是指向结点的指针,所以我们可以用迭代器获取结点位置!
之前先说明如何查找位置?标准库的find()函数!
参数为迭代器头尾和要查找的数据!
3.2.1 insert() 任意位置插入 (往指定位置的前面插入)
void insert(iterator pos, const T& x)
{node* newnode = new node(x);//构造新结点node* cur = pos.pnode;//记录当前结点node* prev = cur->prev;prev->next = newnode;newnode->prev = prev;cur->prev = newnode;newnode->next = cur;
}
3.2.2 erase() 任意位置删除结点 ( 迭代器失效问题)
iterator erase(iterator pos)
{node* cur = pos.pnode;node* prev = cur->prev;node* next = cur->next;prev->next = next;next->prev = prev;delete[]cur;//delete会调用结点类的默认析构函数//!!!返回下一个位置的迭代器return iterator(next);
}
为什么会有迭代器失效问题? 因为结点空间被释放了,这样迭代器++也就不能找到下一个位置结点,所以返回需要返回下一个结点迭代器!
3.2.3 push_back() 尾插
void push_back(const T& x)
{insert(end(), x);
}
3.2.4 pop_back() 尾删
这里提一嘴,注意前后两者区别,前面不--end() 因为插入是插在结点前一个!end()返回哨兵结点,插在它的前一个就是尾结点!
这里尾删,删的是尾结点,所以--迭代器重载返回前一个结点,也就是尾结点!
void pop_back()
{erase(--end());
}
3.2.5 push_front() 头插
void push_front(const T& x)
{insert(begin(), x);
}
3.2.5 pop_front() 头删
void pop_front()
{erase(begin());
}
3.3 构造函数
3.3.1 迭代器区间构造
template <class InputIterator>
list(InputIterator first, InputIterator end)
{empty_initialize();//构建哨兵结点while (first != end){push_back(*first);++first;}
}
3.3.2 拷贝构造(现代写法)
1.先构造临时链表tmp(深拷贝!)->> 2. 临时链表与拷贝构造链表交换!
那么如何交换两个链表? 很简单就是交换两个链表的哨兵结点!
//list<T> lt2(lt1)
void swap(list<T>& lt)
{std::swap(head, lt.head);//交换地址
}
list(const list<T>& lt)
{empty_initialize();//注意我们必须初始化lt2的哨兵结点!这样tmp析构的时候析构的不是野指针!list<T> tmp(lt.begin(), lt.end());swap(tmp);
}
💡💡引入const 迭代器(非常重要!)
首先说明一下,为什么从这里引入const 迭代器,因为注意一下这个拷贝构造的传参,是const list<T> &,我们在用迭代器构造tmp的时候,传的 lt 是const的!
所以我们要实现const 迭代器!
首先我们得明确一下const迭代器const的作用,这个const保护的是Data!也就是说数据只可读,不可写!迭代器解引用不能算数运算!迭代器本身可以++!
如何实现const迭代器?
先思考一下下面这个写法能不能实现我们要的const迭代器
现在看看这样的 rit 能干什么:
我们看到它不能++,它可以解引用算数运算!它是const迭代器吗?当然不是!通过结果我们不难可以类比原来的内置类型 这样写法相当于 int const * 而我们需要的是 const int* !
所以我们仍需要自己写一个const迭代器!
我们在明确一下const 迭代器与非const 迭代器的主要区别就在* 后是可读可写,还是只可读!也就是返回值一个是const T,一个是T!
💡💡那这就很简单了,那不就是我们在原来普通迭代器基础上重载一个*号运算符重载函数,如下:
template<class T> struct list_iterator {typedef list_node<T> node;//结点类typedef list_iterator<T> Self;//迭代器类..../之前上面写的普通迭代器函数const T& operator*()const{return pnode->data;} };
可是这样真的行吗?这样解决了当前的问题,可是我const迭代器想要调用普通迭代器其他接口函数怎么办?有人又会说了那每一个都重载一下呗!每一个函数都弄一个const!
比如 之前的++,写成如下:
那么请问,如果这样写了会有什么后果!我们来看看!
因为const 修饰了this指针,所以我们不能改变this指向的类对象成员函数 !
可是我们const迭代器只需要对* 做修改!所以这种只在原迭代器补const重载函数,行不通!
那么引入第三种想法(一般人),我们可以重新写一个const迭代器类封装它,类中与原来普通迭代器不同的就是*号 重载函数!
//在list类中定义const迭代器 typedef const_list_iterator<T> const_iterator;//const迭代器类 template<class T> struct const_list_iterator {typedef list_node<T> node;//结点类typedef const_list_iterator<T> Self;//迭代器类node* pnode;//成员变量//构造函数 list_iterator(node* p):pnode(p){}//唯一区别地方const T& operator*(){return pnode->data;}T* operator->(){return &pnode->data;//返回结构体地址}Self& operator++(){pnode = pnode->next;return *this;}Self& operator--(){pnode = pnode->prev;return *this;}bool operator!=(const Self& it){return pnode != it.pnode;} };
现在我们看看C++设计者大佬的写法!它们的写法就是一行代码能解决的事绝不用多行!
之前我们先引入一个问题,模板类 类型的问题!
请问list 是类型吗?它不是!它是类明!
什么是类型? 诸如list<int>的list<T>它们是类型! 区别模板类类型的关键在于T!现在再想一想const迭代器不同于普通迭代器什么?不就是重载的*号不同!那么我们是否可以多一个模板参数,区别这两个不同的类!
list_iterator<T,T> list_iterator<T,const T>这两个不是同一个迭代器!!!
现在看看大佬写法!
三个模板参数!! 两者区别在于第二个一个是T,一个是const T!
//这里的T*是->返回时的参数 typedef list_iterator<T,T&,T*> iterator; typedef list_iterator<T, const T&,const T*> const_iterator;const_iterator begin()const {return const_iterator(head->next); } const_iterator end()const {return const_iterator(head); }template<class T, class ref, class ptr> struct list_iterator {typedef list_node<T> node;typedef list_iterator<T, ref, ptr> Self;node* pnode;list_iterator(node* p):pnode(p){}ref& operator*(){return pnode->data;}ptr operator->(){return &pnode->data;}Self& operator++(){pnode = pnode->next;return *this;}Self& operator--(){pnode = pnode->prev;return *this;}bool operator!=(const Self& it){return pnode != it.pnode;} };
3.3.4 赋值拷贝(现代写法)
1.构造tmp--> 2.交换--> 3.出作用域,临时变量调用析构函数,释放this原空间
//连等可能,所以返回链表!
//出作用域,被替换的tmp会调用它的析构函数,析构this的原空间list<T>& operator=(list<T> tmp)
{swap(tmp);return *this;
}
3.4 释放空间函数
3.4.1 clear() 释放list非哨兵结点其余结点
void clear()
{iterator first = begin();while (first != end()){first = erase(first);//!!!注意考虑迭代器失效}
}
3.4.2 ~list() 析构函数
~list()
{clear();delete head;head = nullptr;
}
这里再引入一个问题!为什么之前的迭代器类,结点类我们没有写析构函数?现在需要写呢?
因为这两个类的成员变量都是内置类型,默认构造会自动释放成员变量。它们的任务都是单个结点!
如果list我们这里不写,默认析构函数只会将我们的头结点释放,那些剩余结点并没有被释放,也就是说list析构任务不仅仅是单个结点,而是所有结点!所以这里我们必须手动写!
四、模拟实现的list
namespace wyz
{template<class T>struct list_node{list_node(const T& val = T()):prev(nullptr), next(nullptr), data(val){}public:list_node* prev;list_node* next;T data;};template<class T, class ref, class ptr>template<class T, class ref, class ptr>
struct list_iterator
{typedef list_node<T> node;typedef list_iterator<T, ref, ptr> Self;node* pnode;list_iterator(node* p):pnode(p){}ref operator*(){return pnode->data;}ptr operator->(){return &pnode->data;}//前置Self& operator++(){pnode = pnode->next;return *this;}//后置Self operator++(int){Self tmp(pnode);pnode = pnode->next;return tmp;}//前置Self& operator--(){pnode = pnode->prev;return *this;}//后置Self operator--(int){Self tmp(pnode);pnode = pnode->prev;return tmp;}bool operator!=(const Self& it){return pnode != it.pnode;}bool operator==(const Self& it){return pnode == it.pnode;}
};template<class T>class list{public:typedef list_node<T> node;typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;iterator begin(){//匿名对象返回!return iterator(head->next);}const_iterator begin()const{return const_iterator(head->next);}const_iterator end()const{return const_iterator(head);}iterator end(){return iterator(head);}void clear(){iterator first = begin();while (first != end()){first = erase(first);//!!!}}~list(){clear();delete head;head = nullptr;}void empty_initialize(){head = new node;head->next = head;head->prev = head;}list(){empty_initialize();}template <class InputIterator>list(InputIterator first, InputIterator end){empty_initialize();while (first != end){push_back(*first);++first;}}void swap(list<T>& lt){std::swap(head, lt.head);}list(const list<T>& lt){empty_initialize();list<T> tmp(lt.begin(), lt.end());swap(tmp);}list<T>& operator=(list<T> tmp){swap(tmp);return *this;}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());}void insert(iterator pos, const T& x){node* newnode = new node(x);node* cur = pos.pnode;node* prev = cur->prev;prev->next = newnode;newnode->prev = prev;cur->prev = newnode;newnode->next = cur;}iterator erase(iterator pos){node* cur = pos.pnode;node* prev = cur->prev;node* next = cur->next;prev->next = next;next->prev = prev;delete[]cur;return iterator(next);}private:node* head;//底层是一个哨兵结点};
相关文章:
list的模拟实现(万字解读+由浅入深)
先申明一下本篇总体介绍过程是按照逐步深入去写的,所以可能有些同样类型不在一块! 前言: 写这篇博客的时候,我是边思考边写它!自己其中感觉自己对于list的理解更加的深入,其中提出的很多问题让我明白了lis…...
Java项目:SSM CRM人事管理系统
作者主页:源码空间站2022 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 CRM人事管理系统,主要功能有: 用户管理:用户查询、添加用户、编辑、删除; 职位管理:…...
Qt+opencv 鼠标画线实现几何图形识别并动态创建
前言 使用Qt OpenCV实现,通过鼠标画线绘制几何图形,然后通过opencv进行图形轮廓识别,返回图形顶点,然后创建对应的几何图形添加到场景中。绘制使用QGraphics体系完成。 看效果图: 本文demo在这里 点击下载 环境: …...
HTML5期末大作业——HTML+CSS+JavaScript平遥古城旅游景点介绍(6页)
👨🎓学生HTML静态网页基础水平制作👩🎓,页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码,这是一个不错的旅游网页制作,画面精明,排版整洁,内容…...
HTML5期末考核大作业 基于HTML+CSS+JavaScript沪上美食(9页)
🎀 精彩专栏推荐👇🏻👇🏻👇🏻 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业…...
Reg注册表读写
在Windows 95及其后继版本中,采用了一种叫做“注册表”的数据库来统一进行管理,将各种信息资源集中起来并存储各种配置信息。按照这一原则,Windows各版本中都采用了将应用程序和计算机系统全部配置信息容纳在一起的注册表,用来管理…...
HTML入门零基础教程(五)
嗨,大家好,我是异星球的小怪同志 一个想法有点乱七八糟的小怪 如果觉得对你有帮助,请支持一波。 希望未来可以一起学习交流。 目录 一、图像标签 1.图像标签 2.图标标签的其它属性 3.图像标签属性注意点: 一、图像标签 1.…...
java通过lock实现同步锁
这里我们是一个卖票的演示代码 其实 同步锁 远不止一个synchronized 它本身有一个 加上锁 和释放锁的过程 为了 让我们更好的理解这个过程 JDK5之后 为我们提供了一个单独的锁工具 lock lock是一个接口 他提供了 synchronized 方法 和 更广泛的语句操作 lock方法 获得锁 unl…...
Java多线程同步工具类:Semaphore原理剖析
Java多线程同步工具类:Semaphore原理剖析 文章目录Java多线程同步工具类:Semaphore原理剖析Semaphore原理实战案例前驱知识准备:AbstractQueuedSynchronizer队列同步器 [Java多线程之:队列同步器AbstractQueuedSynchronizer原理剖…...
C++之面向对象
目录 对象与类 类的语法: C中class与struct的区别: 通过类实例化对象的方式 具体案例 类作用域与分文件编写 创建circle.h头文件 创建源文件circle.cpp 创建all.cpp来作为程序的入口 封装 封装的意义 访问权限符 成员属性私有化 优点 具体…...
Windows-》CMD命令
CMD命令【1】Windows-》CMD命令1.mstsc:打开远程桌面连接。2.services.msc:打开本地服务设置。3.notepad:打开记事本。4.control:打开控制面板。5.regedit:打开注册列表编辑器。6.compmgmt.msc---设备管理器。…...
秒级使网站变灰,不改代码不上线,如何做到?
注意:文本不是讲如何将网站置灰的那个技术点,那个技术点之前汶川地震的时候说过。 本文不讲如何实现技术,而是讲如何在第一时间知道消息后,更快速的实现这个置灰需求的上线。 实现需求不是乐趣,指挥别人去实现需求才…...
vue教程
vue window本地保存Local Storage 保存:window.localStorage.setItem(名,值); window.localStorage.setItem(token,backdata.data[2]); 查询:window.localStorage.getItem(名); window.localStorage.getItem(token); 删除:window.localStor…...
认识哈希表
作者:~小明学编程 文章专栏:Java数据结构 格言:目之所及皆为回忆,心之所想皆为过往 目录 为什么我们需要哈希表? 哈希表的原理 什么是哈希值 冲突 负载因子 解决冲突 闭散列 开散列/哈希桶 代码实现 不考虑…...
Vue学习:Hello小案例
使用Vue的目的:构建用户界面(需要使用容器 摆放这个界面的内容) favicon.ico:1 GET http://127.0.0.1:5500/favicon.ico 404 (Not Found) 没有页签图标 在者服务器中 http://127.0.0.1:5500没有/favicon.ico 强制刷新网页:s…...
IDEA创建Java Web项目
✅作者简介:热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏:JAVA开发者…...
C++11中可变参数模板使用
在看同事编写的代码,发现有如下的代码,因为没用过,所以查了一下这是什么语法,通过查询资料知道了这是C11中增加的可变参数模板。 template<class T, class ...Args> bool GetValue(T &value, Args &&...args) c…...
MySQL 中的 sql_mode 选项以及配置
MySQL 中的 sql_mode 选项以及配置 目录MySQL 中的 sql_mode 选项以及配置一、查询与设置 sql_mode1、查询 sql_mode2、设置 sql_mode(1)通过命令设置(2)在配置文件中设置二、sql_mode 支持的模式1、ANSI 模式(宽松模式…...
【C语言航路】第六站:指针初阶
目录 一、指针是什么 二、指针和指针类型 1.指针类型的意义 2.指针-整数 3.指针解引用 三、野指针 1.野指针的成因 (1)指针未初始化 (2)指针越界访问 (3)指针指向的空间释放 2.如何规避野指针 &a…...
从 JPA 2.x 迁移到 3.0
我最近收到了很多关于JPA 3.0的问题,由于EclipseLink和Hibernate现在提供了对它的全面支持,现在是时候仔细看看规范的最新更新了。作为从Java EE到Jakarta EE转换的一部分,Java Persistence API(JPA)更名为Jakarta Per…...
Allegro如何锁定器件操作指导
Allegro如何锁定器件操作指导 Allegro上可以锁定器件,避免误操作被移动,具体操作如下 选择fix命令 Find选择Symbols 框选需要锁定的器件 可以看到器件被锁住了 除了这个方法之外,还有另外一种方法锁定器件,选择edit-property Find选择Symbols...
第三章:SpringBoot的配置文件-核心技术
目录 1、文件类型 1.1、properties 1.2、yaml 1.2.1、简介 1.2.2、基本语法 1.2.3、数据类型 1.2.4、示例 2、配置提示 1、文件类型 1.1、properties 同以前的properties用法 1.2、yaml 1.2.1、简介 YAML 是 "YAML Aint Markup Language"(YA…...
Vue中的计算属性
计算属性:实际上是把vm中的属性进行计算加工,最后能够返回给页面一个结果,它是实时的,所以不能做异步操作。 细想一下,其实methods方法也能实现1中描述的现象,但是计算属性最大的优势是缓存!&a…...
HTML+CSS个人电影网页设计——电影从你的全世界路过(4页)带音乐特效
HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置,有div的样式格局,这个实例比较全面,有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 文章目录一、网页介绍一…...
业务开发时,接口不能对外暴露的解决方案
1.内外网接口微服务隔离 将对外暴露的接口和对内暴露的接口分别放到两个微服务上,一个服务里所有的接口均对外暴露,另一个服务的接口只能内网服务间调用。 该方案需要额外编写一个只对内部暴露接口的微服务,将所有只能对内暴露的业务接口聚合到这个微服务里,通过这个聚合…...
「点燃我,温暖你」用Python制作一个动态爱心效果
最近「点燃我,温暖你」这部剧非常火,讲述的是程序员的爱情故事。 其中陈飞宇饰演的男主李峋,在剧中用程序做出的爱心跳动效果,非常炫。 网上各个大佬也是纷纷给出看法,综合就是不太可能用C语言来实现的。 大概率是AE…...
初识猿如意开发工具
嗨,大家好,我是异星球的小怪同志 一个想法有点乱七八糟的小怪 如果觉得对你有帮助,请支持一波。 希望未来可以一起学习交流。 一、初遇猿如意 第一次听说猿如意开发工具,于是抱着试试的心态,开始下载尝试。 首先是…...
PyTorch 2.0发布了,一行代码提速76%
PyTorch 官方:我们这次的新特性太好用了,所以就直接叫 2.0 了。 前段时间,PyTorch 团队在官方博客宣布 Pytorch 1.13 发布,包含 BetterTransformer 稳定版等多项更新。在体验新特性的同时,不少人也在期待下一个版本的推…...
栈的基本操作
一,自定义函数 #include<bits/stdc.h> using namespace std; const int N 1000;//N是常量 int s[N 1];//栈 int top;//栈顶的位置(栈内有多少个元素) //入栈 void push(int x){ //非满栈 if(top < N){ //将栈顶上移并存入 top…...
windows内核编程-文件操作
文章目录前言背景知识点介绍字符串内存分配与回收文件操作自旋锁win内核编程-日志实现文件操作的封装日志功能的实现简单的测试日志功能其他前言 本文完整代码见:demo/12-win-driver-log 我们必须先搞定,DebugView可以看到DbgPrintDbgPrint的输出。否则…...
Hadoop原理与技术——Linus命令行基本操作
点击链接查看文档 一、实验目的 Hadoop运行在Linux系统上,因此,需要学习实践一些常用的Linux命令。本实验旨在熟悉常用的Linux操作,为顺利开展后续其他实验奠定基础。 二、实验环境 Windows 10 VMware Workstation Pro虚拟机 Hadoop环境 J…...
目标检测算法——YOLOv5/YOLOv7改进之结合特征提取网络RFBNet(涨点明显)
>>>深度学习Tricks,第一时间送达<<< 🚀🚀🚀NEW!!!魔改YOLOv5/v7目标检测算法来啦 ~ 计算机视觉——致力于目标检测领域科研Tricks改进与推荐 | 主要包括Backbone、Neck、Head、普通注意力机制、自注意力机制Transformer、Swin Transformer v2,各…...
anaconda使用系列教程--4)环境迁移
概述 跨平台尽量避免,比如windows和linux就不要跨平台,就在linux之间跨还是可以的 直接copy整体环境文件,适合于无法联网或网速不佳的新环境 anaconda最好是同版本的 迁移方法 使用requirement文件 A机器: pip freeze > …...
Kotlin高仿微信-第57篇-VIP管理列表
Kotlin高仿微信-项目实践58篇详细讲解了各个功能点,包括:注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。 Kotlin高仿…...
贪心算法-- 纪念品分组
问题描述元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得的纪念品价值 相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品,并且每组纪念品的价格之和不能超过一个给…...
java-php-net-python-代驾网站计算机毕业设计程序
java-php-net-python-代驾网站计算机毕业设计程序 java-php-net-python-代驾网站计算机毕业设计程序本源码技术栈: 项目架构:B/S架构 开发语言:Java语言 开发软件:idea eclipse 前端技术:Layui、HTML、CSS、JS、JQ…...
简洁自增ID实现方案
简介 从数据库性能角度考虑,我们经常需要数字型的自增主键,有时候我们并不想用像MySQL自带的自增,因为从1开始很数据位数不一样,对有点强迫症的人来说,不是很友好。 另外,别人也容易根据这种从1开始的自增…...
JMeter入门教程(14)——场景设计
1.JMeter中场景设计是通过线程组来实现的 如图: 控制面板中各元素介绍: 名称:可以随意设置,最好有业务意义。 注释:可以随意设置,可以为空。 在取样器错误后要执行的动作:其中的某一个请求出错后…...
SVM 用于将数据分类为两分类或多分类(Matlab代码实现)
👨🎓个人主页:研学社的博客 💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜…...
转行软件测试我后悔了
很多时候,都在想当初做的转行软件测试行业的决定是对的吗?现在后悔还来得及吗? 记得在求职的时候,面试官经常问我:“为什么要选择软件测试工作?” 而我也会经常说一堆自己有的没的优势去应付。 工作这么久了&#x…...
k8s教程(15)-pod之亲和性与互斥性调度
文章目录01 引言02 pod亲和性调度与互斥性调度2.1 拓扑域2.2 举例2.2.1 参照目标pod2.2.2 pod的亲和性调度2.2.3 pod的互斥性调度03 其它04 文末01 引言 声明:本文为《Kubernetes权威指南:从Docker到Kubernetes实践全接触(第5版)》…...
浅谈降维实操,一种用于处理特征的方式——后附Python代码
👦👦一个帅气的boy,你可以叫我Love And Program 🖱 ⌨个人主页:Love And Program的个人主页 💖💖如果对你有帮助的话希望三连💨💨支持一下博主 降维实操前言线性降维低…...
深度学习中的正则化——L1、L2 和 Dropout
正则化是一组技术,可以防止神经网络中的过度拟合,从而在面对来自问题域的全新数据时提高深度学习模型的准确性。 在本文中,我们将介绍最流行的正则化技术,称为 L1、L2 和 dropout。 文章目录1. 回顾:过拟合2.什么是正则…...
数据结构(王卓)(4)附:链表的销毁与清空
销毁 Status 销毁单链表(LinkList L) {LinkList p;while (L){p L;L->next;delete p;}return OK; } 运行逻辑: (1):设定一个指针,让指针指向链表的头指针L (2):让头指针等于头指针里面指向下…...
C++图书管理系统(管理员-读者)
C图书管理系统(管理员-读者) 一、设计一款文字式交互的图书管理系统,要求具备注册登录、浏览图书、借还图书等基本功能; 二、要求以外部文件的形式存储书籍信息、馆藏记录、借阅记录、用户信息等。【可参考提供的书籍清单】 三…...
永磁同步电机恒压频比(V/F)开环控制系统Matlab/Simulink仿真分析及代码生成到工程实现
文章目录前言一、 恒压频比(V/F)控制原理二、永磁同步电机恒压频比开环控制系统Matlab/Simulink仿真分析2.1.仿真电路分析2.1.1.恒压频比控制算法2.1.2.输出处理2.1.3.主电路2.2.仿真结果分析2.2.1.设定目标转速为1200r/min2.2.1.设定目标转速为变化值三…...
基于JSP网上书城的设计与实现
项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下,你想解决的问…...
java计算机毕业设计-学生宿舍故障报修管理信息系统-源程序+mysql+系统+lw文档+远程调试
java计算机毕业设计-学生宿舍故障报修管理信息系统-源程序mysql系统lw文档远程调试 java计算机毕业设计-学生宿舍故障报修管理信息系统-源程序mysql系统lw文档远程调试本源码技术栈: 项目架构:B/S架构 开发语言:Java语言 开发软件…...
vue学习笔记——简单入门总结(四)
文章目录1.Vue3的特性和变化1.1.创建vue3项目1.2.分析main.js变化:1.3.setup--组合式api的开端1.4.ref函数和reactive函数:1.5.watch监视属性1.5.watchEffect函数1.6.vue3生命周期:1.Vue3的特性和变化 1.1.创建vue3项目 1.这里我们使用脚手架…...
数据结构与算法—数组栈和链表栈
数据结构与算法—数组栈和链表栈 🌈一览众山小数据结构与算法—数组栈和链表栈栈介绍栈图解栈实现数组实现栈实现思路实现代码单链表实现栈实现思路(图解)实现代码栈总结栈力扣栈介绍 栈,存储货物或供旅客住宿的地方,可引申为仓库、中转站,所以引入到计算…...
“超级智能轿车”智己L6开启全国用户交付
继昨天智己L6官宣公布,新增上市权益价为22.69万元的Max 长续航欧;今日又添重磅好消息!新晋爆品智己L6在北京、上海、广州、深圳、杭州、苏州、南京等十余座城市,将首批新车交付用户,正式拉开全国交付的帷幕。同时,智己L6的IM AD“去高精地图城市NOA”在上海、深圳、广州、…...
动手学深度学习(Pytorch版)代码实践 -深度学习基础-02线性回归基础版
02线性回归基础版 主要内容 数据生成:使用线性模型 ( y X*w b ) 加上噪声生成人造数据集。数据读取:通过小批量读取数据集来实现批量梯度下降,打乱数据顺序并逐批返回特征和标签。模型参数初始化:随机初始化权重和偏置&#x…...
Shell脚本的分支语句,循环语句
分支语句 if 表达式 then 命令表 fi 如果表达式为真,则执行命令表中的命令,否则退出。执行fi后的语句。 给文件权限:chmod 0777 文件名 输出: ./文件名 grep 查找用户名,管道wc -l 统计字符 2.多路分支语句 记得给文件名权限喔&#x…...
【Linux进程篇】Linux进程管理——进程创建与终止
W...Y的主页 😊 代码仓库分享💕 目录 进程创建 fork函数初识 写时拷贝 fork常规用法 fork调用失败的原因 进程终止 进程退出场景 _exit函数 exit函数 return退出 进程创建 fork函数初识 在linux中fork函数时非常重要的函数,它从已…...
Flutter 中的 ShrinkWrappingViewPort 小部件:全面指南
Flutter 中的 ShrinkWrappingViewPort 小部件:全面指南 Flutter 是一个由 Google 开发的 UI 框架,它允许开发者使用 Dart 语言来构建跨平台的移动应用。在 Flutter 的布局体系中,ShrinkWrappingViewport 是一个特殊的滚动视图,它…...
解读一下15.52.34.160/27
IP地址15.52.34.160/27可以分解为两部分来解读: IP地址: 15.52.34.160 这是分配给网络接口的地址,用于在网络中标识一个特定的设备。 子网掩码: /27 这表示子网掩码是27位长,意味着网络部分占据了IP地址的前27位,剩下的5位用于主…...