C++ ——string的模拟实现

目录

前言

浅记

1. reserve(扩容) 

2. push_back(尾插) 

3. iterator(迭代器)

4. append(尾插一个字符串)

5. insert 

5.1 按pos位插入一个字符

5.2 按pos位插入一个字符串

6. erase 

7. find

7.1 查找字符

7.2 查找字符串

8. substr 

 代码汇总

string.h

string.cpp


前言

        C++ —— 关于string类-CSDN博客icon-default.png?t=O83Ahttps://blog.csdn.net/hedhjd/article/details/142023625?spm=1001.2014.3001.5501


浅记

char* _str;字符串存储空间首地址指针
size_t _size; 当前存储的有效数据个数
size_t _capacity;可用容量

*
_str:指向字符串存放的空间的指针
_size:当前存储的有效数据个数 ,指向最后一个字符的下一个位置
_capacity:代表当前可存储的最大容量
nops:此值设置为 -1,无符号整型转换就是42亿,且此值为const和静态参数具有全局效应,某些函数设置其为缺省参数

 


1. reserve(扩容) 

void string::reserve(size_t n)
{//如果字符串存储的数据大于容量if (n > _capacity){//cout << "reserve:" << n << endl;//申请新空间赋给临时变量tmp  + 1是位\0申请的空间char* tmp = new char[n + 1];//把数据拷贝到临时变量里strcpy(tmp, _str);//释放旧空间delete[] _str;//指向新空间_str = tmp;//字符串存储的数据等于容量_capacity = n;}
}


2. push_back(尾插) 

//尾插
void string::push_back(char ch)
{//如果当前的有效数据个数和最大容量相等 if (_size == _capacity){//那么扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}//因为size指向最后一个字符的下一个位置,所以直接插入_str[_size] = ch;++_size;//最后要加一个\0,不然会乱码_str[_size] = '\0';
}

先判断是否还有剩余空间如果满了就进行扩容操作。扩容后在_size位置放上我们要插入的字符,然后++_size,最后在_size的后一个位置补上'\0',防止乱码


3. iterator(迭代器)

const size_t string::npos = -1;string::iterator string::begin()
{return _str;
}string::iterator string::end()
{return _str + _size;
}string::const_iterator string::begin() const
{return _str;
}string::const_iterator string::end() const
{return _str + _size;
}

 


4. append(尾插一个字符串)

//尾插一个字符串//_str:指向字符串存放的空间的指针//_size:当前存储的有效数据个数, 指向最后一个字符的下一个位置void string::append(const char* str){//先计算要插入的字符长度,将值赋给临时变量lensize_t len = strlen(str); //如果当前存储的有效数据个数 加上 要插入的字符 大于 容量if (_size + len > _capacity){// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}//将目标地址到\0的位置中间的值拷贝过去strcpy(_str + _size, str);//尾插_size += len;}

如果尾插后的字符串所需空间大于现有空间就扩容,然后使用strcpy函数将需要尾插的字符串从_str + _size的位置开始拷贝,最后插入len即可


5. insert 

5.1 按pos位插入一个字符

//按pos位插入一个字符
void string::insert(size_t pos, char ch)
{assert(pos <= _size);//如果当前的有效数据个数和最大容量相等 if (_size == _capacity){//那么扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}// 挪动数据//_size + 1:\0的后一位//把end指向\0的后一位size_t end = _size + 1;//循环将pos之后的数据都向后挪动一位while (end > pos){_str[end] = _str[end - 1];--end;}//将字符ch放入pos位_str[pos] = ch;++_size;
}

先判断是否需要扩容,然后定义一个end指向'\0'的下一个位置,然后将pos之后的数据都向后挪动一位,最后将字符ch放入pos位

5.2 按pos位插入一个字符串

