【C++】list讲解及模拟

目录

list的基本介绍

list模拟实现

一.创建节点

二.迭代器

1.模版参数

2.迭代器的实现:

a. !=

b. ==

c. ++ --

d. *指针

e.&引用

整体iterator (与const复用):

三.功能实现

1.模版参数

2.具体功能实现:

2.1 构造函数

2.2 begin() && end()

2.3插入

insert任意位置插入

push_back 尾插&& push_front前插

2.4 删除

erase任意位置删除

pop_back 头删 && pop_front尾删

2.5 拷贝构造 && 赋值操作符

2.6 clear() && 析构函数

代码示例

Test.cpp

list.h


list的基本介绍

list本质上是一个带头双向循环链表,列表是一种用于存储一组元素的数据结构,元素按照插入的顺序排列。它允许动态地添加和删除元素,可以重复存储相同的值。列表提供了对元素的插入、删除、访问和遍历等常用操作。

列表是序列容器,允许在序列内的任何位置插入和擦除操作,并在两个方向上进行迭代。

列表容器被实现为双链接列表;双链接列表可以将它们所包含的每个元素存储在不同的和不相关的存储位置中。顺序通过与前面元素的链接和后面元素的链接的关联在内部保持。

与其他序列容器相比,列表和前向列表的主要缺点是它们无法通过位置直接访问元素; 例如,要访问列表中的第六个元素,必须从已知位置(如开始或结束)迭代到该位置,该位置之间的距离需要线性时间。它们还会消耗一些额外的内存来保持与每个元素相关联的链接信息(这可能是大量小元素列表的一个重要因素)。

若要查看双向循环链表相关知识→:数据结构:线性表之-循环双向链表(万字详解)_数据结构循环双链表概念-CSDN博客

list模拟实现

一.创建节点

template <class T>//模版
struct list_node
{list_node<T> *_prev;//前一节点list_node<T> *_next;//后一节点T _data;
​// 构造函数,创建链表list_node(const T &x = T()) // 用匿名对象做缺省值(调用默认构造),以存储其他类型的元素: _next(nullptr), _prev(nullptr), _data(x){}
};

二.迭代器

1.模版参数

template <class T, class Ref, class Ptr>
  1. class T:表示元素类型,为了应对要接收不同类型的数据

  2. class Ref:引用类型参数模版,Ref用于提供对迭代器所指向元素的引用

  3. class Ptr:指针类型参数模版,Ptr用于提供对迭代器所指向元素的指针。

后面会提到Ref,Ptr作用,请仔细阅读哦

2.迭代器的实现:

基本模版:

template <class T, class Ref, class Ptr>
struct __list_iterator
{//重新命名typedef list_node<T> node; typedef __list_iterator<T, Ref, Ptr> self;node *_node;//指向列表节点的指针,用于追踪迭代器的当前位置。
​//构造函数,接受一个指向列表节点的指针,并将其作为初始位置给 _node。__list_iterator(node *n): _node(n){}
};

这个结构体的作用是提供列表的迭代功能,它可以被用于遍历列表中的元素,并对元素进行访问和操作。

"const T&"表示迭代器所指向元素的引用类型,而"const T*"表示迭代器所指向元素的指针类型。 这样定义迭代器的目的是为了在const成员函数中使用该迭代器,并保证在遍历列表时不会修改列表中的元素"

参考:

list<int>::iterator it = lt.begin();
//__list_itreator后续被重命名为iterator
a. !=
bool operator!=(const self &s)
{return _node != s._node;
}
b. ==
bool operator==(const self &s)
{return _node == s._node;
}
c. ++ --
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;
}
d. *指针

重载了解引用运算符(*),返回 _node->_data 的引用,即迭代器所指向的元素

Ref &operator*()//加const不能修改数据
{return _node->_data;
}
e.&引用

重载了箭头运算符(->),返回 _node->_data 的指针,即迭代器所指向元素的指针

Ptr operator->()
{return &(_node->_data); // 取地址
}

Ref与Ptr的定义在class list中进行定义

