当前位置: 首页 > article >正文

(c++)string的模拟实现

目录

1.构造函数

2.析构函数

3.扩容

   1.reserve(扩容不初始化)

   2.resize(扩容加初始化)

4.push_back

5.append

6. += 运算符重载

  1.+=一个字符

  2.+=一个字符串

7 []运算符重载

8.find

1.找一个字符 

2.找一个字符串

9.insert

 1.插入一个字符

 2.插入一个字符串

9.erase

10.substr

11.运算符重载比较大小

         1.<

        2.==

        3.<=

        4.>

        5.>=

        6.!=

12.拷贝构造

13.赋值 =

14.<<

15.>>

16.迭代器

完整代码实现


      首先我们先定义头文件String.h,和命名空间_string防止和库中的string发生名字冲突

#include <iostream>
#include <cassert>
#include <string.h>
using namespace std;namespace _string {class string {public:static size_t npos;protected:char*  _str;size_t _size;size_t _capacity;}size_t string::npos = -1;
}

        其是我们的string类里面就是一个顺序表, 所以我们会定义一个数组_str,_size为实际字符所占的大小,_capacity为容量,如果达到了最大的容量我们就是_size == _capacity 我们就要进行扩容处理.

1.构造函数

string(const char* str = ""):_str(new char[strlen(str) + 1]),_size(strlen(str)),_capacity(strlen(str)){memcpy(_str, str, _size + 1);}

        这里我们为什么要多开一个空间strlen(str) + 1呢?因为我们这里字符串后面会有'\0',我们要多开一个位置给'\0',但是为什么_size和_capacity为什么不用+1呢?因为我们的'\0' 不算大小,所以我们_size和_capacity不需要给多一个空间.

        这里需要注意的是,我们开好空间的时候不要忘记去把str的内容拷贝的_str中,这里拷贝_size + 1是因为有'\0'也是需要拷贝的.

2.析构函数

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

        这里析构函数我认为,如果_str为空才需要释放空间,不为空不需要判断,所以我们这里加上一个判断,不为空的时候才可以去释放空间。

3.扩容

          1.reserve(扩容不初始化)

void reserve(size_t n) {if (n > _capacity) {char* tmp = new char[n + 1];memcpy(tmp, _str, _size + 1);delete[] _str;_str = tmp;_capacity = n;}
}

   扩容的时候需要进行判断,如果n大于容量扩容才有意义,如果小于就没有意义了

        2.resize(扩容加初始化)

void resize(size_t n , char ch = '\0') {if (n < _size) {_size = n;_str[_size] = '\0';}else {reserve(n);while (_size != n) {_str[_size++] = '\0';}_str[_size] = '\0';}
}

        resize如果给的n容量会继续缩小,所以当n < _size的时候我们直接把n位置变为'\0'就可以了

如果这里的n > _ size,就会出现两种情况,一种是  _capacity > n > _size 还有一种是 n > _capacity

因为我们写了扩容reserve,里面有判断,所以我们之间继续复用就可以了,最后再完成数据的拷贝就可以了.

4.push_back

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

5.append

void append(const char* str) {size_t len = strlen(str);if (_size + len > _capacity) {reserve(_size + len);}memcpy(_str+_size,str,len + 1);_size += len;
}

        push_back和append都一样,使用时应该要检查容量是否足够,不够的时候再扩容,最后完成数据的拷贝就可以了.

6. += 运算符重载

        1.+=一个字符

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

        2.+=一个字符串

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

      我们上面实现了push_back()和append()所以这里我们实现复用就可以了.

7 []运算符重载

//只读
const char operator[](size_t pos) const {assert(pos < _size);return _str[pos];
}//读写
char operator[](size_t pos) {assert(pos < _size);return _str[pos];
}

        我们在进行重载的时候应该注意,pos的范围不能超过_size的大小.

8.find

1.找一个字符 

            找一个字符返回当前位置

//默认从0位置开始size_t find(char ch, size_t pos = 0) {assert(pos < _size);for (size_t i = pos; i < _size; i++) {if (_str[i] == ch) {return i;}}return npos;
}

