【C++进阶】深入STL之list:模拟实现深入理解List与迭代器
📝个人主页🌹:Eternity._
⏩收录专栏⏪:C++ “ 登神长阶 ”
🤡往期回顾🤡:初步了解 list
🌹🌹期待您的关注 🌹🌹
❀STL之list
- 📒1. list的基本结构
- 📕2. list的模拟实现
- 🌈构造函数
- 🌞析构函数
- 🌙拷贝构造函数
- ⭐赋值运算符重载
- 📚3. list的迭代器
- 🍂迭代器的基本结构
- 🍁迭代器的运算符重载
- 🌸list的迭代器
- 📙4. list的const迭代器
- 🎩方法一
- 🎈方法二
- 📜5. 统一的方式访问STL容器中的元素
- 📔6. list与vector的对比
- 📖7. 总结补充
- 💧补充:insert和erase的模拟实现
- 🔥总结
在软件开发中,数据结构和算法的选择与实现是每一个开发者都必须面对的问题。标准模板库(STL)为我们提供了一系列高效且通用的数据结构和算法模板,极大地简化了C++编程中的许多常见任务。然而,了解这些数据结构和算法背后的实现原理,不仅有助于我们更深入地理解STL,还能提升我们的编程能力和解决问题的能力。
前言: 在STL中,list是一种双向链表,它支持在序列的任何位置进行快速插入和删除操作。与此同时,迭代器是STL中非常重要的一个概念,它使得我们能够以统一的方式遍历和访问STL容器中的元素。在深入了解STL的过程中,模拟实现list和迭代器无疑是一个极有价值的学习过程。
本节我们将从基本的链表结构开始,逐步构建出完整的list类,并实现相应的迭代器类。
📒1. list的基本结构
list是一个个带头双向循环链表,这意味着每个元素(通常称为节点)都有两个指针:一个指向前一个元素,另一个指向后一个元素,因此我们需要单独再定义一个类来表示节点结构,每个节点再串联起来构成list
节点定义(示例):
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){}
};
而在构建list时,我们成员变量只需要一个头节点。
list定义(示例):
template<class T>
struct list
{typedef list_node<T> Node;
public:// 构造函数等可能的其他成员函数...
private:Node* _head;
};
📕2. list的模拟实现
注意:关于
erase
和insert
这两个函数的模拟我们依然作为补充放在末尾
🌈构造函数
在拥有一个list我们只需要将它的头节点初始化一下
list构造(示例):
void empty_init()
{_head = new Node;_head->_prev = _head;_head->_next = _head;
}// 无参构造
list()
{empty_init();
}
🌞析构函数
关于析构函数,我们需要的是将所有节点一 一释放就ok啦!
在模拟析构函数之前,不得不先介绍一下clear
这个函数,因为clear
可以删除出头节点以外的所有节点,我们可以利用这一点帮助我们优化析构函数
list析构(示例):
void clear()
{// 依次清除节点itetator it = begin(); // 稍后会提到迭代器的模拟while(it != end()){it = erase(it);}
}~list()
{clear(); // 删除出头节点以外的所有节点delete _head; // 单独删除一下头节点_head = nullptr;
}
🌙拷贝构造函数
在学习list时,我们发现list不会因为空间不够而需要扩容,因此在使用模拟list时,不用考虑是否会发生浅拷贝
list拷贝构造函数(示例):
//list(const list<T>& lt)
list(list<T>& lt) // 还未实现const迭代器,先使用常规的
{empty_init();for (auto e : lt){push_back(e); // push_back的实现其实是复用insert,文末有补充}
}
⭐赋值运算符重载
这里我们以让后传统写法和现代写法两种方法
list赋值运算符重载(示例):
// 传统写法
list<T>& operator=(const list<T>& lt)
{clear(); // 先将原来的list清空for (auto e : lt){push_back(e);}return *this;
}// 现代写法
void swap(list<T>& tmp)
{std::swap(_head, tmp._head);
}list<T>& operator=(list<T> lt)
{swap(lt);return *this;
}
在介绍完list基本的结构后,让我们来看看今天的重点:迭代器
📚3. list的迭代器
在我们模拟实现string
,vector
时,我们认为迭代器就是一个原生指针,但是在list
中迭代器底层不是简单的指针,因此我们要独立定义一个新的类
🍂迭代器的基本结构
迭代器定义(示例):
template<class T>
struct __list_iterator
{typedef list_node<T> Node;typedef __list_iterator<T> self;Node* _node;// 构造函数__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;
}bool operator!=(const self& tmp)
{return _node != tmp._node;
}bool operator-=(const self& tmp)
{return _node -= tmp._node;
}
而今天着重要强调以下两个运算符重载,因为const
和非const
下这两个是有区别的:
//可读写
T& operator*()
{return _node->_data;
}
//可读写
T* operator->()
{return &_node->_data;
}
// it.operator->()-> 编译器帮我们省略了一个箭头-> it->
在定义完迭代器类之后,我们可以实现begin()
和end()
来实现list
的范围for
🌸list的迭代器
迭代器代码(示例):
template<class T>
struct list
{typedef list_node<T> Node;
public:typedef __list_iterator<T> iterator;iterator begin(){//return iterator(_head->_next); // 匿名对象return _head->next;}iterator end(){//return iterator(_head); // 匿名对象return _head;}
private:Node* _head;
};
当然我们这里还没有实现
const迭代器
很多需要调用const对象
的函数还无法使用,那么接下来让我们来模拟实现const迭代器
,见证新的神奇
📙4. list的const迭代器
关于这个list的const迭代器其实有两种写法,常规的写法就是在定义一个新的
const迭代器
的类,虽然这样可以解决问题,但是会造成代码的冗余,让操作繁琐。而另一种方法就是在原有的迭代器类上进行修改,让它能具有两个迭代器都能使用的特点
🎩方法一
const迭代器实现(示例):
template<class T>
struct __list_const_iterator
{typedef list_node<T> Node;typedef __list_const_iterator<T> self;Node* _node;// 构造函数__list_const_iterator(Node* node):_node(node){}//可读不可写const T& operator*(){return _node->_data;}//可读不可写const T* operator->(){return &_node->_data;}// 可能的其他成员函数...
};
🎈方法二
如果我们将这两个差异的内容单独表示出来归于模板中,因为在const与非const之间
,无非就是T&,T*上能否读写的区别
,不影响其他的函数实现,因此我们可以在模板上加上两个参数
模板参数 | 实例化类型 |
---|---|
Ref | T&,(const 变量时) const T& |
Ptr | T*,(const 变量时) const T* |
const迭代器实现(示例):
// 用一个模板来解决 const与非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* node):_node(node){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}// 可能的其他成员函数...
};
template<class T>
struct list
{typedef list_node<T> Node;
public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_const_iterator<T, const T&, const T*> const_iterator;iterator begin(){return _head->next;}iterator end(){return _head;}const_iterator begin() const{return _head->next;}const_iterator end() const{return _head;}
private:Node* _head;
};
关于list的模拟实现我们就讲到这里,让我看看如何以统一的方式遍历和访问STL容器中的元素
📜5. 统一的方式访问STL容器中的元素
在完成对list的模拟实现后,我们试着用来遍历和访问list中的元素
代码实现(示例):
void print_list(const list<int>& lt)
{// list<T>没有实例化话,就并不能去遍历寻找// 编译器不知道 list<T>::const_iterator 是内嵌类型,还是静态成员变量list<int>::const_iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}
}
void test_list()
{list<int> lt;lt.push_back(1);lt.push_back(2);print_list(lt);cout << endl;
}
编译器不知道 list::const_iterator 是内嵌类型,还是静态成员变量,但是如果实例化成int
后,有需要一个成员是string
的列表这时我们有犯难了,这时我们就要用到typename
,typename
就是告诉编译器,这是一个类型,等list实例化之后再去取
代码实现(示例):
template<typename T>
void print_list(const list<T>& lt)
{......// typename 就是告诉编译器,这是一个类型,等list实例化之后再去取typename list<T>::const_iterator it = lt.begin();......
}
但是更离谱的来了,这时又有人要求我们打印vector
的值,容器都换了我们该怎么办呢?这时模板的作用又双体现出来了,这也体现了模板的本质,让我们能省的活交给编译器完成
代码实现(示例):
// 这里直接搞了一个Container来适配容器
template<typename Container>
void print_container(const Container& con)
{typename Container::const_iterator it = con.begin();while (it != con.end()){cout << *it << " ";++it;}
}
它使得我们能够以统一的方式遍历和访问STL容器中的元素
📔6. list与vector的对比
我们可以发现list与之前学的竟然有那么多的差异,我们结合上节学的vector
来分析一下它们的差异:vector
与list
都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不同
vector | list | |
---|---|---|
底 层 结 构 | 动态顺序表,一段连续空间 | 带头结点的双向循环链表 |
随 机 访 问 | 支持随机访问,访问某个元素效率O(1) | 不支持随机访问,访问某个元素效率O(N) |
插 入 和 删 除 | 任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有可能需要增容, | 任意位置插入和删除效率高,不需要搬移元素,时间复杂度为O(1) |
空 间 利 用 率 | 底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高 | 底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低 |
迭 代 器 | 插入删除时触发条件会导致迭代器失效 | 删除元素时,只会导致当前迭代器失效,其他迭代器不受影响 |
使 用 场 景 | 需要高效存储,支持随机访问,不关心插入删除效率 | 大量插入和删除操作,不关心随机访问 |
📖7. 总结补充
💧补充:insert和erase的模拟实现
代码实现(示例):
// insert会返回插入位置的一个迭代器
iterator insert(iterator pos, const T& x)
{Node* newnode = new Node(x);Node* cur = pos._node;Node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;cur->_prev = newnode;newnode->_next = cur;return iterator(newnode); // 匿名对象
}
// erase会返回删除位置的next节点的迭代器
iterator erase(iterator pos)
{Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;delete cur;prev->_next = next->_prev;next->_prev = prev->_next;return iterator(next); // 匿名对象
}
// erase和insert的复用
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());
}
🔥总结
通过本次对STL中list和迭代器模拟实现的探索,我们深入了解了双向链表的基本结构、操作原理以及迭代器在遍历和访问链表元素中的重要作用。模拟实现的过程不仅让我们对STL中的list容器有了更深刻的理解,也锻炼了我们的编程能力和解决问题的能力
- 在模拟实现的过程中,我们学习了如何设计并实现一个双向链表结构,包括节点的定义、链表的插入、删除和遍历等操作。同时,我们也掌握了迭代器的基本概念和实现方法,理解了如何通过迭代器来统一访问和遍历不同的容器类型。
- 模拟实现STL中的list和迭代器是一个既有趣又富有挑战性的过程。它让我们更加深入地理解了数据结构和算法的基本原理,也为我们日后在实际项目中高效应用STL容器打下了坚实的基础。
最后,感谢大家的耐心阅读和学习。希望本次介绍能够为大家在STL学习和编程实践中提供一些帮助和启示。在未来的学习和工作中,让我们继续深入探索STL的奥秘,不断提升自己的编程能力和解决问题的能力
谢谢大家支持本篇到这里就结束了,祝大家天天开心!
相关文章:
【C++进阶】深入STL之list:模拟实现深入理解List与迭代器
📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C “ 登神长阶 ” 🤡往期回顾🤡:初步了解 list 🌹🌹期待您的关注 🌹🌹 ❀STL之list 📒1. list…...
技术管理之巅—如何从零打造高质效互联网技术团队阅读体验
技术管理之巅—如何从零打造高质效互联网技术团队 《技术管理之巅:如何从零打造高质效互联网技术团队》是黄哲铿所著的一本书,致力于帮助技术管理者从零开始打造高效的互联网技术团队。该书分为多个章节,分别探讨了从团队文化建设到技术架构…...
机器学习与数据挖掘知识点总结(一)
简介:随着人工智能(AI)蓬勃发展,也有越来越多的人涌入到这一行业。下面简单介绍一下机器学习的各大领域,机器学习包含深度学习以及强化学习,在本节的机器学习中主要阐述一下机器学习的线性回归逻辑回归&…...
行心科技中禄松波携手,开启智能健康新时代
在2024年第34届健博会暨中国大健康产业文化节的盛大舞台上,广州市行心信息科技有限公司(以下简称“行心科技”)与浙江中禄松波生物工程有限公司(以下简称“中禄松波”)宣布达成战略合作,共同推动医康养产业…...
前端多人项目开发中,如何保证CSS样式不冲突?
在前端项目开发中,例如突然来了一个大项目,很可能就需要多人一起开发,领导说了,要快,要快,要快,你们给我快。然后下面大伙就一拥而上,干着干着发现,一更新代码࿰…...
【YOLOv10改进[CONV]】使用DualConv二次创新C2f模块实现轻量化 + 含全部代码和详细修改方式 + 手撕结构图 + 全网首发
本文将使用DualConv二次创新C2f模块实现轻量化,助力YOLOv10目标检测效果的实践,文中含全部代码、详细修改方式以及手撕结构图。助您轻松理解改进的方法。 改进前和改进后的参数对比: 目录 一 DualConv 1 结合33卷积和11卷积核 2 DualConv 3 可视化 二 C2f_DualConv助…...
基于SSM+Jsp的高校信息资源共享平台
开发语言:Java框架:ssm技术:JSPJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包…...
软件测试--Linux快速入门
文章目录 软件测试-需要掌握的Linux指令Linux命令操作技巧Linx命令的基本组成常用命令 软件测试-需要掌握的Linux指令 Linux命令操作技巧 使用Tab键自动补全上下键进行翻找之前输入的命令命令执行后无法停止使用CtrC,结束屏幕输出 Linx命令的基本组成 命令 [-选项] [参数] …...
module ‘django_cas_ng.views‘ has no attribute ‘login‘
这个错误表明你正在尝试从django_cas_ng.views模块中访问一个名为login的属性,但是这个模块中并没有名为login的属性或方法。 解决这个问题,你需要确认你的代码中是否有错误的引用。django_cas_ng是一个CAS(Central Authentication Service&…...
CW32F030K8T7单片机在即热式热水器的应用介绍
随着智能家居技术的不断进步,即热式热水器作为现代家庭中的重要组成部分,正逐渐向智能化、节能化方向发展。本方案通过采用武汉芯源半导体的CW32F030系列单片机,以其高性能、超强抗干扰等特性,为即热式热水器的智能化提供了理想的…...
HTML静态网页成品作业(HTML+CSS)—— 美食湘菜介绍网页(5个页面)
🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有5个页面。 二、作品演示 三、代…...
使用redis构建简单的社交网站
Redis命令实践通常涉及对Redis服务器的直接操作,包括数据的增删改查以及管理Redis实例。以下是一些基本的Redis命令及其使用场景: 连接Redis服务器: 使用Redis客户端连接到Redis服务器:redis-cli 设置和获取键值对: SET key value࿱…...
【Java面试】九、微服务篇-SpringCloud(上)
文章目录 1、SpringCloud五大组件2、服务注册和发现2.1 Eurake2.2 Eurake和Nacos的区别 3、Ribbon负载均衡3.1 策略3.2 自定义负载均衡策略 4、服务雪崩与熔断降级4.1 服务雪崩4.2 服务降级4.3 服务熔断 5、服务限流5.1 Nginx限流5.2 网关限流 6、微服务监控7、面试 1、SpringC…...
Python 树状数组
树状数组(Binary Indexed Tree, BIT),又称为斐波那契堆,是一种数据结构,用于高效地解决以下问题: 单点更新:在数组的某个位置增加或减少一个值。区间查询:查询数组中一段连续区间的…...
【QEMU中文手册】2.2 调用方式(持续更新中)
本文由 AI 翻译(ChatGPT-4)完成,并由作者进行人工校对。如有任何问题或建议,欢迎联系我。联系方式:jelin-shoutlook.com。 原文:Invocation — QEMU documentation qemu-system-x86_64 [选项] [磁盘镜像]磁…...
(函数)判断一句话中最长的单词(C语言)
一、运行结果; 二、源代码; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//声明函数; int aiphabetic(char); int longest(char[]);int main() {//初始化变量值;int i;char line[100] { 0 };//获取用户输入字符…...
QT5.5.0中使用lambda表达式时遇到的问题
QT5.5中使用lambda表达式的遇到的error_qt中lamda不起作用-CSDN博客...
【Go语言精进之路】构建高效Go程序:了解切片实现原理并高效使用
🔥 个人主页:空白诗 文章目录 引言一、切片究竟是什么?1.1 基础的创建数组示例1.2 基础的创建切片示例1.3 切片与数组的关系 二、切片的高级特性:动态扩容2.1 使用 append 函数扩容2.2 容量管理与性能考量2.3 切片的截取与缩容 三…...
Python与C语言:深入探索两者的奥秘与差异
Python与C语言:深入探索两者的奥秘与差异 在编程的世界里,Python和C语言如同两位性格迥异的伙伴,各自拥有独特的魅力和应用场景。Python以其简洁易懂的语法和强大的库支持赢得了众多开发者的青睐,而C语言则以其接近硬件的低级特性…...
图像编解码器在AI绘画中的革新作用
随着人工智能技术的飞速发展,AI绘画已经从一个简单的概念演变为一个充满创意与可能性的领域。在这场技术与艺术的融合中,图像编解码器扮演着至关重要的角色。它们不仅提升了AI绘画的质量和效率,还拓宽了艺术创造的边界。本篇博客将深入探讨图…...
SecureCRT[po破] for Mac SSH终端操作工具[解] 安装教程
文章目录 效果一、准备工作二、开始安装1、双击运行软件,将其从左侧拖入右侧文件夹中,等待安装完毕2、 应用程序显示软件图标,表示安装成功 三、输入对应参数1、解决“软件已损坏,无法打开,要移到废纸篓”问题解决步骤…...
【大数据架构】基于流式数据的大数据架构升级
背景 团队在升级大数据架构,摒弃了原来基于hadoop的架构,因此抛弃了hive,hdfs,mapreduce这一套,在讨论和摸索中使用了新的架构。 后端使用kafka流式数据通过rest catalog写入iceberg,存储于minio。在写入iceberg的时候,首先是写data数据文件,然后再写iceberg的metada…...
OpenCV中的圆形标靶检测——斑点检测算法(二)
前面的章节中我们已经大致介绍了算法流程,也对一些算法中用到的相关概念做了简要介绍,同时给出了算法调用的API,现在我们开始算法检测接口实现源码的分析。 1. 斑点的分组与加权 这里我们选择后者,先了解算法的处理流程,再分析各个模块的实现。算法流程图如下图所示,上一…...
网线制作(双绞线+水晶头)——T568B标准
参考视频:https://www.bilibili.com/video/BV1KQ4y1i7zP/ 1、使用剥线器 2、将线捋顺、排序、剪掉牵引线 记忆技巧 1.线序颜色整体是一浅一深 2.颜色顺序是黄、蓝、绿、棕 一个黄种人、从上向下看,分别看到的是蓝天、青草(绿)、泥土(棕色) 3.中间两根浅…...
湖南源点(市场研究咨询)如何产出更加有意义的竞品调研
湖南源点咨询认为:当前,任何项目都不能盲目开始,前期的准备工作必不可少。在基础架构搭建的同时,设计上对于前端功能、用户体验的调研就优先开始了。在这个阶段,大部分设计师都会分配很多调研任务,疯狂对竞…...
Qt/C++音视频开发76-获取本地有哪些摄像头名称/ffmpeg内置函数方式
一、前言 上一篇文章是写的用Qt的内置函数方式获取本地摄像头名称集合,但是有几个缺点,比如要求Qt5,或者至少要求安装了多媒体组件multimedia,如果没有安装呢,或者安装的是个空的呢,比如很多嵌入式板子&am…...
09 platfrom 设备驱动
platform 设备驱动,也叫做平台设备驱动。请各位重点学习! 1、驱动的分离与分层 1)驱动的分隔与分离 Linux 操作系统,代码的重用性非常重要。驱动程序占用了 Linux 内核代码量的大头,如果不对驱动程序加以管理,用不了多久 Linux 内核的文件数量就庞大到无法接受的地步。…...
【C#】C#读写Excel文件
1.工具库选择 使用EPPlus读取Excel文件,在visual studio2022中安装最新NuGet。 2.读文件测试 using OfficeOpenXml; using OfficeOpenXml.Packaging.Ionic.Zip; using OfficeOpenXml.Style; using System; using System.Collections.Generic; using System.IO; u…...
数据流图(DFD)绘制规范
软件数据流图(Data Flow Diagram,DFD)是一种重要的工具,用于表示系统中数据的流动和处理。DFD帮助开发团队和利益相关者理解系统的功能和数据处理过程。绘制DFD时应遵循一定的规范和步骤,以确保图表的清晰性和一致性。…...
有待挖掘的金矿:大模型的幻觉之境
人工智能正在迅速变得无处不在,在科学和学术研究中,自回归的大型语言模型(LLM)走在了前列。自从LLM的概念被整合到自然语言处理(NLP)的讨论中以来,LLM中的幻觉现象一直被广泛视为一个显著的社会…...
做网站高流量赚广告费/北京seo优化方案
概述 什么是分库分表 数据数量是不可控的,随着时间和业务发展,造成表里面数据越来越多,如果再去对数据库表CURD操作时,就会有性能问题。 解决方案 为了解决由于数据量过大而造成数据库性能降低问题,主要有下面两种…...
网上虚拟银行注册网站/营销活动有哪些
对于刚接触linux系统的学员来说,确实是一件比较困难的事情,造成这种局面主要原因之一是windows的设计考虑到用户的体验效果,提供了更好的用户操作效果。以至于用户接触的最多的系统,所以刚接触linux的时候会感觉很不适应ÿ…...
wordpress整体搬家/自媒体seo优化
基于MPP框架开发了demo展示应用,方案数据流如下图所示,简单说明一下. 1.支持一路sensor输入,四路输出. 2.第一路VIPP0输出YUV大小为1920*1080. 编码为H264main profile大小的压缩BitStream存盘。 3.第二路预览,源分辨率1920*10…...
管理公司网站建设/推广引流哪个软件最好
作为一名大数据领域的从业者,我来回答一下这个问题。在大数据技术的推动下,随着数据价值的不断提高,关于个人隐私的安全问题受到了更多的关注,关于如何在大数据时代保护个人隐私(数据安全)也是目前不少研究生的研究课题。大数据…...
基于aws ec2免费实例进行网站建设/企业seo关键词优化
2019独角兽企业重金招聘Python工程师标准>>> 当反向跟踪(Trackback )被启用后,在任何你链接到可用启用自动发现功能的外部页面中,Confluence 将会自动发送一个方向跟踪 ping,这个 ping 能通知链接的页面有了…...
wordpress怎么提速/百度秒收录排名软件
这么久没有写博客了,今天给大家分享一些多file文件的操作。一般可以用到清理垃圾获取文件大小 删除文件等操作,可以直接用于工具类里面,直接做操作便可以public final class FileUtils { public static long fileLen 0;public static void d…...