C++——string的模拟实现(下)
目录
成员函数
3.4 修改操作
(3)insert()函数
(4)pop_back()函数
(5)erase()函数
(6)swap()函数
3.5 查找操作
(1)find()函数
(2)substr()函数
3.6 重载函数
(1)operator=赋值函数
(2)其他比较函数
(3)流插入和流提取
完整代码
结束语
第一篇链接:C++——string的模拟实现(上)
成员函数
3.4 修改操作
(3)insert()函数
insert() 函数用于在字符串的指定位置插入一个字符或字符串。
注意事项:
在移动字符串内容时,需要确保不会覆盖或丢失任何字符。
使用 memcpy() 时,要确保源和目标内存区域不重叠,否则可能导致未定义行为。
string.h:
// insert()函数 void insert(size_t pos, char ch); //插入字符void insert(size_t pos, const char* str); //插入字符串
string.cpp:
// insert()函数
// 插入字符
void string::insert(size_t pos, char ch)
{assert(pos <= _size);if (_capacity == _size){size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;reserve(newcapacity);}size_t end = _size + 1;// 挪动元素while (pos < end){_str[end] = _str[end - 1];end--;}_str[pos] = ch; //将ch放置到pos这个位置++_size; //更新_size
}// 插入字符串
void string::insert(size_t pos, const char* str)
{assert(pos <= _size);size_t len = strlen(str); // 要插入的字符串长度if (_size + len > _capacity){reserve(_size + len);}// 从后向前移动字符串内容以腾出空间 for (size_t i = _size; i >= pos; --i){_str[i + len] = _str[i];}// 复制新字符串到指定位置 memcpy(_str + pos, str, len);// 添加新的字符串结束符 _str[_size + len] = '\0';// 更新字符串长度 _size += len;
}
来个简单的代码测试一下:

