C++——string

一学习string的原因

1.从个人理解角度上:

在刚开始学习之前,我只知道学习完string在以后的刷题中能提高做题效率,在对字符串的处理string库中也许有对应的接口去实现需求,不用自己去写函数的实现。

但在学string中改变了之前的看法:不仅是要会用接口,而且在理解了接口的底层原理后能更好的去理解,使用它。

总结:使用——明理——扩展

2从C语言上:

C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

二标准库中的string

使用string必须用它对应的头文件:#include<string>

在学习接口及其文档的说明,可以到cpulspuls官网中去学习:

cplusplus.com - The C++ Resources Network

1(拷贝)构造和析构

string()     构造string类的空字符串(其中有’\0‘)

string(char* s)   构造的同时进行string的拷贝(支持单参数隐式类型转换)

string(const string& str)     string拷贝构造

string(const string& str , size_t  pos , size_t  len = npos)     进行str子串的获取,pos是子串的起始位置,len是子串的结束位置(没有说明就默认是str的结束位置)

~string()     string的析构

2运算符重载

使string的访问向数组访问数据一样数组名+[]

char& operator[] (size_t pos)     

const char& operator[] (size_t pos) const   

 string类的赋值,对象可以是string,字符串,字符

string& operator = (const string& str)   

string& operator = (const char* s)

string& operator = (char c)

string类字符串的尾插,对象可以是string,字符串,字符

string& operator += (const string& str)

string& operator += (const char*s)

string& operator += (char c)

实现string类与char*,char类型的字符(串)进行拼接(反过来也成立) 

string operator+ (const string& lhs , const char* rhs)

string operator+ (const char* lhs , const string& rhs)

string operator+ (const string& lhs , char rhs)

string operator+ (char rhs ,  const string& lhs)

流插入,流提取的重载

istream& operator >>(istream is , string& str)

ostream& operator <<(ostream os , string& str)

3迭代器

迭代器行为指针一样,但不=指针

iterator begin()     指向string的开始 

const_iterator begin() const   

iterator end()      指向string的末尾

const_iterator end() const

反向迭代器

iterator rbegin()     指向string的末尾

irerator rend()        指向string的开始

有了迭代器,我们就有了两种遍历string的方式:迭代器与范围for(本质是迭代器)

#include<string>
int main()
{string s1("hello warld");string::iterator it = s1.begin();while (it != s1.end()){cout << *it << ' ';it++;}cout << endl;for (auto ch : s1){cout << ch << ' ';}cout << endl;return 0;
}

2查询string的各种数据

size_t size() const     返回string内的字符个数(不包含’\0‘)      =size_t length() const

size_t capacity() const     返回string的空间大小(包含’\0‘)

void reserve(size_t n=0)   开n个空间大小

(知道要插入的多少数据提前开好空间就不用进行扩容,提高了效率)