//按pos位插入一个字符串
void string::insert(size_t pos, const char* str)
{assert(pos <= _size);//先计算要插入的字符长度,将值赋给临时变量lensize_t len = strlen(str);//如果当前存储的有效数据个数 加上 要插入的字符 大于 容量if (_size + len > _capacity){// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}//定义一个end指向_size + len的位置上size_t end = _size + len;//通过循环把pos后的len个数据向后挪动len个位置while (end > pos + len - 1){_str[end] = _str[end - len];--end;}// 这里不能用 strcpy 会把 '\0' 拷贝过来//使用memcpy函数进行拷贝的原因是memcpy函数不会自动补上'\0'// 而strcpy函数会在拷贝后自动补上'\0’,//把str里的len个数据拷贝到_str + pos里memcpy(_str + pos, str, len);//插入字符串_size += len;
}

 先计算要插入的字符长度,将值赋给临时变量len,判断是否需要扩容,然后定义一个end指向_size + len 的位置。通过循环来控制将pos后的len个数据向后挪动len个位置,然后使用memcpy函数把str里的len个数据拷贝到_str + pos里


6. erase 

//从pos位置开始删除长度为的len的字符串
//_str:指向字符串存放的空间的指针
//_size:当前存储的有效数据个数, 指向最后一个字符的下一个位置
void string::erase(size_t pos, size_t len)
{//判断是否会越界assert(pos < _size);//如果要删除的字符  大于等于  当前存储的有效数据个数 减去 当前指向数据的位置if (len >= _size - pos){//直接将pos位置置为\0_str[pos] = '\0';_size = pos;}//如果要删除的字符  小于  当前存储的有效数据个数减去当前指向数据的位置else{//将_str + pos + len(要保留的数据)位置的字符串直接拷贝到_str + pos(要删除的数据)位置直接覆盖掉strcpy(_str + pos, _str + pos + len);_size -= len;}
}

 先进行判断len是否大于等于pos后面的元素个数,如果大于等于的话,就将pos位及其之后的元素全部删除,直接将pos位置置为'\0',然后将有效数据个数置为pos

如果len小于pos后面的元素个数的话,就将_str + pos + len位置的字符串直接拷贝到_str + pos位置,直接将要删除的那len个元素覆盖,最后有效数据更新即可


7. find

7.1 查找字符

//查找字符//查找对应的字符,返回对应的下标size_t string::find(char ch, size_t pos){assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}


7.2 查找字符串

strstr:在一个字符串中查找另一个字符串 ,返回子串在原串里第一个出现的位置
str1:原串       str2:子串
const char * strstr ( const char * str1, const char * str2 );


size_t string::find(const char* str, size_t pos)
{assert(pos < _size);//通过strstr函数来将str作为子串找到它的地址const char* ptr = strstr(_str + pos, str);//匹配失败if (ptr == nullptr){return npos;}else//匹配成功{//ptr的地址减去_str的地址就是我们要找的字符串的起始位置的下标return ptr - _str;}
}

通过strstr函数来将str作为子串找到它的地址,然后sub的地址减去_str的地址就是我们要找的字符串的起始位置的下标


8. substr 

//从pos位置开始截取长度为len的字符再构造一个子串,子串返回
string string::substr(size_t pos, size_t len)
{assert(pos < _size);// 如果len大于剩余字符长度if (len > _size - pos){//把len更新成为一个有效的长度,有多少长度取多少空间len = _size - pos;}//构造一个子串substring sub;//先给sub预留len个空间sub.reserve(len);//for循环遍历要截取的字符for (size_t i = 0; i < len; i++){//将从pos位置开始长度为len的字符尾插到sub中sub += _str[pos + i];}return sub;
}

先判断len是否大于剩余字符的长度,如果len大于剩余字符的长度就把len更新成为一个有效的长度,有多少长度取多少空间,然后再构造一个子串sub,先给sub预留len个空间,然后通过遍历将从pos位置开始长度为len的字符尾插到sub中最后直接返回sub 


 代码汇总