2.找一个字符串

        找一个字符串返回第一个字符出现的位置.

size_t find(const char* str, size_t pos) {assert(pos < _size);char* ptr = strstr(_str, str);if (ptr) {return ptr - _str;}else {return npos;}
}

        什么两个如果都没有找到的话,会返回npos,npos是string中静态变量,为无符号数的最大值.

9.insert

        1.插入一个字符

void insert(size_t pos , char ch) {assert(pos < _size);if (_size == _capacity) {reserve(_capacity == 0 ? 4 : _capacity*2);}//'\0'也要一起移动size_t end = _size;while (end >= pos &&  end != npos) {_str[end + 1] = _str[end];end--;}_str[pos] = ch;_size++;
}

        2.插入一个字符串

void insert(size_t pos, const char* str) {size_t len = strlen(str);if (_size + len > _capacity) {reserve(_size + len);}	//移动数据size_t end = _size;while (end >= pos && end != npos) {_str[end + len] = _str[end];end--;}//拷贝数据for (size_t i = 0; i < len; i++) {_str[pos + i] = str[i];}_size += len;
}

        我们两个函数都需要注意的是移动数据的时候这里是end--,如果没有npos != end,pos的位置是0,会造成死循环的问题,这是为什么?

        没有npos != end,如果pos的位置是0,那么循环的结束条件应该是end < 0,但是这里的end是无符号数,当end到达-1时相当于正数的最大值,不可能小于0. 所以我们这里应该要加上npos != end;

9.erase


void erase(size_t pos = 0 , size_t len = npos) {// '\0'也要移动所以可以等于 _size;assert(pos <= _size);if (pos + len >= _size || len == npos) {_str[_size] = '\0';_str[pos] = '\0';_size = pos;}else {size_t end = pos + len;while (end <= _size) {_str[pos++] = _str[end++];}_size -= len;}
}

        从pos位置开始删除,长度为len的字符. 如果pos + len >= _size 或者说 len说民删除完后面的字符, 直接把pos换成'\0'就可以了.

        如果pos + len < _size 就移动数据,为什么end <= _size ? 因为'\0'也要被移动.

10.substr

string substr(size_t pos = 0,size_t len = npos) {assert(pos < _size);//调整len的大小if (pos + len >= _size || len == npos) {len = _size - pos;}//预留好空间string tmp;tmp.reserve(len);for (size_t i = 0; i < len; i++){tmp += _str[pos + i];}tmp += '\0';return tmp;
}

        不要忘记最后一个位置要加上'\0'

11.运算符重载比较大小

         1.<

        我们要注意有三种特殊的情况

hello helloo true
hello hell false
hello hello false

        我们给两个长度len1,len2从0开始遍历碰到第一个小于就返回true,大于返回false,要是等于就继续len1和len2都要加加.

        如果出了循环,我们看上面三种情况,只有len2 < str._size && len1 == _size 才能返回true

其他都是false,所以我们直接返回len2 < str._size && len1 == _size就可以了

bool operator<(const string& str) const {size_t len1 = 0, len2 = 0;while (len1 < _size && len2 < str._size) {if (_str[len1] < str._str[len2]) {return true;}else if (_str[len1] > str._str[len2]) {return false;}else {len1++;len2++;}}return len1 == _size && len2 < str._size;
}

        2.==

bool operator==(const string& str) const {if (_size != str._size) {return false;}else {size_t len1 = 0, len2 = 0;while (len1 < _size && len2 < str._size) {if (_str[len1] < str._str[len2]) {return false;}else if (_str[len1] > str._str[len2]) {return false;}else {len1++;len2++;}}return true;}
}

       如果两个字符串的长度不相等直接返回false就可以了,长度如果相等有不相等的两个字符也是直接返回false,如果能出循环直接返回true;

        我们上面实现了< 和 = 我们直接复用就可以了

        3.<=

bool operator<=(const string& str) const {return *this < str || *this == str;
}

        4.>

bool operator>(const string& str) const {return !(*this <= str);
}

        5.>=

bool operator>=(const string& str) const {return !(*this < str);
}

        6.!=