(4)pop_back()函数
pop_back() 函数用于移除字符串末尾的字符。
实现:将字符串末尾的字符设置为 '\0'。 更新字符串长度 _size。
string.h:
// pop_back()函数
void pop_back();
string.cpp:
// pop_back()函数
void string::pop_back()
{_str[_size - 1] = '\0';--_size;
}
(5)erase()函数
erase() 函数用于从字符串中移除指定位置的字符或子字符串。
string.h:
// erase()函数
void erase(size_t pos = 0, size_t len = npos);
string.cpp:
// erase()函数
void string::erase(size_t pos,size_t len)
{assert(pos < _size); if (len == npos || len >= _size - pos){_str[pos] = '\0'; // 位置pos置为'\0'_size = pos; // 有效元素个数为pos个}else // len小于后面的字符个数{// 将后面的字符拷贝到pos位置strcpy(_str + pos, _str + pos + len);_size -= len; // 更新有效元素}
}
erase()需要额外定义一个类成员变量npos来实现,它为无符号数的-1,一般为整型的最大值。
string.h:
public:static const size_t npos;
string.cpp:
const size_t string::npos = -1;
简单的对上面两个函数进行测试:

(6)swap()函数
swap() 函数用于交换两个字符串的内容。
string.h:
// swap()函数
void swap(string& str);
string.cpp:
// swap()函数
void string::swap(string& str)
{// 这里我们调用std库中的swap()函数std::swap(_str, str._str);std::swap(_capacity, str._capacity);std::swap(_size, str._size);
}
测试:

3.5 查找操作
(1)find()函数
find() 函数用于在字符串中查找指定字符或子字符串的位置。
我们在这里实现从指定位置开始向后遍历查找指定字符或者子字符串。
如果找到,则返回子字符串在字符串中的起始位置;否则返回 npos。
string.h:
// find()函数
size_t find(char ch, size_t pos);
size_t find(const char* str, size_t pos);
string.cpp:
// find()函数
// 寻找字符
size_t string::find(char ch, size_t pos)
{for (int i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;
}// 从pos开始寻找字符串
size_t string::find(const char* str, size_t pos)
{char* p = strstr(_str + pos, str);if (p){return p - _str;}else{return npos;}
}
(2)substr()函数
substr() 函数用于获取字符串的子字符串。
string.h:
// substr()函数
string substr(size_t pos = 0, size_t len = npos);
string.cpp:
// substr()函数
string string::substr(size_t pos, size_t len)
{string str;if (len == npos || len >= _size - pos){for (size_t i = pos; i < _size; i++){str += _str[i];}}else{for (size_t i = pos; i < pos + len; i++){str += _str[i];}}return str;
}
3.6 重载函数
在C++中,函数重载允许我们为同一函数名创建多个版本,这些版本可以有不同的参数列表(参数的数量或类型不同)。通过这种方式,我们可以使代码更加简洁和易于理解。
(1)operator=赋值函数
赋值运算符(operator=)用于将一个对象的内容复制到另一个对象中。对于自定义的字符串类,我们需要自己实现这个运算符,以确保正确地管理内存。
string.h:
// operator=赋值函数
string& operator=(const string& s);
string.cpp:
// operator= 函数
string& string::operator=(const string& str)
{if (this != &str){char* tmp = new char[str._capacity + 1];strcpy(tmp, str._str);delete[] _str;_str = tmp;_size = str._size;_capacity = str._capacity;}return *this;
}
来测试一下:

这里我们可以对以上的代码进行优化:
// operator= 函数
string& string::operator=(const string& str)
{if (this != &str){string tmp(str._str); // 调用构造函数swap(tmp); // 将tmp与this交换}return *this;
}
原始实现中,我们首先检查自赋值(即对象试图将自己赋值给自己),然后分配足够的内存来存储新字符串,复制内容,并释放旧内存。这种方法虽然有效,但可能会导致性能问题,特别是当字符串很长时,因为涉及到多次内存分配和释放。
优化后的实现采用了“拷贝-交换”技术。这种方法通过创建一个临时对象来存储要赋值的字符串,然后使用swap函数交换临时对象和当前对象的内容。由于swap函数通常实现得非常高效(只需交换指针),这种方法可以显著提高性能,并减少内存分配的次数。
(2)其他比较函数
每个比较运算符都基于strcmp函数的返回值来实现。
这些函数之间是可以复用的。
string.h:
// 比较函数
bool operator<(const string& s)const;
bool operator<=(const string& s)const;
bool operator>(const string& s)const;
bool operator>=(const string& s)const;
bool operator==(const string& s)const;
bool operator!=(const string& s)const;
string.cpp:
// 比较函数
bool string::operator<(const string& str) const
{return strcmp(_str, str._str) < 0;
}
bool string::operator<=(const string& str) const
{return *this < str || *this == str;
}
bool string::operator>(const string& str) const
{return !(*this <= 0);
}
bool string::operator>=(const string& str) const
{return !(*this <= str);
}
bool string::operator==(const string& str)const
{return strcmp(_str, str._str) == 0;
}
bool string::operator!=(const string& str)const
{return !(*this == str);
}void string::clear()
{_str[0] = '\0';_size = 0;
}
(3)流插入和流提取
我们接下来试着实现流插入和流提取:
注意,我们不能将这两个函数定义放在string类里
在 C++ 中,当我们使用 std::cout << d1 或 std::cin >> d1 这样的表达式时,左侧的 std::cout 或 std::cin 是对象,而右侧的 d1 是我们想要输出或输入的数据。运算符函数需要能够接受这两个对象作为参数。 如果 << 或 >> 运算符被定义为 std::string 的成员函数,那么它们将需要额外的 this 指针来访问类的成员变量,这将导致需要三个参数(this 指针,左操作数,右操作数),这与标准的运算符用法不兼容。
string.h:
//流插入和流提取
istream& operator>>(istream& is, string& str);
ostream& operator<<(ostream& os, const string& str);
string.cpp:
// 流输入
istream& operator>>(istream& is, string& str)
{// 清除字符串 str 中的现有内容 str.clear();char ch;// 从输入流 is 中读取第一个字符到 ch 中 ch = is.get();// 定义一个字符数组(缓冲区)buffchar buff[128];size_t i = 0;// 循环读取字符,直到遇到空格或换行符为止 while (ch != ' ' && ch != '\n'){// 将字符 ch 存储到缓冲区 buff 的当前位置 buff[i++] = ch; if (i == 127){// 在缓冲区末尾添加字符串结束符 '\0'buff[i++] = '\0';str += buff;// 重置索引 i,为下一轮存储字符做准备 i = 0;}// 从输入流中读取下一个字符到 ch 中 ch = is.get();}// 循环结束后,检查缓冲区中是否还有未处理的字符 if (i > 0){// 在缓冲区末尾添加字符串结束符 '\0' buff[i] = '\0';// 将缓冲区的内容追加到字符串 str 中 str += buff;}return is;
}
// 流提取
ostream& operator<<(ostream& os, const string& str)
{for (size_t i = 0; i < str.size(); i++){os << str[i];}return os;
}
测试一下:

完整代码
string.h:
#include<iostream>
#include<assert.h>
#include<stdbool.h>
using namespace std;namespace My_string
{class string{public:typedef char* iterator; //将char*重命名为iteratortypedef const char* const_iterator;//const版本的iteratorconst_iterator begin() const; //提供const_iterator begin()函数const_iterator end() const; //提供const_iterator end()函数//非const版本的iteratoriterator begin(); //提供iterator begin()函数iterator end(); //提供iterator end()函数string(const char* str = " "); //构造函数~string(); //析构函数string(const string& str); //拷贝构造函数const char* c_str() const; // c_str()函数size_t size() const; // size()函数size_t capacity() const; // capacity()函数bool empty() const; // empty()函数// resize()函数void resize(size_t n, char ch = '\0');// 非const版本char& operator[](size_t pos); //operator[]函数// const版本const char& operator[](size_t pos)const;// 预留空间void reserve(size_t n);// 尾插一个字符void push_back(char ch);// 尾插一个字符串void append(const char* str);//operator+=函数可以构成重载,函数名相同,参数不同string& operator+=(char ch); // 字符相加string& operator +=(const char* str); // 字符串相加// insert()函数 void insert(size_t pos, char ch); //插入字符void insert(size_t pos, const char* str); //插入字符串// erase()函数void erase(size_t pos = 0, size_t len = npos);// pop_back()函数void pop_back();// find()函数size_t find(char ch, size_t pos);size_t find(const char* str, size_t pos);// substr()函数string substr(size_t pos = 0, size_t len = npos);// operator=赋值函数string& operator=(const string& s);// swap()函数void swap(string& str);// 比较函数bool operator<(const string& s)const;bool operator<=(const string& s)const;bool operator>(const string& s)const;bool operator>=(const string& s)const;bool operator==(const string& s)const;bool operator!=(const string& s)const;// clear()函数void clear();public:static const size_t npos;private:char* _str; // 指向字符串的指针size_t _size; // 有效字符个数size_t _capacity; // 有效空间个数};//流插入和流提取istream& operator>>(istream& is, string& str);ostream& operator<<(ostream& os, const string& str);
}
string.cpp:
#include"string.h"
namespace My_string
{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;}// 构造函数string::string(const char* str){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1]; // +1用于储存'\0'strcpy(_str, str);}// 析构函数string::~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}// 拷贝构造函数(1)string::string(const string& str){_str = new char[str._capacity + 1]; //额外多给一个空间,用于存放'/0'strcpy(_str, str._str); //拷贝数据_capacity = str._capacity; //设置容量_size = str._size; //设置有效数据个数}// 拷贝构造函数(2)//string::string(const string& str)//{// string tmp(str._str);// std::swap(tmp._str, _str);// std::swap(tmp._size, _size);// std::swap(tmp._capacity, _capacity);//}// 拷贝构造函数(3)//string::string(const string& str)//{// string tmp(str._str);// swap(tmp); // 这里的swap我们接下来会定义//}// c_str()函数const char* string::c_str() const{return _str;}// size()函数size_t string::size() const{return _size;}// capacity()函数size_t string::capacity() const{return _capacity;}// empty()函数bool string::empty() const{return _size == 0;}// operator[]函数char& string::operator[](size_t pos){assert(pos < _size);return _str[pos];}// const版本const char& string::operator[](size_t pos)const{assert(pos < _size);return _str[pos];}// 预留空间void string::reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}// resize()函数void string::resize(size_t n, char ch){if (n > _size){if (n > _capacity){reserve(n);}// 使用 memset 函数将字符 ch // 填充到新添加的空间中memset(_str + _size, ch, n - _size);}_size = n;_str[n] = '\0';}//尾插一个字符void string::push_back(char ch){if (_capacity == _size){size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;reserve(newcapacity);}_str[_size] = ch;_str[_size + 1] = '\0';_size++;}//尾插一个字符串void string::append(const char* str){size_t len = strlen(str);if (_size + len > _capacity) {reserve(_size + len);}strcpy(_str+_size, str);_size += len; }string& string::operator+=(char ch){// 调用push_back()函数push_back(ch); return *this;}string& string::operator+=(const char* str){append(str);return *this;}// insert()函数// 插入字符void string::insert(size_t pos, char ch){assert(pos <= _size);if (_capacity == _size){size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;reserve(newcapacity);}size_t end = _size + 1;// 挪动元素while (pos < end){_str[end] = _str[end - 1];end--;}_str[pos] = ch; //将ch放置到pos这个位置++_size; //更新_size}// 插入字符串void string::insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str); // 要插入的字符串长度if (_size + len > _capacity){reserve(_size + len);}// 从后向前移动字符串内容以腾出空间 for (size_t i = _size; i >= pos; --i){_str[i + len] = _str[i];}// 复制新字符串到指定位置 memcpy(_str + pos, str, len);// 添加新的字符串结束符 _str[_size + len] = '\0';// 更新字符串长度 _size += len;}// erase()函数void string::erase(size_t pos,size_t len){assert(pos < _size); if (len == npos || len >= _size - pos){_str[pos] = '\0'; // 位置pos置为'\0'_size = pos; // 有效元素个数为pos个}else // len小于后面的字符个数{// 将后面的字符拷贝到pos位置strcpy(_str + pos, _str + pos + len);_size -= len; // 更新有效元素}}// pop_back()函数void string::pop_back(){_str[_size - 1] = '\0';--_size;}// find()函数// 寻找字符size_t string::find(char ch, size_t pos){for (int i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}// 从pos开始寻找字符串size_t string::find(const char* str, size_t pos){char* p = strstr(_str + pos, str);if (p){return p - _str;}else{return npos;}}// substr()函数string string::substr(size_t pos, size_t len){string str;if (len == npos || len >= _size - pos){for (size_t i = pos; i < _size; i++){str += _str[i];}}else{for (size_t i = pos; i < pos + len; i++){str += _str[i];}}return str;}// operator= 函数//string& string::operator=(const string& str)//{// if (this != &str)// {// char* tmp = new char[str._capacity + 1];// strcpy(tmp, str._str);// delete[] _str;// _str = tmp;// _size = str._size;// _capacity = str._capacity;// }// return *this;//}// operator= 函数string& string::operator=(const string& str){if (this != &str){string tmp(str._str); // 调用构造函数swap(tmp); // 将tmp与this交换}return *this;}// swap()函数void string::swap(string& str){// 这里我们调用std库中的swap()函数std::swap(_str, str._str);std::swap(_capacity, str._capacity);std::swap(_size, str._size);}// 比较函数bool string::operator<(const string& str) const{return strcmp(_str, str._str) < 0;}bool string::operator<=(const string& str) const{return *this < str || *this == str;}bool string::operator>(const string& str) const{return !(*this <= 0);}bool string::operator>=(const string& str) const{return !(*this <= str);}bool string::operator==(const string& str)const{return strcmp(_str, str._str) == 0;}bool string::operator!=(const string& str)const{return !(*this == str);}void string::clear(){_str[0] = '\0';_size = 0;}// 流输入istream& operator>>(istream& is, string& str){// 清除字符串 str 中的现有内容 str.clear();char ch;// 从输入流 is 中读取第一个字符到 ch 中 ch = is.get();// 定义一个字符数组(缓冲区)buffchar buff[128];size_t i = 0;// 循环读取字符,直到遇到空格或换行符为止 while (ch != ' ' && ch != '\n'){// 将字符 ch 存储到缓冲区 buff 的当前位置 buff[i++] = ch; if (i == 127){// 在缓冲区末尾添加字符串结束符 '\0'buff[i++] = '\0';str += buff;// 重置索引 i,为下一轮存储字符做准备 i = 0;}// 从输入流中读取下一个字符到 ch 中 ch = is.get();}// 循环结束后,检查缓冲区中是否还有未处理的字符 if (i > 0){// 在缓冲区末尾添加字符串结束符 '\0' buff[i] = '\0';// 将缓冲区的内容追加到字符串 str 中 str += buff;}return is;}// 流提取ostream& operator<<(ostream& os, const string& str){for (size_t i = 0; i < str.size(); i++){os << str[i];}return os;}
}
test.cpp:
#include"string.h"
#include<iostream>using namespace std;void test1()
{// 测试构造函数 My_string::string s1("Hello");cout << "s1: " << s1.c_str() << endl;// 测试拷贝构造函数 /*My_string::string s2(s1);cout << "s2 (s1): " << s2.c_str() << endl; */
}void test2()
{My_string::string str("Hello");str[0] = 'h';cout << str.c_str() << endl;//使用operator[]函数打印for (size_t i = 0; i < str.size(); i++){cout << str[i] << " ";}cout << endl;
}void test3()
{My_string::string str("hello");for (auto i : str){cout << i << " ";}cout << endl;My_string::string::iterator it1 = str.begin();while (it1 != str.end()){cout << *it1 << " ";++it1;}cout << endl;My_string::string::iterator it2 = str.end();if (it2 != str.begin()) { // 检查避免直接解引用 end() --it2; // 先移动到一个有效的位置 while (it2 != str.begin()){std::cout << *it2 << " ";--it2;}std::cout << *it2 << " "; // 输出最后一个字符(begin() 之前的字符) }std::cout << std::endl;
}void test4()
{My_string::string str("hello");cout << str.c_str() << endl;str.push_back('A');cout << str.c_str() << endl;str.append("world");cout << str.c_str() << endl;str += 'C'; cout << str.c_str() << endl;
}void test5()
{My_string::string str("hello world");str.insert(6, 'x');cout << str.c_str() << endl;str.insert(6, "yyyyy");cout << str.c_str() << endl;str.insert(0, 'X');cout << str.c_str() << endl;
}void test6()
{My_string::string str("hello world");str.pop_back();cout << str.c_str() << endl;str.erase(2, 3);cout << str.c_str() << endl;
}void test7()
{My_string::string str("hello world");cout << str.find('l', 0) << endl;cout << str.find("ld", 0) << endl;
}void test8()
{My_string::string str1("hello");My_string::string str2("world");cout << str1.c_str() << endl;cout << str2.c_str() << endl;str1.swap(str2);cout << str1.c_str() << endl;cout << str2.c_str() << endl;
}void test9()
{My_string::string str("hello World");cout << str.substr(2, 2) << endl;cout << str.substr(7, 3) << endl;
}void test10()
{My_string::string str1("hello world");My_string::string str2("xxxxxxxxxxx");str1 = str2;cout << str1.c_str() << endl;cout << str2.c_str() << endl;My_string::string str3("yyyyy");str1 = str3;cout << str1.c_str() << endl;cout << str3.c_str() << endl;
}void test11()
{My_string::string str("hello");str.resize(10, '*');cout << str.c_str() << endl;str.reserve(15);cout << str.c_str() << endl;
}void test12()
{My_string::string str("XXX");cin >> str;cout << str << endl;
}int main()
{//test1();//test2();//test3();//test4();//test5();//test6();//test7();//test8();//test9();//test10();//test11();test12();return 0;
}
结束语
实验周太忙啦!!!一直没时间写。。。
感谢各位大佬的阅读!!!
求点赞收藏评论关注!!!
相关文章:
C++——string的模拟实现(下)
目录 成员函数 3.4 修改操作 (3)insert()函数 (4)pop_back()函数 (5)erase()函数 (6)swap()函数 3.5 查找操作 (1)find()函数 (2)substr()函数 3.6 重载函数 (1)operator赋值函数 (2)其他比较函数 (3)流插入和流提取 完整代码 结束语 第一篇链接:C——…...
面试 Java 基础八股文十问十答第二十九期
面试 Java 基础八股文十问十答第二十九期 作者:程序员小白条,个人博客 相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新! ⭐点赞⭐收藏⭐不迷路!⭐ 1)类加载过程 类加载…...
454.四数相加||
题目: 454. 四数相加 II - 力扣(LeetCode) 思路: 考虑到时间复杂度问题,本题最重要的是要将四个数组划分成两个部分,每个部分(n^2)的时间复杂度,选取数据结构时,考虑到既要存储元素(key),又要有元素次数…...
禅道源码部署
文章目录 禅道部署1.环境部署安装httpd和mariadb安装php 2.安装禅道首先进行httpd服务的配置安装禅道 禅道部署 1.环境部署 安装lamp环境 组件版本httpdyum安装mariadbyum安装phpphp-7.4.33 选择一个php版本就行,我们这里选择的是7.4.33 安装httpd和mariadb [r…...
️ Vulnhuntr:利用大型语言模型(LLM)进行零样本漏洞发现的工具
在网络安全领域,漏洞的发现和修复是保护系统安全的关键。今天,我要向大家介绍一款创新的工具——Vulnhuntr,这是一款利用大型语言模型(LLM)进行零样本漏洞发现的工具,能够自动分析代码,检测远程…...
【Android】多渠道打包配置
目录 简介打包配置签名配置渠道配置配置打包出来的App名称正式包与测试包配置 打包方式开发工具打包命令行打包 优缺点 简介 多渠道打包 是指在打包一个 Android 应用时,一次编译生成多个 APK 文件,每个 APK 文件针对一个特定的渠道。不同的渠道可能代表…...
Spring Boot Configuration和AutoConfiguration加载逻辑和加载顺序调整
在spring中, AutoConfiguration也是一个种Configuration,只是AutoConfiguration是不能使用proxy的。 而且spring对于两者的加载顺序也不是一视同仁,是有顺序的。spring会先加载@SpringBootApplication可达的且标注了@Configuration的类,这个过程会将@AutoConfiguration标注…...
点餐系统需求分析说明书(软件工程分析报告JAVA)
目录 1 引言 4 1.1 编写目的 4 1.2 项目背景 4 1.3 定义 4 1.4 预期的读者 5 1.5 参考资料 5 2 任务概述 5 2.1 目标 5 2.2 运行环境 5 2.3 条件与限制 6 3 数据描述 6 3.1 静态数据 6 3.2 动态数据 6 3.3 数据库介绍 6 3.4 对象模型 6 3.5 数据采集 7 4 动态模型 7 4.1 脚本 …...
Python条形图 | 指标(特征)重要性图的绘制
在数据科学和机器学习的工作流程中,特征选择是一个关键步骤。通过评估每个特征对模型预测能力的影响,我们可以选择最有意义的特征(指标),从而提高模型的性能并减少过拟合。本文将介绍如何使用 Python 的 Seaborn 和 Ma…...
危险物品图像分割系统:一键训练
危险物品图像分割系统源码&数据集分享 [yolov8-seg-GFPN&yolov8-seg-CSwinTransformer等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI Global…...
城市景色视频素材下载好去处
在制作短视频、Vlog 或商业宣传片时,城市景色视频素材能为作品增添现代感与活力。繁华都市、流光溢彩的夜景、清晨街道等都是展现城市魅力的好素材。那么城市景色视频素材去哪里下载呢? 蛙学网 是专为短视频创作者打造的素材平台,城市景色素材…...
基于SSM美容院管理系统的设计
管理员账户功能包括:系统首页,个人中心,用户管理,套餐类型管理,美容预约管理,生日提醒管理,管理员管理,系统管理 员工账号功能包括:系统首页,个人中心&#…...
Threejs 实现3D 地图(04)3d 地图的柱状图和文字显示
3d 地图的数据展示 代码仓库: King/threejs-3d-map 核心代码: function createText(feature, level, font) {if (feature.properties.name) {const [x_XYZ, y_XYZ] handleProject(feature.properties.center)// 缺点:首次渲染很慢 无法使…...
Oracle 第2章:安装与配置Oracle
安装与配置Oracle数据库是一项复杂但有序的过程。以下是对Oracle数据库安装与配置的概述,包括系统需求与硬件推荐,以及详细的安装步骤。 系统需求与硬件推荐 系统需求 在安装Oracle数据库之前,需要确保目标系统满足Oracle官方规定的最低要…...
动态规划 —— 斐波那契数列模型-解码方法
1. 解码方法 题目链接: 91. 解码方法 - 力扣(LeetCode)https://leetcode.cn/problems/decode-ways/description/ 2. 题目解析 1. 对字母A - Z进行编码1-26 2. 11106可以解码为1-1-10-6或者11-10-6, 但是11-1-06不能解码 3. 0n不能解码 4. …...
PPT / Powerpoint中利用LaTeX输入公式
PPT / Powerpoint中利用LaTeX输入公式_ppt插入latex公式-CSDN博客文章浏览阅读2.8w次,点赞42次,收藏75次。新版的Word(Office 2016后?)是支持LaTeX公式输入的,但是Powerpoint并不支持。下面介绍如何利用。_…...
C++ 模板专题 - 类型擦除
一:概述 C 中的类型擦除(Type Erasure)是一种技术,允许你在不暴露具体类型信息的情况下,通过统一的接口处理不同的类型。这种技术常用于实现泛型编程,特别是在需要支持多种不同类型的情况下,如容…...
RuoYi-Vue项目 重点代码讲解
1. RuoYi-Vue项目 常规说明: ruoyi-admin:后台接口开发(主要存放控制层相关代码)ruoyi-common:通用工具ruoyi-framework:框架核心ruoyi-generator:代码生成(可以移除)r…...
pandas习题 024:用字典构造 DataFrame
编码题)用 Python 的字典构造一个 DataFrame,它有 a、b 两列,三行数据。其中 a 列值为 1、4、7,b 列值为 2、5、8,索引为 x、y、z。 即: ‘’’ a b x 1 2 y 4 5 z 7 8 ‘’’ import pandas as pddf = pd.DataFrame({a: [1, 4,...
如何在Node.js中执行解压缩文件操作
一、解压文件 1.安装依赖: 安装adm-zip依赖包:npm install adm-zip --save 安装iconv-lite依赖包:npm install iconv-lite --save 解压前的file文件夹结构: update-1.0.2.zip压缩包内容: 2.在depresssFile.js文件&…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
高防服务器价格高原因分析
高防服务器的价格较高,主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因: 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器,因此…...
无需布线的革命:电力载波技术赋能楼宇自控系统-亚川科技
无需布线的革命:电力载波技术赋能楼宇自控系统 在楼宇自动化领域,传统控制系统依赖复杂的专用通信线路,不仅施工成本高昂,后期维护和扩展也极为不便。电力载波技术(PLC)的突破性应用,彻底改变了…...