string.h

 

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once#include<iostream>
#include<string>
#include<assert.h>
using namespace std;namespace bit
{class string{public:typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}/*string():_str(new char[1]{'\0'}),_size(0),_capacity(0){}*/// 短小频繁调用的函数,可以直接定义到类里面,默认是inlinestring(const char* str = ""){_size = strlen(str);// _capacity不包含\0_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}// 深拷贝问题// // s2(s1)string(const string& s){_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}// s2 = s1// s1 = s1string& operator=(const string& s){if (this != &s){delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;}~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}const char* c_str() const{return _str;}//将字符串的内容清空void clear(){_str[0] = '\0';_size = 0;}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 reserve(size_t n);void push_back(char ch);void append(const char* str);string& operator+=(char ch);string& operator+=(const char* str);void insert(size_t pos, char ch);void insert(size_t pos, const char* str);void erase(size_t pos, size_t len = npos);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);string substr(size_t pos = 0, size_t len = npos);private: //设置私有,不允许随便访问底层数据char* _str;//字符串存储空间首地址指针size_t _size; //当前存储的有效数据个数size_t _capacity;//可用容量//static const size_t npos = -1;static const size_t npos;/*_str:指向字符串存放的空间的指针_size:当前存储的有效数据个数 ,指向最后一个字符的下一个位置_capacity:代表当前可存储的最大容量nops:此值设置为 -1,无符号整型转换就是42亿,且此值为const和静态参数具有全局效应,某些函数设置其为缺省参数*/};bool operator<(const string& s1, const string& s2);bool operator<=(const string& s1, const string& s2);bool operator>(const string& s1, const string& s2);bool operator>=(const string& s1, const string& s2);bool operator==(const string& s1, const string& s2);bool operator!=(const string& s1, const string& s2);ostream& operator<<(ostream& out, const string& s);istream& operator>>(istream& in, string& s);
}


string.cpp

 