bool operator!=(const string& str) const {return !(*this == str);
}

12.拷贝构造

        类里面默认生成的拷贝构造为浅拷贝,如果我们直接用默认生成的赋值,会造成析构函数释放同一块空间两次的问题编译器会就行报错,所以我们需要实现深拷贝.

string(const string& str) {//要多给一个位置给'\0'char* _str = new char[str._capacity + 1];_size = str._size;_capacity = str._capacity;//'\0' 也要进行拷贝所以拷贝_size + 1memcpy(_str,str._str,str._size + 1);
}

13.赋值 =

        和上面的拷贝构造一样,必须要实现深拷贝否则编译器会报错.

void swap(string& str) {std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);
}//str为临时变量出了作用域就会销毁
//交换后不用就行处理
string& operator=(string str) {swap(str);return *this;
}

        这里有很多人不明白赋值这里参数为什么不传引用?这里的string没有引用是一个临时变量,处理作用域就会销毁.所以我们把*this 的值和str的值进行交换不会有任何的问题

        这里的<< 和 >> 我们一般不喜欢写在类里面,如果写在类里面,第一个参数默认是this指针,那么我们调用的时候就需要反过来写,不符合我们的习惯.

str >> cin   

str << cout 

14.<<

//按照_size的大小来进行打印
//不是碰到'\0'就停止
ostream& operator<<(ostream& _cout, const string& str) {for (size_t i = 0; i < str.size(); i++){_cout << str[i];}return _cout;
}

        这里需要注意的是打印的是按照_size去打印,不是碰到'\0'就停下.

15.>>

//每次输入之前都要清空
istream& operator>>(istream& _cin, string& str) {	//清空str.clear();char ch;//给一buff数组来减小拷贝来提高效率int i = 0;char buff[128] = { 0 };//读取前置空格ch = _cin.get();while (ch == '\n' || ch == ' ')ch = _cin.get();while (ch != '\n' && ch != ' ') {buff[i++] = ch;if (i == 127) {//最后一个位置给'\0'buff[i] = '\0';str += buff;i = 0;}ch = _cin.get();}//如果i不等于0说明里面还有字符if (i != 0) {buff[i] = '\0';str += buff;}return _cin;
}

16.迭代器

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;
}

完整代码实现