整体iterator (与const复用):
template <class T, class Ref, class Ptr>
struct __list_iterator
{typedef list_node<T> node;typedef __list_iterator<T, Ref, Ptr> self;node *_node;__list_iterator(node *n): _node(n){}Ref &operator*(){return _node->_data;}Ptr operator->(){return &(_node->_data); // 取地址}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 &s){return _node != s._node;}bool operator==(const self &s){return _node == s._node;}
};

三.功能实现

1.模版参数

    
template <class T>
class list
{typedef list_node<T> node;public://iterator和const_iterator都是公用接口typedef __list_iterator<T, T &, T *> iterator;typedef __list_iterator<T, const T &, const T *> const_iterator;private://头节点node *_head; // ListNode<T>是类型 , ListNode是类名
};

2.具体功能实现:

2.1 构造函数

为了后续操作的方便,将初始化链表代码写在另一个函数里

void empty_init()
{_head = new node;_head->_next = _head;_head->_prev = _head;
}
list()
{empty_init();
}
2.2 begin() && end()
iterator begin()
{return iterator(_head->_next);
}
​
iterator end()
{return iterator(_head);
}
​
const_iterator begin() const
{return const_iterator(_head->_next);
}
​
const_iterator end() const
{return const_iterator(_head);
}

test:通过迭代器依次打印出元素

list<int>::iterator it = lt.begin();
while (it != lt.end())
{cout << *it << " ";++it;
}
cout << endl;

我们将迭代器遍历封装到一个函数内:

void print_list(const list<T> &lt)
{cout << "---list---" << endl;// list<int>::const_iterator it = lt.begin();list<int>::const_iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl<< "---list---" << endl;
}
2.3插入
insert任意位置插入
void insert(iterator pos, const T &x)
{node *cur = pos._node;   // .访问pos内的成员变量_nodenode *prev = cur->_prev; // ->访问指针所指向的节点的成员
​node *new_node = new node(x);
​prev->_next = new_node;new_node->_prev = prev;new_node->_next = cur;cur->_prev = new_node;
}
push_back 尾插&& push_front前插
void push_back(const T &x)
{insert(end(), x);
}
void push_front(const T &x)
{insert(begin(), x);
}

test:

void test_list3()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);
​list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;
​it = lt.begin();list<int>::iterator pos = lt.begin();++pos;lt.insert(pos, 20);
​lt.print_list(lt);
​cout << endl;
}
2.4 删除
erase任意位置删除
iterator erase(iterator pos)
{assert(pos != end());
​node *prev = pos._node->_prev;node *next = pos._node->_next;
​prev->_next = next;next->_prev = prev;delete pos._node;
​return iterator(next);
}
pop_back 头删 && pop_front尾删
void pop_back()
{erase(--end());
}
void pop_front()
{erase(begin());
}

test:

void test_list4()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.print_list(lt);cout << endl;lt.push_back(100);lt.push_front(99);lt.print_list(lt);cout << endl;
​lt.pop_back();lt.pop_front();lt.print_list(lt);cout << endl;
}

2.5 拷贝构造 && 赋值操作符

swap交换函数:

void swap(list<T> &temp)
{std::swap(_head, temp._head);
}

当调用swap函数时[例子:lt2拷贝lt1调用swap时],调用拷贝构造将lt1进行拷贝再交换到lt2

list:

list(const list<T> &lt)
{empty_init();//创建头节点list<T> temp(lt.begin(), lt.end());swap(temp);
}

赋值操作数:

// lt3=lt2
// 不能使用&,而是传值调用拷贝构造,拷贝lt2,赋值给lt3
list<T> &operator=(const list<T> lt)//const list<T>& lt
{swap(lt);return *this;
}

test:

void test_list6()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.print_list(lt);cout << endl;
​// list<int> lt2(lt);// lt2.print_list(lt2);// cout << endl;list<int> lt2 = lt;lt2.print_list(lt2);lt.print_list(lt);
}

2.6 clear() && 析构函数

clear:清除头节点以外的数据

void clear()
{iterator it = begin();while (it != end())it = erase(it); // erase(it++);//后置++返回的是前一个的拷贝,不会失效
}

test:

void test_list5()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.print_list(lt);cout << endl;
​lt.clear();lt.push_back(20);
​lt.print_list(lt);
}

析构:

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

代码示例

Test.cpp

#include "list.h"int main()
{wzf::test_list6();return 0;
}

list.h