#include"string.h"//char* _str;字符串存储空间首地址指针
//size_t _size; 当前存储的有效数据个数
//size_t _capacity;可用容量
//static const size_t npos = -1;
/*_str:指向字符串存放的空间的指针
_size:当前存储的有效数据个数 ,指向最后一个字符的下一个位置
_capacity:代表当前可存储的最大容量
nops:此值设置为 -1,无符号整型转换就是42亿,且此值为const和静态参数具有全局效应,某些函数设置其为缺省参数*/namespace bit
{const size_t string::npos = -1;//扩容void string::reserve(size_t n){//如果字符串存储的数据大于容量if (n > _capacity){//cout << "reserve:" << n << endl;//申请新空间赋给临时变量tmp  + 1是位\0申请的空间char* tmp = new char[n + 1];//把数据拷贝到临时变量里strcpy(tmp, _str);//释放旧空间delete[] _str;//指向新空间_str = tmp;//字符串存储的数据等于容量_capacity = n;}}//尾插void string::push_back(char ch){//如果当前的有效数据个数和最大容量相等 if (_size == _capacity){//那么扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}//因为size指向最后一个字符的下一个位置,所以直接插入_str[_size] = ch;++_size;//最后要加一个\0,不然会乱码_str[_size] = '\0';}//尾插一个字符串//_str:指向字符串存放的空间的指针//_size:当前存储的有效数据个数, 指向最后一个字符的下一个位置void string::append(const char* str){//先计算要插入的字符长度,将值赋给临时变量lensize_t len = strlen(str);//如果当前存储的有效数据个数 加上 要插入的字符 大于 容量if (_size + len > _capacity){// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}//将目标地址到\0的位置中间的值拷贝过去strcpy(_str + _size, str);//尾插_size += len;}//尾插一个字符string& string:: operator+=(char ch){push_back(ch);return *this;}//尾插一个字符串string& string::operator+=(const char* str){append(str);return *this;}//按pos位插入一个字符void string::insert(size_t pos, char ch){assert(pos <= _size);//如果当前的有效数据个数和最大容量相等 if (_size == _capacity){//那么扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}// 挪动数据//_size + 1:\0的后一位//把end指向\0的后一位size_t end = _size + 1;//循环将pos之后的数据都向后挪动一位while (end > pos){_str[end] = _str[end - 1];--end;}//将字符ch放入pos位_str[pos] = ch;++_size;}//按pos位插入一个字符串void string::insert(size_t pos, const char* str){assert(pos <= _size);//先计算要插入的字符长度,将值赋给临时变量lensize_t len = strlen(str);//如果当前存储的有效数据个数 加上 要插入的字符 大于 容量if (_size + len > _capacity){// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}//定义一个end指向_size + len的位置上size_t end = _size + len;//通过循环把pos后的len个数据向后挪动len个位置while (end > pos + len - 1){_str[end] = _str[end - len];--end;}// 这里不能用 strcpy 会把 '\0' 拷贝过来//使用memcpy函数进行拷贝的原因是memcpy函数不会自动补上'\0'// 而strcpy函数会在拷贝后自动补上'\0’,//把str里的len个数据拷贝到_str + pos里memcpy(_str + pos, str, len);//插入字符串_size += len;}//从pos位置开始删除长度为的len的字符串//_str:指向字符串存放的空间的指针//_size:当前存储的有效数据个数, 指向最后一个字符的下一个位置void string::erase(size_t pos, size_t len){//判断是否会越界assert(pos < _size);//如果要删除的字符  大于等于  当前存储的有效数据个数 减去 当前指向数据的位置if (len >= _size - pos){//直接将pos位置置为\0_str[pos] = '\0';_size = pos;}//如果要删除的字符  小于  当前存储的有效数据个数减去当前指向数据的位置else{//将_str + pos + len(要保留的数据)位置的字符串直接拷贝到_str + pos(要删除的数据)位置直接覆盖掉strcpy(_str + pos, _str + pos + len);_size -= len;}}//查找字符//查找对应的字符,返回对应的下标size_t string::find(char ch, size_t pos){assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}//查找字符串//strstr:在一个字符串中查找另一个字符串 // 返回子串在原串里第一个出现的位置//str1:原串       str2:子串//const char * strstr ( const char * str1, const char * str2 );size_t string::find(const char* str, size_t pos){assert(pos < _size);//通过strstr函数来将str作为子串找到它的地址const char* ptr = strstr(_str + pos, str);//匹配失败if (ptr == nullptr){return npos;}else//匹配成功{//ptr的地址减去_str的地址就是我们要找的字符串的起始位置的下标return ptr - _str;}}//从pos位置开始截取长度为len的字符再构造一个子串,子串返回string string::substr(size_t pos, size_t len){assert(pos < _size);// 如果len大于剩余字符长度if (len > _size - pos){//把len更新成为一个有效的长度,有多少长度取多少空间len = _size - pos;}//构造一个子串substring sub;//先给sub预留len个空间sub.reserve(len);//for循环遍历要截取的字符for (size_t i = 0; i < len; i++){//将从pos位置开始长度为len的字符尾插到sub中sub += _str[pos + i];}return sub;}//string比较大小按照ascii码比//strcmp:如果第一个数大于/小于/等于第二个数,那么返回>0/<0/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 s1 < s2 || s1 == s2;}//大于bool operator>(const string& s1, const string& s2){return !(s1 <= s2);}//大于等于bool operator>=(const string& s1, const string& s2){return !(s1 < s2);}//等于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 !(s1 == s2);}//流插入
ostream& operator<<(ostream& out, const string& s)
{for (auto ch : s){out << ch;}return out;
}//流提取
istream& operator>>(istream& in, string& s)
{s.clear();const int N = 256;char buff[N];int i = 0;char ch;//in >> ch;ch = in.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}//in >> ch;ch = in.get();}if (i > 0){buff[i] = '\0';s += buff;}return in;
}


感谢观看~

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

2024年全国大学生数学建模竞赛B题生产过程中的决策问题分析

目录 引言 问题 1&#xff1a;抽样检测方案设计 问题 2&#xff1a;生产过程中的决策 决策阶段划分 决策方案 结果 问题 3&#xff1a;多道工序和零配件的决策 生产流程 决策过程 问题 4&#xff1a;基于抽样检测的重新决策 动态调整次品率 结论 引言 在2024年全国…

Python 的 WSGI 简单了解

从 flask 的 hello world 说起 直接讨论 WSGI&#xff0c;很多人可能没有概念&#xff0c;我们还是先从一个简单的 hello world 程序开始吧。 from flask import Flaskapp Flask(__name__)app.route("/", methods[GET]) def index():return "Hello world!&q…

【Axure原型】B端系统登录注册页设计成这样,就不用跟小孩一桌了

前言 在B端后台中&#xff0c;登录注册页这个东西&#xff0c;因为感觉很简单&#xff0c;所以经常不被产品经理们重视。但是登录注册页作为一个后台系统的门面&#xff0c;直接影响用户第一印象&#xff0c;又是非常重要的存在。 登录注册页的价值 B端系统登录注册页是用户…

极验3代前两个参数w逆向分析

声明: 该文章为学习使用,严禁用于商业用途和非法用途,违者后果自负,由此产生的一切后果均与作者无关。 本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除! 前言 这次会简单的讲解…

Java封装(面向对象)

这个是大三来的时候刚开始又捡起来了java这个语言&#xff0c;以前是开设过这个课程的&#xff0c;但是上课都没哈好听讲&#xff0c;现在又开始学习java类的。 首先附上黑马程序员的一张听课截图吧 我就拿我在黑马程序员的例子上给自己的一个讲解吧 首先是javabean类 pack…

我在高职教STM32——准备HAL库工程模板(2)

新学期已开始,又要给学生上 STM32 嵌入式课程了。这课上了多年了,一直用的都是标准库来开发,已经驾轻就熟了。人就是这样,有了自己熟悉的舒适圈,就很难做出改变,老师上课也是如此,排斥新课和不熟悉的内容。显然,STM32 的开发,HAL 库已是主流,自己其实也在使用,只不过…

【IEEE出版,高录用 | EI快检索】第二届人工智能与自动化控制国际学术会议(AIAC 2024,10月25-27)

第二届人工智能与自动化控制国际学术会议&#xff08;AIAC 2024&#xff09; The 2nd International Conference on Artificial Intelligence and Automation Control 2024年10月25-27日 中国-广州 重要信息 会议官网&#xff1a;www.icaiac.org The 2nd International Conf…

网络安全学习(三)Hydra破解密码

接下来看一下Hydra工具&#xff0c;这是一个暴力破解密码的工具。 使用命令&#xff08;注意区分大小写&#xff09;。 hydra -L user.txt账号字典 -P pass.txt密码字典 IP地址 smb协议名称 hydra -l administrator指定账号 -P pass.txt密码字典 IP地址 smb协议名称 hydra -…

进程状态、进程创建和进程分类

文章目录 进程进程常见的状态进程调度进程状态变化关系 进程标识示例--进程标识的使用以及简介 进程创建fork函数vfork函数示例--使用fork函数创建子进程&#xff0c;并了解进程之间的关系 创建进程时发生的变化虚拟内存空间的变化示例--验证fork函数创建进程时的操作 对文件IO…

改进RRT*的路径规划算法

一、RRT算法 RRT 算法是一种基于随机采样的快速搜索算法。该算法的主要思想是通过随机采样来创建一个快速探索的树&#xff0c;从而生长出一条从起点到终点的路径。如图为随机树的生长过程。 初始化。首先&#xff0c;初始化起始点和目标点位置&#xff0c;并将起点作为根节点…

5-----RYZ维修工具 操作界面预览与功能操作解析 刷机 解锁 修复参数等等

以上是工具选项功能的界面预览 。通过预览可以看到很多功能选项。此类工具涵盖了很多操作区域。需要根据自己机型的实际需求来操作。根据开发者的描述。此工具有一下功能。包含mtk刷机 分区修复。9008刷机 备份基带efs等等。 高通操作区域 高通修复串码 高通修改写入基带qc…

python中的各类比较与计算

运算符 1.算数运算符2.关系运算符3.逻辑运算符4.关于短路求值5.赋值运算符1&#xff09;的使用链式赋值多元赋值 2)复合赋值运算符 6.位运算符7.成员运算符8.身份运算符 1.算数运算符 # 加 print(1 2) # 减 print(2 - 1) # 乘 print(1 * 2) # 余数 4%31余数为1 print(4 % 3…

只要不逾期就行了吗?如何守护好你的“第二张身份证“!

在这个时代&#xff0c;信用记录已远远超越了金融交易的范畴&#xff0c;它如同一根无形的纽带&#xff0c;将我们生活的各个领域紧密相连。近闻有人甚至在步入婚姻殿堂前&#xff0c;也要细致核查对方的信用状况&#xff0c;毕竟&#xff0c;这关乎到共同生活的基石与未来幸福…

通过hosts.allow和hosts.deny限制用户登录

1、Hosts.allow和host.deny说明 两个文件是控制远程访问设置的&#xff0c;通过设置这个文件可以允许或者拒绝某个ip或者ip段的客户访问linux的某项服务。如果请求访问的主机名或IP不包含在/etc/hosts.allow中&#xff0c;那么tcpd进程就检查/etc/hosts.deny。看请求访问的主机…

volatile 实现原理了解吗?

volatile 实现原理了解吗&#xff1f; volatile 有两个作用&#xff0c;保证可见性和有序性。 volatile 怎么保证可见性的呢&#xff1f; 简单来说&#xff1a;读取和写入变量从原本的本地内存变成主内存中 相比 synchronized 的加锁方式来解决共享变量的内存可见性问题&#…

网络原理 IP协议与以太网协议

博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:MySQL数据库 JavaEE专栏:JavaEE 关注博主带你了解更多数据结构知识 目录 1.网络层 IP协议 1.IP协议格式 2.地址管理 2.1 IP地址 2.2 解决IP地址不够用的问题 2.3NAT网络地址转换 2.4网段划分 3.路由选择…

Unity多国语言支持

Unity多国语言支持 项目在我的课程 ”淘金城堡“ 中应用 项目的地址&#xff1a;http://t.csdnimg.cn/m0hFd 一、基本概念 在Unity中加入多国语言的支持可以让我们发布的游戏或应用上线在拥有不同语言的国家或地区。 下面介绍一款Unity官方提供的插件“Localization package…

FinLex An effective use of word embeddings for financial lexicon generation

FinLex: An effective use of word embeddings for financial lexicon generation 论文阅读 文章目录 FinLex: An effective use of word embeddings for financial lexicon generation 论文阅读 AbstractMethodology具体词表例子LM 词列表与 FinLex 词列表 词列表在分类任务中…

EMT-DAVT--基于子空间分布对齐和决策变量转移的多目标多任务优化

EMT-DAVT–基于子空间分布对齐和决策变量转移的多目标多任务优化 title&#xff1a; Multiobjective Multitasking Optimization With Subspace Distribution Alignment and Decision Variable Transfer author&#xff1a; Weifeng Gao, Jiangli Cheng, Maoguo Gong, Hong L…

FreeRTOS实战指南 — 3.1 C语言链表

目录 1 单向链表 1.1 单链表的概念 1.2 链表增加头结点的作用 1.3 单链表的实现 2 循环链表 3 双向链表 为什么学习链表&#xff1f;FreeRTOS使用链表来管理任务调度&#xff0c;来维护不同优先级的就绪任务&#xff1b;许多内部数据结构&#xff0c;如任务控制块&#x…