namespace _String {class string {friend ostream& operator<<(ostream& _cout, const string& str);friend istream& operator>>(istream& _cin, string& str);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(const char* str = ""):_str(new char[strlen(str) + 1]), _size(strlen(str)), _capacity(strlen(str)){memcpy(_str, str, _size + 1);}~string() {if (_str) {delete[] _str;_size = _capacity = 0;}}string(const string& str) {//要多给一个位置给'\0'char* _str = new char[str._capacity + 1];_size = str._size;_capacity = str._capacity;//'\0' 也要进行拷贝所以拷贝_size + 1memcpy(_str,str._str,str._size + 1);}void swap(string& str) {std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}//str为临时变量出了作用域就会销毁//交换后不用就行处理string& operator=(string str) {swap(str);return *this;}//只读const char operator[](size_t pos) const {assert(pos < _size);return _str[pos];}//读写char operator[](size_t pos) {assert(pos < _size);return _str[pos];}// hello helloo true// hello hell false;// hello hello falsebool operator<(const string& str) const {size_t len1 = 0, len2 = 0;while (len1 < _size && len2 < str._size) {if (_str[len1] < str._str[len2]) {return true;}else if (_str[len1] > str._str[len2]) {return false;}else {len1++;len2++;}}return len1 == _size && len2 < str._size;}bool operator==(const string& str) const {if (_size != str._size) {return false;}else {size_t len1 = 0, len2 = 0;while (len1 < _size && len2 < str._size) {if (_str[len1] < str._str[len2]) {return false;}else if (_str[len1] > str._str[len2]) {return false;}else {len1++;len2++;}}return true;}}bool operator<=(const string& str) const {return *this < str || *this == str;}bool operator>(const string& str) const {return !(*this <= str);}bool operator>=(const string& str) const {return !(*this < str);}bool operator!=(const string& str) const {return !(*this == str);}void reserve(size_t n) {if (n > _capacity) {char* tmp = new char[n + 1];memcpy(tmp, _str, _size + 1);delete[] _str;_str = tmp;_capacity = n;}}void resize(size_t n, char ch = '\0') {if (n < _size) {_str[_size] = '\0';_size = n;_str[_size] = '\0';}else {//会自己判断不用加reserve(n);while (_size != n) {_str[_size++] = '\0';}_str[_size] = '\0';}}void push_back(char ch) {if (_size == _capacity) {reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size++] = ch;_str[_size] = '\0';}void insert(size_t pos , char ch) {assert(pos <= _size);if (_size == _capacity) {reserve(_capacity == 0 ? 4 : _capacity*2);}//'\0'也要一起移动size_t end = _size;while (end >= pos &&  end != npos) {_str[end + 1] = _str[end];end--;}_str[pos] = ch;_size++;}void insert(size_t pos, const char* str) {assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity) {reserve(_size + len);}//移动数据size_t end = _size;while (end >= pos && end != npos) {_str[end + len] = _str[end];end--;}//拷贝数据for (size_t i = 0; i < len; i++) {_str[pos + i] = str[i];}_size += len;}void erase(size_t pos = 0 , size_t len = npos) {// '\0'也要移动所以可以等于 _size;assert(pos <= _size);if (pos + len >= _size || len == npos) {_str[_size] = '\0';_str[pos] = '\0';_size = pos;}else {size_t end = pos + len;while (end <= _size) {_str[pos++] = _str[end++];}_size -= len;}}//如果len == npos 说明从pos位置开始截完全部string substr(size_t pos = 0,size_t len = npos) {assert(pos < _size);//调整len的大小if (pos + len >= _size || len == npos) {len = _size - pos;}//预留好空间string tmp;tmp.reserve(len);for (size_t i = 0; i < len; i++){tmp += _str[pos + i];}tmp += '\0';return tmp;}//默认从0位置开始size_t find(char ch, size_t pos = 0) {assert(pos < _size);for (size_t i = pos; i < _size; i++) {if (_str[i] == ch) {return i;}}return npos;}//默认0位置开始size_t find(const char* str, size_t pos = 0) {assert(pos < _size);char* ptr = strstr(_str, str);if (ptr) {return ptr - _str;}else {return npos;}}void append(const char* str) {size_t len = strlen(str);if (_size + len > _capacity) {reserve(_size + len);}//'\0'也要就行拷贝memcpy(_str + _size, str, len + 1);_size += len;}string& operator+=(char ch) {push_back(ch);return *this;}string& operator+=(const char* str) {append(str);return *this;}const char* c_str() const {return _str;}size_t size() const {return _size;}void clear() {_str[0] = '\0';_size = 0;}static size_t npos;protected:char* _str;size_t _size;size_t _capacity;};size_t string::npos = -1;//按照_size的大小来进行打印//不是碰到'\0'就停止ostream& operator<<(ostream& _cout, const string& str) {for (size_t i = 0; i < str.size(); i++){_cout << str[i];}return _cout;}//每次输入之前都要清空istream& operator>>(istream& _cin, string& str) {//清空str.clear();char ch;//给一buff数组来减小拷贝来提高效率int i = 0;char buff[128] = { 0 };//读取前置空格ch = _cin.get();while (ch == '\n' || ch == ' ')ch = _cin.get();while (ch != '\n' && ch != ' ') {buff[i++] = ch;if (i == 127) {buff[i] = '\0';str += buff;i = 0;}ch = _cin.get();}//如果i不等于0说明里面还有字符if (i != 0) {buff[i] = '\0';str += buff;}return _cin;}
}