#pragma once
#include <iostream>
#include <assert.h>
using namespace std;namespace wzf
{// 节点template <class T>struct list_node{list_node<T> *_prev;list_node<T> *_next;T _data;// 构造函数,创建链表list_node(const T &x = T()) // 用匿名对象做缺省值(调用默认构造),以存储收其他类型的元素: _next(nullptr), _prev(nullptr), _data(x){}};// 迭代器// // 1.iterator// template <class T>// struct __list_iterator// {//     typedef list_node<T> node;//     typedef __list_iterator<T> self;//     node *_node;//     __list_iterator(node *n)//         : _node(n)//     {//     }//     T &operator*()//     {//         return _node->_data;//     }//     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 &s)//     {//         return _node != s._node;//     }//     bool operator==(const self &s)//     {//         return _node == s._node;//     }// };// // 2.const_iterator// template <class T>// struct __list_const_iterator// {//     typedef list_node<T> node;//     typedef __list_const_iterator<T> self;//     node *_node;//     __list_const_iterator(node *n)//         : _node(n)//     {//     }//     const T &operator*() // 与1区别的地方,加const不能修改数据//     {//         return _node->_data;//     }//     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 &s)//     {//         return _node != s._node;//     }//     bool operator==(const self &s)//     {//         return _node == s._node;//     }// };// template <class T,class Ref>// struct __list_iterator// {//     typedef list_node<T> node;//     typedef __list_iterator<T,Ref> self;//     node *_node;//     __list_iterator(node *n)//         : _node(n)//     {//     }//     Ref &operator*()//     {//         return _node->_data;//     }//     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 &s)//     {//         return _node != s._node;//     }//     bool operator==(const self &s)//     {//         return _node == s._node;//     }// };// 迭代器template <class T, class Ref, class Ptr>struct __list_iterator{typedef list_node<T> node;typedef __list_iterator<T, Ref, Ptr> self;node *_node;__list_iterator(node *n): _node(n){}Ref &operator*(){return _node->_data;}Ptr operator->(){return &(_node->_data); // 取地址}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 &s){return _node != s._node;}bool operator==(const self &s){return _node == s._node;}/*"const T&"表示迭代器所指向元素的引用类型,而"const T*"表示迭代器所指向元素的指针类型。这样定义迭代器的目的是为了在const成员函数中使用该迭代器,并保证在遍历列表时不会修改列表中的元素*/};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_const_iterator<T> const_iterator;iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}void empty_init(){_head = new node;_head->_next = _head;_head->_prev = _head;}list(){empty_init();}// 构造函数, 迭代器区间template <class Iterator>list(const Iterator first, const Iterator last){empty_init(); // 创建头节点for (Iterator it = first; it != last; ++it)push_back(*it);}void swap(list<T> &temp){std::swap(_head, temp._head);}// 拷贝构造// lt2(lt1)// list(const list<T> &lt)// {//     empty_init();//     const_iterator it = lt.begin();//     while (it != lt.end())//     {//         push_back(*it);//         ++it;//     }// }list(const list<T> &lt){empty_init();list<T> temp(lt.begin(), lt.end());swap(temp);}// 赋值操作符// lt3=lt2// 不能使用&,而是传值调用拷贝构造,拷贝lt2,赋值给lt3list<T> &operator=(const list<T> lt){swap(lt);return *this;}~list(){clear();delete _head;_head = nullptr;}// 清除头节点以外的数据void clear(){iterator it = begin();while (it != end())it = erase(it); // erase(it++);//后置++返回的是前一个的拷贝,不会失效}// void push_back(const T &x)// {//     node *tail = _head->_prev;//     node *new_node = new node(x);//     tail->_next = new_node;//     new_node->_prev = tail;//     new_node->_next = _head;//     _head->_prev = new_node;// }void push_back(const T &x){insert(end(), x);}void push_front(const T &x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}void print_list(const list<T> &lt){cout << "---list---" << endl;// list<int>::const_iterator it = lt.begin();list<int>::const_iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl<< "---list---" << endl;}void insert(iterator pos, const T &x){node *cur = pos._node;   // .访问pos内的成员变量_nodenode *prev = cur->_prev; // ->访问指针所指向的节点的成员node *new_node = new node(x);prev->_next = new_node;new_node->_prev = prev;new_node->_next = cur;cur->_prev = new_node;}iterator erase(iterator pos){assert(pos != end());node *prev = pos._node->_prev;node *next = pos._node->_next;prev->_next = next;next->_prev = prev;delete pos._node;return iterator(next);}/*在该函数的最后一行,返回了一个迭代器对象 `iterator(next)`。这是因为在 C++ STL 中,通常情况下,删除一个元素后,我们希望返回删除元素的下一个位置作为新的迭代器。直接返回 `next` 的话,可能会暴露内部实现细节,使得用户可以直接操作指针 `next`,可能导致潜在的问题。为了隐藏底层指针的细节,通常会将其封装在迭代器对象中返回。因此,返回 `iterator(next)` 的方式可以提供更好的封装性和安全性,使用户能够使用迭代器对象来操作返回的下一个位置,而不需要直接访问底层的指针。这也符合 C++ STL 设计的一般原则,即通过迭代器提供统一的接口,隐藏底层的具体实现细节。*/private:node *_head; // ListNode<T>是类型 , ListNode是类名};void test_list1(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;lt.print_list(lt);}struct AA{int _a1;int _a2;AA(int a1 = 0, int a2 = 0): _a1(a1), _a2(a2){}};void test_list2(){list<AA> lt;lt.push_back(AA(1, 2));lt.push_back(AA(3, 4));lt.push_back(AA(5, 6));list<AA>::iterator it = lt.begin();while (it != lt.end()){cout << it->_a1 << " " << it._node->_data._a2 << endl;cout << it.operator->()->_a1 << " " << it.operator->()->_a2 << endl;cout << it.operator->() << endl<< endl; // 地址值++it;}}void test_list3(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;it = lt.begin();list<int>::iterator pos = lt.begin();++pos;lt.insert(pos, 20);lt.print_list(lt);cout << endl;}void test_list4(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.print_list(lt);cout << endl;lt.push_back(100);lt.push_front(99);lt.print_list(lt);cout << endl;lt.pop_back();lt.pop_front();lt.print_list(lt);cout << endl;}void test_list5(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.print_list(lt);cout << endl;lt.clear();lt.push_back(20);lt.print_list(lt);}void test_list6(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.print_list(lt);cout << endl;// list<int> lt2(lt);// lt2.print_list(lt2);// cout << endl;list<int> lt2 = lt;lt2.print_list(lt2);lt.print_list(lt);}
}

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

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