(但空间不够时,string应该要进行对应的空间扩容。那么是要扩容多少呢?2倍扩?

我们用+=的方式在string末尾每次插入一个字符,循环100次来观察capacity的变化:

#include<string>
int main()
{string s;size_t sz = s.capacity();cout << "capacity changed: " << sz << '\n';cout << "making s grow:\n";for (int i = 0; i < 100; ++i){s += ('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed: " << sz << '\n';}}return 0;
}

在VS底层中实现的扩容:先开出15内存空间,等到空间不够时,第一次扩容是2倍扩,接下来的扩容都是大概按1.5来扩容。

而在g++下的扩容全是按照2倍扩容来的:

但两者的扩容方式不同会不会有什么影响呢?

没有!! 2倍扩容也好1.5倍扩容也好,说到底它们的目标都是要进行扩容。实现起来的细节是不做考虑的。


void resize(size_t n,char c)     开n个空间大小并插入n-size()个字符c

resize一般不缩容,在以下的不同情况使用resize会有不同的效果:

5增删查改

viod push_back (char c)     在string的末尾插入一个字符

void pop_back (char c)       在string的末尾删除一个字符        

string& insert(size_t pos , char c)     在pos下插入字符(字符串,string)

string& erase(size_t pos , size_t len = npos)     在pos位置下删除len个字符(不加len默认删除pos后面的全部字符)  (左闭右开)

void swap(string& str)   不仅仅是数据的交换,还有size,capacity的交换

6其它操作

void swap(string& x , string& y)     与算法库的swap分离开(如果调用算法库的swap,三次拷贝+一次析构代价太大)

const char* c_str() const     类型转换成char*方便打印(string类的要用到运算符重载)

string substr(size_t pos = 0 , size_t len = npos)     从pos位置到len个位置的字符串截取

size_t find(char c , size_t pos=0)   返回字符c所在的下标

string& replace(size_t pos , size_t len = npos , char c)     在pos到len的位置插入c字符

两者的特性结合可用来解决:

字符串空格的替换

三string的模拟实现

在string类中共有三个成员:_str(字符串),_size(字符个数),_capacity(空间大小)

其中,_size个数不包含‘\0’,但在_capacity中要多开出一个空间存储‘\0’!!

3.1成员函数

3.1.1构造函数

在实现构造时,如果string构造不传参,默认为空串。

但不意味着给缺省值时就是”\0“,因为写成”“是有’\0‘的存在的

//string(const char* str = "\0")
string(const char* str = ""):_size(strlen(str))
{_capacity = _size;_str = new char[_size + 1];strcpy(_str, str);//把字符串拷贝给_str成员对象}

3.1.2拷贝构造 

 拷贝构造里不单单只是数据拷贝!要在拷贝之前先new一块跟str一样长的空间,在进行数据的拷贝。也就是所谓的深拷贝!

一般的思路是:直接开出一个与拷贝对象一样长的空间,再把对应的数据赋值过去就完事了

string(const string& str)
{_str = new char[str._capacity + 1];strcpy(_str, str._str);_size = str._size;_capacity = str._capacity;
}

但这种属于是’自己买菜自己做‘。是比较传统的写法。

有这样的写法:构造一个与拷贝对象一样的临时对象,在进行交换(深拷贝),比较方便简洁:

string(const string& str)
{string tmp(str.c_str());swap(tmp);
}

 有了拷贝构造,与它对应的还有一个赋值运算符的重载:也是类似的道理:

string& operator=(const string& str)
{char* tmp = new char[str._capacity + 1];strcpy(tmp, str._str);delete[] _str;//释放_str = tmp;_size = str._size;_capacity = str._capacity;return *this;
}//现代写法
string& operator=(const string& str)
{string tmp(str.c_str());swap(tmp);return *this;
}string& operator=(string ss)
{    swap(ss);return *this;
}

3.1.3析构函数

~string()
{delete[] _str;_str = nullptr;_size = _capacity = 0;
}

3.2迭代器

实现的迭代器因为要支持可读可写与只读两个版本,实现时要实现俩个版本出来:

对应的begin(),end()实现成string类中的成员函数

typedef char* iterator;//类似指针的作用
typedef const char* const_iterator;
const_iterator begin() const
{return _str;
}
const_iterator end() const
{return _str + _size;
}iterator begin()
{return _str;
}
iterator end()
{return _str + _size;
}

3.3扩容

传参进来的n如果比_capacity要小则需要进行空间的扩容到n+1(’\0‘要开给它):

void reserve(size_t n)
{//扩容if (_capacity < n){char* tmp = new char[n + 1];strcpy(tmp , _str);_str = tmp;_capacity = n;}
}

它的扩容不是我们在C语言学的函数realloc扩容那样有两种情况:原地扩与异地扩。它的扩容就是直接看出一块新的空间,在把_str的数据拷贝的! 

3.4插入字符(串)

3.4.1append

将原来的_capacity与拼接形成新的string的_size个数进行比较,空间不够才进行扩容:

void append(const char* s)
{size_t len = strlen(s);//扩容if (_capacity < _size + len){reserve(_size + len);}/*for (size_t i = _size; i < len; i++){_str[i] = *s;s++;}*/strcpy(_str +_size, s);_size += len;
}

3.4.2insert

在pos位置上插入字符也好,字符串也好,都需要进行是否扩容与数据挪动,字符串的挪动必须是从后往前进行字符串的覆盖:

void insert(size_t pos, char ch)
{assert(pos <= _size);if (_capacity == _size){//扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}size_t end=_size;while (end>=pos){_str[end+1] = _str[end];end--;}_str[pos] = ch;_size += 1;
}

但在这有个细节:如果pos的位置是0即进行头插,这将会进行程序出现问题:因为但end=0循环进入,end--使得end=-1。但end的类型是size_t,不会为负数!修改方式有两种:

1修改类型;2让end=_size+1进行循环时end永远都>pos:

	void insert(size_t pos, char ch){assert(pos <= _size);if (_capacity == _size){//扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}1size_t end = _size;//当pos=0时,size_t end=0,end--!=-1int end = _size;while (end >= (int)pos){_str[end + 1] = _str[end];end--;2size_t end = _size + 1;while (end>pos){_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size += 1;}

插入的是字符串也是同理的:

		void insert(size_t pos, const char* str){size_t len = strlen(str);assert(pos <= _size);if (_capacity <= _size + len){//扩容reserve(_size + len);}/*int end = _size;while (end >= (int)pos){_str[end + len] = _str[end];end--;}*/size_t end = _size + len;while (end > pos+len-1){_str[end] = _str[end-len];end--;}strncpy(_str+pos, str, len);_size += len;}

 3.4.3push_back

复用insert进行尾插或者直接实现:

void push_back(char ch)
{if (_capacity == _size){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size++] = ch;_str[_size] = '\0';//insert(_size, ch);
}

3.4.4赋值运算符=重载

string& operator+=(char ch)
{push_back(ch);return *this;
}
string& operator+=(const char* str)
{append(str);return *this;
}

3.5resize

实现resize是要了解的是:使用resize一般不缩容。要插入n个字符是有两种情况:n<=_size是仅需保留前n个字符串后加’\0‘即可;n>_capacity就要进行扩容与插入n-_size个字符:

		void resize(size_t n, char ch = npos){if (n <= _size){_str[n] = '\0';_size = n;}else{//扩容reserve(n);//n>size后面有要求加字符for (size_t i = _size; i < n; i++){_str[i] = ch;}_str[n] = '\0';_size = n;}}

对应resize与reserve:基本上都是有扩容的功能的,但resize能在进行扩容的基础上将数据进行初始化,比较适合在对数据的管理上使用它。

3.6find

进行string的遍历,如果找到该字符就返回该字符的下标:如果是找字符串,找到了就返回该字符串的起始位置:

size_t find(char c, size_t pos = 0) const
{assert(pos < _size);for (size_t i = pos; i < _size; i++){if (c == _str[i]){return i;}}return npos;
}
size_t find(const char* s, size_t pos = 0) const
{assert(pos < _size);const char* p=strstr(_str + pos, s);if(p){return p - _str;//指针-指针=s的下标}else{return npos;}
}

 3.7运算符重载<<,>>

流提取或者是流插入重载成全局函数好方便调用:

ostream& operator<< (ostream& os, const string& str)
{for (int i = 0; i < str.size(); i++){os << str[i];}return os;
}istream& operator>>(istream& in, string& s)
{s.clear();//防止string中有数据影响流插入char ch;//in >> ch;ch = in.get();//s.reserve(128);while (ch != '\n' && ch != ' '){s += ch;ch = in.get();}return in;
}

在重载流插入时,如果按照上面的实现方式的话,在每次插入时都要进行扩容,非常影响程序运行的效率。

如果要进行reserve开空间,但至于要看多少不能确定。所以就有人进行对这段代码的优化: 

istream& operator>>(istream& in, string& s)
{s.clear();char ch;//in >> ch;ch = in.get();char buff[128];size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;// [0,126]if (i == 127){buff[127] = '\0';s += buff;i = 0;}ch = in.get();}if (i > 0){buff[i] = '\0';s += buff;}return in;
}

要不要扩容取决于会不会超出buff的数组总个数,非常的妙!!!

完整源代码

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<assert.h>
#include<iostream>
using namespace std;
namespace bit
{class string{public://迭代器typedef char* iterator;//类似指针的作用typedef const char* const_iterator;const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}iterator begin(){return _str;}iterator end(){return _str + _size;}//在末尾加n个ch字符void resize(size_t n, char ch = npos){if (n <= _size){_str[n] = '\0';_size = n;}else{//扩容reserve(n);//n>size后面有要求加字符for (size_t i = _size; i < n; i++){_str[i] = ch;}_str[n] = '\0';_size = n;}}//先开空间void reserve(size_t n){//扩容if (_capacity < n){char* tmp = new char[n + 1];strcpy(tmp, _str);_str = tmp;_capacity = n;}}//末尾插人字符void push_back(char ch){if (_capacity == _size){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size++] = ch;_str[_size] = '\0';//insert(_size, ch);}//末尾插入字符串void append(const char* s){size_t len = strlen(s);//扩容if (_capacity < _size + len){reserve(_size + len);}/*for (size_t i = _size; i < len; i++){_str[i] = *s;s++;}*/strcpy(_str +_size, s);_size += len;}string& operator+=(char ch){push_back(ch);return *this;}string& operator+=(const char* str){append(str);return *this;}//在pos位置插入字符void insert(size_t pos, char ch){assert(pos <= _size);if (_capacity == _size){//扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}//size_t end = _size;//当pos=0时,size_t end=0,end--!=-1/*int end = _size;while (end >= (int)pos){_str[end + 1] = _str[end];end--;}*/size_t end = _size + 1;//size-1Xwhile (end>pos){_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size += 1;}void insert(size_t pos, const char* str){size_t len = strlen(str);assert(pos <= _size);if (_capacity <= _size + len){//扩容reserve(_size + len);}/*int end = _size;while (end >= (int)pos){_str[end + len] = _str[end];end--;}*/size_t end = _size + len;while (end >= pos+len){_str[end] = _str[end-len];end--;}strncpy(_str+pos, str, len);_size += len;}//删除pos位置的字符void erase(size_t pos, int len = npos){assert(pos <= _size);if (len == npos || len >= _size - pos)//len+pos会溢出{_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}}//string(const char* str = "\0")string(const char* str = ""):_size(strlen(str)){_capacity = _size;_str = new char[_size + 1];strcpy(_str, str);//把字符串拷贝给_str成员对象}//传统写法//s2(s1)//string(const string& str)//{//	_str = new char[str._capacity + 1];//	strcpy(_str, str._str);//	_size = str._size;//	_capacity = str._capacity;//}//s2=s1//string& operator=(const string& str)//{//	char* tmp = new char[str._capacity + 1];//	strcpy(tmp, str._str);//	delete[] _str;//置空//	_str = tmp;//	_size = str._size;//	_capacity = str._capacity;// return *this;//}//现代写法string(const string& str){string tmp(str.c_str());swap(tmp);}string& operator=(string str){swap(str);return *this;}~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}const char* c_str() const{return _str;}size_t size() const{return _size;}size_t capacity() const{return _capacity;}char& operator[](size_t pos){assert(pos <= _size);return _str[pos];}const char& operator[](size_t pos) const{assert(pos <= _size);return _str[pos];}void clear(){_size = 0;_str[_size] = '\0';}//string的成员函数void swap(string& str){//共有三种swap使用:算法,string.swap,swapstd::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}bool empty()const{if (_size == 0){return true;}return false;}size_t find(char c, size_t pos = 0) const{assert(pos < _size);for (size_t i = pos; i < _size; i++){if (c == _str[i]){return i;}}return npos;}size_t find(const char* s, size_t pos = 0) const{assert(pos < _size);const char* p=strstr(_str + pos, s);if(p){return p - _str;//指针-指针=s的下标}else{return npos;}}string substr(size_t pos = 0, size_t len = npos) const{string s;if (len >= _size-pos){for (size_t i = pos; i < _size; i++){s += _str[i];}}else{for (size_t i = pos; i < pos + len; i++){s += _str[i];}}return s;}private:char* _str;size_t _size;size_t _capacity;public:static const int npos;//类中共有的对象};const int string::npos = -1;bool operator==(const string& s1,const string& s2){return strcmp(s1.c_str(), s2.c_str()) == 0;}bool operator<(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) < 0;}bool operator>(const string& s1, const string& s2){return !(strcmp(s1.c_str(), s2.c_str()) == 0 || strcmp(s1.c_str(), s2.c_str()) < 0);}//重载成全局函数ostream& operator<< (ostream& os, const string& str){for (int i = 0; i < str.size(); i++){os << str[i];}return os;}istream& operator>> (istream& is, string& str)//getline的实现方式	{str.clear();char ch = is.get();char buffer[128];size_t i = 0;while (ch != ' ' && ch != '\n'){//str += ch;buffer[i++] = ch;if (i == 127){buffer[127] = '\0';//开128个空间str += buffer;//重新计算i = 0;}ch = is.get();}if (i > 0){//有多少看多少buffer[i] = '\0';str += buffer;}return is;}/*istream& operator>> (istream& is, string& str){str.clear();char ch = is.get();while(ch != ' ' && ch != '\n'){str += ch;ch = is.get();}return is;}*///定义一个全局的swap就不会去调用算法的swapvoid swap(string& s1,string& s2){s1.swap(s2);}

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

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

相关文章

【PyTorch】基础学习:一文详细介绍 torch.save() 的用法和应用

【PyTorch】基础学习&#xff1a;一文详细介绍 torch.save() 的用法和应用 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f44…

Flask中的Blueprints:模块化和组织大型Web应用【第142篇—Web应用】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 Flask中的Blueprints&#xff1a;模块化和组织大型Web应用 在构建大型Web应用时&#xff0…

最后的挣扎 - Qt For Android on HuaWei Mate 60Pro (v4.0.0)

简介 为什么叫最后的挣扎, 其实都知道即将到来的 HarmonyOS NEXT 将抛弃Android支持&#xff0c;纯血HarmonyOS 将上线&#xff0c; 此时再说Qt for android支持Huawei HarmonyOS的设备其实并没有多少意思&#xff0c; 但恐怕在大多数基础软件完成兼容前&#xff0c; 很多人还是…

【PyTorch】基础学习:一文详细介绍 torch.load() 的用法和应用

【PyTorch】基础学习&#xff1a;一文详细介绍 torch.load() 的用法和应用 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f44…

UCORE 清华大学os实验 lab0 环境配置

打卡 lab 0 &#xff1a; 环境配置 &#xff1a; 首先在ubt 上的环境&#xff0c;可以用虚拟机或者直接在windows 上面配置 然后需要很多工具 如 qemu gdb cmake git 就是中间犯了错误&#xff0c;误以为下载的安装包&#xff0c;一直解压不掉&#xff0c;结果用gpt 检查 结…

LeetCode 189.轮转数组

题目&#xff1a;给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 思路&#xff1a; 代码&#xff1a; class Solution {public void rotate(int[] nums, int k) {int n nums.length;k k % n;reverse(nums, 0, n);revers…

sqlite 常见命令 表结构

在 SQLite 中&#xff0c;将表结构保存为 SQL 具有一定的便捷性和重要性&#xff0c;原因如下 便捷性&#xff1a; 备份和恢复&#xff1a;将表结构保存为 SQL 可以方便地进行备份。如果需要还原或迁移数据库&#xff0c;只需执行保存的 SQL 脚本&#xff0c;就可以重新创建表…

vulhub中GitLab 任意文件读取漏洞复现(CVE-2016-9086)

GitLab是一款Ruby开发的Git项目管理平台。在8.9版本后添加的“导出、导入项目”功能&#xff0c;因为没有处理好压缩包中的软连接&#xff0c;已登录用户可以利用这个功能读取服务器上的任意文件。 环境运行后&#xff0c;访问http://your-ip:8080即可查看GitLab主页&#xff0…

Linux进程管理:(六)SMP负载均衡

文章说明&#xff1a; Linux内核版本&#xff1a;5.0 架构&#xff1a;ARM64 参考资料及图片来源&#xff1a;《奔跑吧Linux内核》 Linux 5.0内核源码注释仓库地址&#xff1a; zhangzihengya/LinuxSourceCode_v5.0_study (github.com) 1. 前置知识 1.1 CPU管理位图 内核…

深度强化学习01

Random variable Probability Density Function 期望 Random Sampling 学习视频 这绝对是我看过最好的深度强化学习&#xff01;从入门到实战&#xff0c;7小时内干货不断&#xff01;_哔哩哔哩_bilibili

智慧城市新篇章:数字孪生的力量与未来

随着信息技术的迅猛发展和数字化浪潮的推进&#xff0c;智慧城市作为现代城市发展的新模式&#xff0c;正在逐步改变我们的生活方式和社会结构。在智慧城市的构建中&#xff0c;数字孪生技术以其独特的优势&#xff0c;为城市的规划、管理、服务等方面带来了革命性的变革。本文…

Mybatis-xml映射文件与动态SQL

xml映射文件 动态SQL <where><if test"name!null">name like concat(%,#{name},%)</if><if test"username!null">and username#{username}</if></where> <!-- collection&#xff1a;遍历的集合--> <!-- …

百科源码生活资讯百科门户类网站百科知识,生活常识

百科源码生活资讯百科门户类网站百科知识,生活常识 百科源码安装环境 支持php5.6&#xff0c;数据库mysql即可&#xff0c;需要有子目录权限&#xff0c;没有权限的话无法安装 百科源码可以创建百科内容&#xff0c;创建活动内容。 包含用户注册&#xff0c;词条创建&#xff…

Flask学习(四):路由转换器

默认的路由转换器&#xff1a; string &#xff08;缺省值&#xff09; 接受任何不包含斜杠的文本int接受正整数float接受正浮点数 path类似 string&#xff0c;但可以包含斜杠uuid接受 UUID 字符串 代码示例&#xff1a; app.route(/user/<username>) def show_u…

使用Python进行自然语言处理(NLP):NLTK与Spacy的比较【第133篇—NLTK与Spacy】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 使用Python进行自然语言处理&#xff08;NLP&#xff09;&#xff1a;NLTK与Spacy的比较 自…

用尾插的思想实现移除链表中的元素

目录 一、介绍尾插 1.链表为空 2.链表不为空 二、题目介绍 三、思路 四、代码 五、代码解析 1. 2. 3. 4. 5. 6. 六、注意点 1. 2. 一、介绍尾插 整体思路为 1.链表为空 void SLPushBack(SLTNode** pphead, SLTDataType x) {SLTNode* newnode BuyLTNode(x); …

蓝桥杯并查集|路径压缩|合并优化|按秩合并|合根植物(C++)

并查集 并查集是大量的树&#xff08;单个节点也算是树&#xff09;经过合并生成一系列家族森林的过程。 可以合并可以查询的集合的一种算法 可以查询哪个元素属于哪个集合 每个集合也就是每棵树都是由根节点确定&#xff0c;也可以理解为每个家族的族长就是根节点。 元素集合…

【开源鸿蒙】模拟运行OpenHarmony轻量系统QEMU RISC-V版

文章目录 一、准备工作1.1 编译输出目录简介 二、QEMU安装2.1 安装依赖2.2 获取源码2.3 编译安装2.4 问题解决 三、用QEMU运行OpenHarmony轻量系统3.1 qemu-run脚本简介3.2 qemu-run脚本参数3.3 qemu-run运行效果3.4 退出QEMU交互模式 四、问题解决五、参考链接 开源鸿蒙坚果派…

YOLOv8改进 | 图像去雾 | 门控可微分图像处理GDIP模块改善物体低照度检测检测(适用于图片不清晰等一切场景,全网独家首发)

一、本文介绍 本文给大家带来的改进机制是门控可微分图像处理GDIP模块&#xff0c;其可以理解为是一直图像增强领域的模块&#xff0c;其主要适用于雾天的一些去雾检测&#xff0c;当然了也适用于于一些图片模糊不清的场景&#xff0c;GDIP&#xff08;Gated Differentiable Im…

论文阅读——EarthPT

EarthPT: a time series foundation model for Earth Observation 一个Earth Observation (EO)预训练的Transformer。EarthPT是一个7亿参数解码Transformer基础模型&#xff0c;以自回归自监督方式进行训练&#xff0c;并专门针对EO用例进行开发。我们证明了EarthPT是一个有效的…