        如果有错误,欢迎各位大佬指正.

相关文章:

(c++)string的模拟实现

目录 1.构造函数 2.析构函数 3.扩容 1.reserve(扩容不初始化) 2.resize(扩容加初始化) 4.push_back 5.append 6. 运算符重载 1.一个字符 2.一个字符串 7 []运算符重载 8.find 1.找一个字符 2.找一个字符串 9.insert 1.插入一个字符 2.插入一个字符串 9.erase 10…...

一种通用图片红色印章去除的工具设计

朋友今天下午需要处理个事情&#xff0c;问我有没有什么好的办法能够去除&#xff0c;核心问题是要去除图片上的印章。记得以前处理过类似的需求&#xff0c;photoshop操作比较简单&#xff0c;本质是做运算。这种处理方式有很多&#xff0c;比如现在流行的大模型&#xff0c;一…...

企业应用AI对向量数据库选型思考

一、向量数据库概述 向量数据库是一种专门用于存储和检索高维向量数据的数据库系统&#xff0c;它能够高效地处理基于向量相似性的查询&#xff0c;如最近邻搜索等&#xff0c;在人工智能、机器学习等领域的应用中发挥着重要作用&#xff0c;为处理复杂的向量数据提供了有力的…...

时序数据库IoTDB安装学习经验分享

1. JDK安装问题 在安装IoTDB时&#xff0c;我遇到了“无法加载主类”的错误&#xff0c;这通常表明Java环境存在问题。尽管我能正确输出classpath和查询JDK版本&#xff0c;但问题依旧存在。经过查阅相关资料&#xff0c;我发现问题出在多余的classpath设置上。Java编译器和虚…...

RapidOCR集成PP-OCRv5_det mobile模型记录

该文章主要摘取记录RapidOCR集成PP-OCRv5_mobile_det记录&#xff0c;涉及模型转换&#xff0c;模型精度测试等步骤。原文请前往官方博客&#xff1a; https://rapidai.github.io/RapidOCRDocs/main/blog/2025/05/26/rapidocr%E9%9B%86%E6%88%90pp-ocrv5_det%E6%A8%A1%E5%9E%8B…...

当 Redis 作为缓存使用时,如何保证缓存数据与数据库(或其他服务的数据源)之间的一致性?

当 Redis 作为缓存使用时&#xff0c;保证缓存数据与数据库&#xff08;或其他数据源&#xff09;之间的一致性是一个核心挑战。通常&#xff0c;我们追求的是“最终一致性”&#xff0c;而不是“强一致性”&#xff0c;因为强一致性往往会牺牲性能和可用性&#xff0c;这与使用…...

Dify理论+部署+实战

概述 一个功能强大的开源AI应用开发平台&#xff0c;融合后端即服务&#xff08;Backend as Service&#xff09;和LLMOps理念&#xff0c;使开发者能够快速搭建生产级的生成式AI应用。 核心优势 直观的用户界面&#xff1a;提供简洁明了的操作界面&#xff0c;使得用户能够…...

内网穿透系列五:自建SSH隧道实现内网穿透与端口转发,Docker快速部署

​以下是对这个自建SSH隧道工具的简单介绍&#xff1a; 一款基于OpenSSH构建的内网穿透与端口转发工具&#xff0c;通过SSH隧道技术实现支持所有TCP协议通信&#xff0c;包括SSH、HTTP、HTTPS等各类应用提供灵活部署方式&#xff0c;特别支持Docker容器化快速部署开源工具地址…...

桥梁进行3D建模时的数据采集、存储需求及技术参数

桥梁进行3D建模时的数据采集、存储需求及技术参数 1公里桥梁进行3D建模时的数据采集、存储需求及技术参数的详细分析 1. 照片数量估算 关键影响因素 桥梁类型&#xff1a;梁桥/拱桥/斜拉桥&#xff08;结构复杂度不同&#xff09; 建模精度&#xff1a;工程级&#xff08;1-…...

Transformer架构技术学习笔记:从理论到实战的完整解析

引言&#xff1a;重新定义序列建模的里程碑 2017年&#xff0c;Vaswani等人在论文《Attention Is All You Need》中提出的Transformer架构&#xff0c;彻底改变了自然语言处理领域的游戏规则。与传统RNN/LSTM相比&#xff0c;Transformer具有三大革命性特征&#xff1a; 全注意…...

1、python代码实现与大模型的问答交互

一、基础知识 1.1导入库 torch 是一个深度学习框架&#xff0c;用于处理张量和神经网络。modelscope是由阿里巴巴达摩院推出的开源模型库。 AutoTokenizer 是ModelScope 库的类&#xff0c;分词器应用场景包括自然语言处理&#xff08;NLP&#xff09;中的文本分类、信息抽取…...

CPU服务器的主要功能有哪些?

服务器作为互联网社会中基础的网络设施&#xff0c;为企业提供了存储和传输文件的功能&#xff0c;而中央处理器作为服务器计算能力的核心部分&#xff0c;能够帮助企业进行十分复杂的科学计算任务&#xff0c;本文就主要来探索一下CPU服务器的主要功能都有哪些吧&#xff01; …...

如何在 Vue.js 中集成 Three.js —— 创建一个旋转的 3D 立方体

在这篇文章中&#xff0c;我将向大家展示如何将 Three.js 与 Vue.js 结合&#xff0c;创建一个简单的 3D 场景&#xff0c;并展示一个旋转的立方体。通过这个简单的示例&#xff0c;你将学习到如何在 Vue 项目中集成 Three.js&#xff0c;以及如何创建动态的 3D 内容。 1. 安装…...

Java开发经验——阿里巴巴编码规范实践解析6

摘要 本文深入解析了阿里巴巴编码规范在数据库设计和Java开发中的实践应用。详细阐述了数据库字段命名、类型选择、索引命名等规范&#xff0c;以及Java POJO类的对应规范。强调了字段命名的重要性&#xff0c;如布尔字段命名规则、表名和字段名的命名禁忌等。同时&#xff0c…...

docker常见考点

一、基础概念类 Docker与虚拟机的区别 Docker基于容器化技术&#xff0c;共享宿主机内核&#xff0c;资源消耗更少&#xff1b;虚拟机通过Hypervisor虚拟化硬件&#xff0c;资源占用高。Docker启动速度更快&#xff08;秒级&#xff09;&#xff0c;虚拟机需要启动完整操作系统…...

工业自动化实战:基于 VisionPro 与 C# 的机器视觉 PLC 集成方案

一、背景介绍 在智能制造领域&#xff0c;机器视觉检测与 PLC 控制的无缝集成是实现自动化生产线闭环控制的关键。本文将详细介绍如何使用 C# 开发上位机系统&#xff0c;实现 Cognex VisionPro 视觉系统与西门子 S7 PLC 的数据交互&#xff0c;打造高效、稳定的工业检测方案。…...

C++ —— B/类与对象(中)

&#x1f308;个人主页&#xff1a;慢了半拍 &#x1f525; 创作专栏&#xff1a;《史上最强算法分析》 | 《无味生》 |《史上最强C语言讲解》 | 《史上最强C练习解析》|《史上最强C讲解》 &#x1f3c6;我的格言&#xff1a;一切只是时间问题。 ​ 目录 一、类的6个默认成员…...

Java网络编程与Socket安全权限详解

Socket安全权限控制 Java通过java.net.SocketPermission类实现对网络套接字访问的细粒度控制。该权限管理机制通常在Java策略文件中配置,其标准授权语法格式如下: grant {permission java.net.SocketPermission"target", "actions"; };目标主机与端口规…...

AXI协议乱序传输机制解析:提升SoC性能的关键设计

AXI 协议 Out-of-Order 传输机制 概述 AXI (Advanced eXtensible Interface) 协议支持乱序传输 (Out-of-Order) 机制&#xff0c;这是一种重要的性能优化特性&#xff0c;允许数据传输不按照发起顺序完成&#xff0c;从而提高总线带宽利用率和系统整体性能。 基本原理 通道…...

Qt实现csv文件按行读取的方式

Qt实现csv文件按行读取的方式 场景:我有一个保存数据的csv文件,文件内保存的是按照行保存的数据,每行数据是以逗号为分隔符分割的文本数据。如下图所示: 现在,我需要按行把这些数据读取出来。 一、使用QTextStream文本流的方式读取 #include <QFile>void readfil…...

分库分表后的 ID 生成方案

分库分表后的 ID 生成方案 一、问题背景 在分布式系统中,当单表数据量超过千万级时,通常会采用分库分表策略。此时传统的自增ID方案会面临以下问题: 不同分片可能生成相同ID(冲突)单调递增特性被破坏全局唯一性难以保证关键结论:分库分表环境下,ID生成必须满足全局唯一…...

进行性核上性麻痹健康护理全指南:从症状管理到生活照护

进行性核上性麻痹&#xff08;PSP&#xff09;是一种罕见的神经退行性疾病&#xff0c;主要影响运动、平衡及眼球运动功能&#xff0c;常表现为步态不稳、吞咽困难、眼球上视受限、情绪改变等。由于目前尚无根治方法&#xff0c;科学的健康护理对延缓病情进展、提升患者生活质量…...

openFuyao开源发布,建设多样化算力集群开源软件生态

openFuyao 开源发布 随着 AI 技术的高速发展&#xff0c;算力需求呈爆发式增长&#xff0c;集群已成为主流生产方式。然而&#xff0c;当前集群软件生态发展滞后于硬件系统&#xff0c;面临多样化算力调度困难、超大规模集群软件支撑不足等挑战。这些问题的根源在于集群生产的…...

第四十五节:目标检测与跟踪-Meanshift/Camshift 算法

引言 在计算机视觉领域,目标跟踪是实时视频分析、自动驾驶、人机交互等应用的核心技术之一。Meanshift和Camshift算法作为经典的跟踪方法,以其高效性和实用性广受关注。本文将从原理推导、OpenCV实现到实际案例,全面解析这两种算法的核心思想与技术细节。 一、Meanshift算法…...

Docker Desktop无法在windows低版本进行安装

问题描述 因工作需要&#xff0c;现在一台低版本的window系统进行Docker Desktop的安装&#xff0c;但是安装过程当中出现了报错信息 系统版本配置 原因分析&#xff1a; 关于本机查看了系统的版本号&#xff0c;版本号如下为1909,但是docker Desktop要求的最低的win10版本…...

SQL Server 简介和与其它数据库对比

SQL Server 是微软&#xff08;Microsoft&#xff09;开发的一种 关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;全称是 Microsoft SQL Server。 &#x1f50d; SQL Server 是什么&#xff1f; SQL Server 是一个功能强大、企业级的数据库平台&#xff0c;用…...

2025年- H56-Lc164--200.岛屿数量(图论,深搜)--Java版

1.题目描述 2.思路 &#xff08;1&#xff09;主函数&#xff0c;存储图结构 &#xff08;2&#xff09;主函数&#xff0c;visit数组表示已访问过的元素 &#xff08;3&#xff09;辅助函数&#xff0c;用递归&#xff08;深搜&#xff09;&#xff0c;遍历以已访问过的元素&…...

自证式推理训练:大模型告别第三方打分的新纪元

1. 传统验证体系的困境与技术跃迁的必然性 1.1 传统验证器的局限性 现有强化学习框架依赖显式验证器对答案进行二值化判定&#xff0c;这种模式在数学、代码等可验证领域表现优异。某厂内部数据显示&#xff0c;传统R1-Zero方法在代码生成任务中准确率达92%&#xff0c;但切换…...

vue2使用el-tree实现两棵树间节点的拖拽复制

原文链接&#xff1a;两棵el-tree的节点跨树拖拽实现 参照这篇文章&#xff0c;把它做成组件&#xff0c;新增左侧树&#xff08;可拖出&#xff09;被拖节点变灰提示&#xff1b; 拖拽中&#xff1a; 拖拽后&#xff1a; TreeDragComponent.vue <template><!-- …...

前端开发中 <> 符号解析问题全解:React、Vue 与 UniApp 场景分析与解决方案

前端开发中 <> 符号解析问题全解&#xff1a;React、Vue 与 UniApp 场景分析与解决方案 在前端开发中&#xff0c;<> 符号在 JSX/TSX 环境中常被错误解析为标签而非比较运算符或泛型&#xff0c;导致语法错误和逻辑异常。本文全面解析该问题在不同框架中的表现及解…...