相关文章

【操作系统】实验九 写一个设备驱动程序

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的很重要&…

6.【SpringBoot3】登录优化-redis

1. SpringBoot 集成 redis 示例 在之前实现的登录接口中&#xff0c;用户登录成功后会生成一个令牌响应给浏览器&#xff0c;之后浏览器访问其他接口时&#xff0c;都要携带该令牌&#xff0c;接受拦截器的检验&#xff0c;如果令牌有效就放行&#xff0c;允许访问后续接口&am…

uml时序图刻画多个线程的活动

使用box关键字圈入不同线程内的组件 使用loop关键字客刻画线程的定时活动 示例

SpringMVC-RESTFul

文章目录 RESTFul一、基础概念二、增删改查1.查询全部用户信息 &#xff08;GET&#xff09;2.根据id查询用户信息3.添加用户&#xff08;POST&#xff09;4.修改用户 &#xff08;PUT&#xff09;5.删除用户 &#xff08;DELETE&#xff09; RESTFul 一、基础概念 二、增删改…

GitHub 上传文件夹到远程仓库、再次上传修改文件、如何使用lfs上传大文件、github报错一些问题

按照大家的做法&#xff0c;把自己遇到的问题及解决方案写出来&#xff08;注意&#xff1a;Error里面有些方法有时候我用可以成功&#xff0c;有时候我用也不能成功&#xff0c;写出来仅供参考&#xff0c;实在不行重头再clone&#xff0c;add&#xff0c;commit&#xff0c;p…

Qt程序设计-修改系统时间(Windows和Linux)

本文讲解Qt程序设计-修改系统时间(windows) 1、实例 创建项目,添加DateEdit和TimeEdit控件和按钮 头文件 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>namespace Ui { class MainWindow; }class MainWindow : public QMainWindow {Q_OBJECTpubl…

C#,生成图片的指定尺寸缩略图的源代码

编程的时候经常用到图像的缩略图。 本文发布一个用于生成指定尺寸的缩略图的简单方法。 1 文本格式 private void button1_Click(object sender, EventArgs e) { CreateThumbnail("demo.jpg", "demo_thumb.jpg", 128, 128); } private void CreateTh…

社交媒体与新闻:Facebook在信息传播中的角色

社交媒体的崛起不仅改变了人们的日常交流方式&#xff0c;也对新闻传播产生了深远的影响。在众多社交媒体平台中&#xff0c;Facebook以其庞大的用户基础和强大的社交网络机制&#xff0c;成为信息传播的中流砥柱。本文将深入探讨Facebook在社交媒体与新闻传播的交汇点上扮演的…

xshell无法连接linux,查询本机ip时出现<NO-CARRIER,BROADCAST,MULTICAST,UP>

在用xshell连接虚拟机VMware中的linux时&#xff0c;发现昨天还能连通的&#xff0c;今天连接不了了 我寻思应该是网卡配置出问题了&#xff0c;就去终端ip addr试了一下&#xff0c;果然发现问题&#xff0c;ip 查看网卡ens33就发现出现ens33:<NO-CARRIER,BROADCAST,MULTI…

git安装步骤

安装环境&#xff1a;Windows10 64bit 下载 Git网址 &#xff1a;Git - Downloading Package 版本&#xff1a;Git-2.21.0-64-bit 第一步&#xff1a;双击下载后的Git-2.21.0-64-bit.exe&#xff0c;开始安装 安装开始 第二步&#xff1a;选择安装路径&#xff0c;点击[next]…

Linux基础指令大汇总

Linux的指令比较多&#xff0c;在学习的过程中要学会总结和归纳&#xff0c;同时结合实践多多使用&#xff0c;就像学数学一样&#xff0c;不是背过公式就等于掌握的&#xff0c;而是要知道在什么时候用&#xff0c;怎么用才是关键。 这篇文章会列举一系列常用的指令&#xff0…

基于Grafana+Prometheus搭建可视化监控系统实践

基本介绍 Grafana&#xff1a;一个监控仪表系统&#xff0c;可以根据提供的监控数据&#xff0c;生产可视化仪表盘&#xff0c;同时也具有告警通知功能。这里的监控数据来源&#xff0c;目前主要以Prometheus为主&#xff08;也支持其它数据源&#xff09;&#xff0c;每次展现…

EasyCVR视频智能监管系统方案设计与应用

随着科技的发展&#xff0c;视频监控平台在各个领域的应用越来越广泛。然而&#xff0c;当前的视频监控平台仍存在一些问题&#xff0c;如视频质量不高、监控范围有限、智能化程度不够等。这些问题不仅影响了监控效果&#xff0c;也制约了视频监控平台的发展。 为了解决这些问…

Spring 的存储和获取Bean

文章目录 获取 Spring 上下文对象的方式存储 Bean 对象的方式类注解配置扫描路径&#xff08;必须&#xff09;Controller&#xff08;控制器存储&#xff09;Service&#xff08;服务&#xff09;Repository&#xff08;持久层&#xff09;Component&#xff08;工具&#xff…

css不规则的文本环绕

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>不规则的文本环绕</title><style>.b…

flyway使用配置参数和注意事项介绍

文章目录 业务场景参数介绍initSqlsbaselineOnMigratebaselineVersiontargetvalidateOnMigrate SQL注意事项 业务场景 对于生产环境&#xff0c;随着项目版本迭代&#xff0c;数据库结构也会变动。如果一个项目在多个地方实施部署&#xff0c;且版本不一致&#xff0c;就需要一…

CSS之粘性定位

让我为大家介绍一下粘性定位吧&#xff01; 大家应该都了解过绝对定位&#xff0c;它是相对于父级定位 那么粘性定位相对于谁呢&#xff1f; 它相对于overflow:hidden; 如果没找到就会跟fixed固定定位一样&#xff0c;相对于视口 <!DOCTYPE html> <html lang"en…

C++ 利用容器适配器,仿函数实现栈,队列,优先级队列(堆),反向迭代器,deque的介绍与底层

C 利用容器适配器,仿函数实现栈,队列,优先级队列【堆】,反向迭代器,deque的介绍与底层 一.容器适配器的介绍二.利用容器适配器实现栈和队列1.stack2.queue 三.仿函数介绍1.什么是仿函数2.仿函数的使用3.函数指针的使用1.函数指针的用处2.利用函数指针完成回调3.利用仿函数完成回…

免 费 小程序商城搭建之b2b2c o2o 多商家入驻商城 直播带货商城 电子商务b2b2c o2o 多商家入驻商城 直播带货商城 电子商务

1. 涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务&#xff09; 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis 3. 前端框架…

cg插画设计行业怎么样,如何学习插画设计

插画设计行业是一个充满创意和艺术性的行业&#xff0c;随着数字化时代的不断发展&#xff0c;cg插画的应用范围越来越广泛&#xff0c;市场需求也在逐年增长。以下是一些关于acg插画设计行业的现状和发展趋势&#xff1a; 市场需求不断增长&#xff1a;随着广告、媒体、影视、…