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

C++ --> string类模拟实现(附源码)

欢迎来到我的Blog,点击关注哦💕

前言:

C++中STL扮演着极其重要的角色,学习C++重中之重的就是学习STL,虽然string不作为containers的其中一员,但是也是值得学习的le类。下面就进行string的模拟实现

string的模拟实现和顺序表是差不多,就是增加了C++的特性。

string 模拟实现

存储结构

结构上使用命名空间mystr进行封装,防止与库冲突,使用class封装成为对象string:

  • 定义 _size 方便记录string的大小。
  • 定义 _capacity方便记录string的容量大小
  • 定义 char* _str是存储数据,进行动态new出空间
  • nopsnpos用于表示在字符串中未找到所查找的子串,或者表示一个超出字符串长度的有效索引位置。npos的值通常被定义为std::size_t类型的最大值,这是一个无符号整数类型,因此npos实际上是一个非常大的正整数,用于表示没有找到匹配项或字符串的结束位置.
namespace mystr
{class string{public:static const size_t npos = -1;private:		size_t _size;size_t _capacity;char* _str;};
}

默认构造函数

构造函数

  • 全缺省的构造函数也是默认构造函数,结尾给""常量字符串末尾存在\0;
  1. 默认构造函数:全缺省、无参、编译器默认生成的构造函数称之为默认构造函数
  • 采取初始化列表,对于常量引用可以进行初始化。strlen计算出大小,初始化_size
    2. 注意:初始化顺序就是声明的顺序,这个也是为什么将char* _str放在最后;
  • _capacoty初始化容量+1的目的是给\0开辟空间;
  • 最后将str进行拷贝,这里采用memcpy不采用strcpy
    3. memcpy可以将全部内容拷贝,strcpy会识别\0停止,假使字符串hello\0 world构造就不会得到我们想要的结果
string(const char* str = ""):_size(strlen(str)), _capacity(_size), _str(new char[_capacity + 1]){	memcpy(_str, str, _capacity + 1);}

拷贝构造函数

  • 众所周知的是当不存在拷贝构造函数,编译器会自动生成拷贝构造函数;
    1. 编译器生成的仅仅会实现数值上的拷贝(浅拷贝)
    2. _strnew出空间,要实现内容上的拷贝(深拷贝)
  • _capacoty初始化容量+1的目的是给\0开辟空间;
string(const string& s)
{_capacity = s._capacity;_size = s._size;_str = new char[s._capacity+1];memcpy(_str, s._str, _capacity+1);
}

赋值运算符重载

赋值预算符重载的底层逻辑是和拷贝构造函数是一样的,在这里就不过多介绍了

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

析构函数

程序的整个历程开辟空间,不进行空间的释放不是一个好的习惯,这里析构函数就要上场了

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

迭代器(iterator)

  • string的迭代器的本质就是指针,根据C语言的指针很容易就可以理解,就是将 char * 进行

    typefed char* iterator

  • 迭代器实现两个版本 const非const只读可读可写

begin()

iterator begin()
{return _str;
}iterator begin()const 
{return _str;
}

end()

iterator end()
{return _str + _size;
}iterator end()const
{return _str + _size;
}

容量(capacity)

size

  • mstr::string类定义了_size直接将其返回
size_t size()const
{
return _size;
}

capacity

  • mstr::string类定义了_capacity直接将其返回
size_t capacity() const
{return _capacity;
}

resize

  • resize是将后面指定大小初始化指定的字符(缺省:\0
  • 进行容量的检查,不够扩容
  • 一层循环初始化为ch
  • 修改_size长度为n
void resize(size_t n,char ch = '\0')
{if (n < _size){_str[n ] = '\0';_size = n;}else{reverse(n);for (size_t i = _size; i < n; i++){_str[i] = ch;}_str[_size] = '\0';_size = n;}}

reverse

  • 由于很多地方进行复用,需要在函数内部进行判断提高效率
  • 开辟一个大于原始空间的新的空间,将 _str拷贝过去,改变_str的指向,将新开辟的空间释放谨防内存泄漏
void reverse(size_t n)
{if (n > _capacity){char* tmp = new char[n + 1];memcpy(tmp, _str, _capacity + 1);delete[] _str;_capacity = n;_str = tmp;}}

empty

直接判断_size是否为0即可

bool empty()const
{
return _size == 0 ? true : false;
}

clear

  • 直接将首位置赋值为\0,修改_size大小即可
void clear()
{_str[0] = '\0';_size = 0;
}

修改(modify)

push_back

C++string中 push_back 函数声明:void push_back (char c);在字符串后追加一个字符;

  • 开始要检查容量 进行扩容这里用 reverse 实现
  • 由于一个字符,仅仅需要在_size位置上直接赋值,在_size+1的位置上赋值\0
 void push_back(char ch)
{if (_size == _capacity){reverse(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_str[_size + 1] = '\0';_size++;
}

append

  • append后面追加一个字符可以进行复用 push_back
  • append后面追加一个字符串和添加一个string类是一样的思路是一样;
//追加一个字符
void append(const char ch)
{
push_back(ch);
}
//追加一个字符串
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
reverse(_capacity + len);
}
memcpy(_str + _size, str, len + 1);
}
//追加一个string类
void append(const string& str)
{
if (_size + str._size == _capacity)
{
reverse(_size + str._size);
}memcpy(_str + _size, str._str, str._size+1);
}

operator+=

由于是实现了append实现运算符重载就方便跟多,功能一样,结果一样直接进行复用

//追加一个字符
string& operator+= (const char* str)
{append(str);return *this;
}
//追加一个字符串
string& operator+= (const string& str)
{append(str._str);return *this;
}
//追加一个string类
string& operator+= (char ch)
{push_back(ch);return *this;
}

inset

  • 实现两个版本,插入字符和插入字符串

  • string类是没有实现push_front头插入,insert就有很大的作用了在pos位置进行插入

  • 首先进行pos位置的断言,保证pos在字符串的有效位置

  • 进行容量检查,进行扩容.

  • pos位置后面的字符(以及pos位置)依次向后面移len个长度,在pos位置插入字符(字符串)

  • i!= nposfor循环中如果i变成了0,之后再去减1 ,size_t下的-1会变为无线大,会陷入死循环。

  • 最后不要忘记将_size进行修改

//插入字符
string& insert(size_t pos, char c)
{assert(pos < _size);if (_capacity == _size){reverse(_size+1);}for (size_t i = _size; i >= pos&& i!= npos; i--){_str[i + 1] = _str[i];}_str[pos] = c;_size++;return *this;
}
//插入字符串
string& insert(size_t pos, const char* str)
{assert(pos < _size);size_t len = strlen(str);if (_capacity == _size){			reverse(_size + len);}for (size_t i = _size; i >= pos&& i!= npos; i--){_str[i + len] = _str[i];}memcpy(_str + pos, str, len);_size+=len;return *this;}

erase

  • 首先进行pos位置的断言,保证pos在字符串的有效位置

  • erase是在pos位置删除len个字符(缺省值:npos

  • 函数主体进入进len的判断,如果len == npos pos + len >= _size超出字符串的长度,就是从pos后全部删除

  • 否则没有超过将pos + len位置后面的数据将 pos位置移动直至移动到\0

string& erase(size_t pos, size_t len = npos)
{assert(pos < _size);if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos;}else{size_t end = pos + len;while (end <= _size){_str[pos++] = _str[end++];}_size -= len;}}

swap

  • 利用C++库中的swap进行string类的交换
void swap(string& s)
{
string tmp(s);
std::swap(_str, tmp._str);
std::swap(_size, tmp._size);
std::swap(_capacity, tmp._capacity);
}

元素访问(Element access)

operator [ ]

  • 实现const非const两种,只读和可读可改
  • 充分利用字符串特性可以进行下标的访问
//const
char& operator[](size_t index)
{assert(index < _size);return _str[index];
}
//nonconst
const char& operator[](size_t index)const
{assert(index < _size);return _str[index];
}

字符串操作(String operations)

c_str

  • 直接返回_str
const char* c_str()
{return _str;
}

find

  • 首先进行pos位置的断言,保证pos在字符串的有效位置
  • 字符串查找利用C语言中的strstr函数进行查找
  • 返回下面的下标,利用指针减指针的方法,没有找到返回npos
size_t find(const char* s, size_t pos = 0) const
{assert(pos < _size);char* p = strstr(_str, s);if (p){return p - _str;}else{return npos;}}

关系运算符(relational operators)

进行比较的重载

  • 实现< ==其他的进行复用即可
  • 使用memcpy进行比较,比较字符串较小的那个_size < s._size ?_size : s._size
  • 返回 为 0 返回比较长(_size < s._size)的那个否则返回假( ret < 0
//重载<
bool operator<(const string& s)
{int ret = memcmp(_str, s._str, (_size < s._size ?_size : s._size));return ret == 0 ? _size < s._size : ret < 0;
}
//重载==
bool operator==(const string& s)
{return _size == s._size && memcmp(_str, s._str, _size);
}
//重载<=
bool operator<=(const string& s)
{return !(*this > s);
}
//重载>
bool operator>(const string& s)
{return !(*this <= s);
}
//重载>=
bool operator>=(const string& s)
{return !(*this < s);
}
//重载!=
bool operator!=(const string& s)
{return !(*this == s);
}

流提取和插

operator<<

  • 这个函数是写在类外面的一个友元函数
  • 使用范围for进行实现
ostream& operator<<(ostream& out, const mystr::string& s)
{for (auto ch : s){out << ch;}return out;
}

operator>>

  • s.clear();这句话是清理缓冲区上次cin的残留
  • 第一个while循环是处理缓冲区的空格
  • 创建一个数组,避免多次开辟空间,直至大小到128拷贝会加到string s 中
  • 最后的if语句是字符遇见空格或者换行结束,末尾添加\0
istream& operator>>(istream& in, string& s)
{s.clear();char ch = in.get();// 处理前缓冲区前面的空格或者换行while (ch == ' ' || ch == '\n'){ch = in.get();}char buff[128];int i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if (i != 0){buff[i] = '\0';s += buff;}return in;
}

mystr:: string 源码

#pragma once#include<iostream>#include<string.h>
#include <assert.h>
#include <stdlib.h>using namespace std;namespace mystr
{class string{friend ostream& operator<<(ostream& _cout, const mystr::string& s);friend istream& operator>>(istream& _cin,mystr::string& s);public:typedef char* iterator;typedef const char* const_iterator;string(const char* str = ""):_size(strlen(str)), _capacity(_size), _str(new char[_capacity + 1]){	memcpy(_str, str, _capacity + 1);}//析构函数~string(){_size = 0;_capacity = 0;delete[] _str;_str = nullptr;}// 拷贝构造函数string(const string& s){_capacity = s._capacity;_size = s._size;_str = new char[s._capacity+1];memcpy(_str, s._str, _capacity+1);}//赋值预算符重载string& operator=(const string& s){_capacity = s._capacity;_size = s._size;_str = new char[_capacity + 1];memcpy(_str, s._str, _capacity + 1);}const char* c_str(){return _str;}//迭代器iterator begin(){return _str;}iterator end(){return _str + _size;}iterator begin()const {return _str;}iterator end()const{return _str + _size;}//capacitysize_t size()const{return _size;}size_t capacity() const{return _capacity;}void reverse(size_t n){if (n > _capacity){char* tmp = new char[n + 1];memcpy(tmp, _str, _capacity + 1);delete[] _str;_capacity = n;_str = tmp;}}void resize(size_t n,char ch = '\0'){if (n < _size){_str[n ] = '\0';_size = n;}else{reverse(n);for (size_t i = _size; i < n; i++){_str[i] = ch;}_str[_size] = '\0';_size = n;}}bool empty()const{return _size == 0 ? true : false;}//access//modifyvoid push_back(char ch){if (_size == _capacity){reverse(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_str[_size + 1] = '\0';_size++;}void append(const char ch){push_back(ch);}void append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){reverse(_capacity + len);}memcpy(_str + _size, str, len + 1);}void append(const string& str){if (_size + str._size == _capacity){reverse(_size + str._size);}memcpy(_str + _size, str._str, str._size+1);}string& operator+= (const char* str){append(str);return *this;}string& operator+= (const string& str){append(str._str);return *this;}string& operator+= (char ch){push_back(ch);return *this;}void clear(){_str[0] = '\0';_size = 0;}void swap(string& s){string tmp(s);std::swap(_str, tmp._str);std::swap(_size, tmp._size);std::swap(_capacity, tmp._capacity);}//relational operatorsbool operator<(const string& s){int ret = memcmp(_str, s._str, (_size < s._size ?_size : s._size));return ret == 0 ? _size < s._size : ret < 0;}bool operator==(const string& s){return _size == s._size && memcmp(_str, s._str, _size);}bool operator<=(const string& s){return !(*this > s);}bool operator>(const string& s){return !(*this <= s);}bool operator>=(const string& s){return !(*this < s);}bool operator!=(const string& s){return !(*this == s);}// 返回c在string中第一次出现的位置size_t find(char c, size_t pos = 0) const{assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == c){return i;}}return npos;}// 返回子串s在string中第一次出现的位置size_t find(const char* s, size_t pos = 0) const{assert(pos < _size);char* p = strstr(_str, s);if (p){return p - _str;}else{return npos;}}// 在pos位置上插入字符c/字符串str,并返回该字符的位置string& insert(size_t pos, char c){assert(pos < _size);if (_capacity == _size){reverse(_size+1);}for (size_t i = _size; i >= pos; i--){_str[i + 1] = _str[i];}_str[pos] = c;_size++;return *this;}string& insert(size_t pos, const char* str){assert(pos < _size);size_t len = strlen(str);if (_capacity == _size){			reverse(_size + len);}for (size_t i = _size; i >= pos; i--){_str[i + len] = _str[i];}memcpy(_str + pos, str, len);_size+=len;return *this;}string& erase(size_t pos, size_t len = npos){assert(pos < _size);if (_capacity == _size){reverse(_size + len);}if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos;}else{size_t end = pos + len;while (end <= _size){_str[pos++] = _str[end++];}_size -= len;}}private:		size_t _size;size_t _capacity;char* _str;public:const static size_t npos;};const size_t string::npos = -1;ostream& operator<<(ostream& out, const mystr::string& s){for (auto ch : s){out << ch;}return out;}istream& operator>>(istream& in, string& s){//清除缓冲区s.clear();char ch = in.get();while (ch == ' ' || ch == '\n'){ch = in.get();}char buff[128];int i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if (i!= 0){buff[i] = '\0';s += buff;}return in;}}                                                                                              

相关文章:

C++ --> string类模拟实现(附源码)

欢迎来到我的Blog&#xff0c;点击关注哦&#x1f495; 前言&#xff1a; C中STL扮演着极其重要的角色&#xff0c;学习C重中之重的就是学习STL&#xff0c;虽然string不作为containers的其中一员&#xff0c;但是也是值得学习的le类。下面就进行string的模拟实现 string的模拟…...

基于PHP+MySQL组合开发的微信活动投票小程序源码系统 带完整的安装代码包以及搭建部署教程

系统概述 在当今数字化时代&#xff0c;微信作为社交媒体的巨头&#xff0c;为企业和个人提供了丰富的互动营销平台。其中&#xff0c;投票活动作为一种有效的用户参与和互动方式&#xff0c;被广泛应用于各种场景。为了满足这一需求&#xff0c;我们推出了一款基于PHPMySQL组…...

利用Arcgis设置分式标注(分子分母标注)

因工作需要&#xff0c;需要设置分式标注&#xff0c;下面详细介绍下如何利用arcgis 设置分式标注&#xff0c;以下操作以供参考&#xff0c;如有疑义可提出。 一、准备工作 软件&#xff1a;arcmap 示例数据&#xff1a;行政区shp矢量图 二、操作步骤 1.添加数据 将行政区sh…...

大麦网抢票攻略:使用Python Selenium实现

随着互联网技术的发展&#xff0c;在线购票已成为人们获取演出、比赛等活动门票的主要方式。然而&#xff0c;面对热门活动&#xff0c;门票往往在开售瞬间被抢购一空。为了解决这一问题&#xff0c;本文将介绍如何利用Python和Selenium技术实现大麦网的自动抢票。 1. 环境准备…...

Navicat 在整个数据库中查找字符

Navicat 在整个数据库中查找字符 1.首先打开Navicat,连接目标数据库。2.选择工具选项卡&#xff0c;选择在数据库或模式中查找。3.查找前填入关键字信息&#xff0c;点击查找4.双击查找到数据&#xff0c;进行查看 说明&#xff1a;当我们知道数据库有数据的关键字&#xff0c;…...

Python基础—处理时间问题

一文帮助您解决99%时间处理问题...

如何选择合适的自动化测试工具!

选择合适的自动化测试工具是一个涉及多方面因素的决策过程。以下是一些关键步骤和考虑因素&#xff0c;帮助您做出明智的选择&#xff1a; 一、明确测试需求和目标 测试范围&#xff1a;确定需要自动化的测试类型&#xff08;如单元测试、集成测试、UI测试等&#xff09;和测试…...

数字图像边缘曲率计算及特殊点检测

一、曲率和数字图像边缘曲率检测常用方法简介 边缘曲率作为图像边缘特征的重要参数&#xff0c;不仅反映了边缘的几何形状信息&#xff0c;还对于图像识别、图像分割、目标跟踪等任务具有显著影响。 曲线的曲率&#xff08;curvature&#xff09;就是针对曲线上某个点的切线方向…...

python map

在 Python 中&#xff0c;如果你指的是字典&#xff08;dictionary&#xff09;&#xff0c;可以使用字典的 .items() 方法来遍历键值对。Python 中没有严格意义上的 Map 类型&#xff0c;而是使用字典来实现类似于键值对映射的功能。 遍历字典的键值对 可以使用 for 循环和 …...

每日一练 - NFV部署应用环境

01 真题题目 NFV 常常部署在下列哪些应用环境中?(多选) A.数据中心 B.网络节点 C.用户接入侧 D.客户机/服务器 02 真题答案 ABC 03 答案解析 NFV&#xff08;Network Functions Virtualization&#xff0c;网络功能虚拟化&#xff09;是一种技术&#xff0c;它允许在标准的…...

031-GeoGebra中级篇-GeoGebra的布尔值

在 GeoGebra 中&#xff0c;布尔值和条件判断是实现动态数学模型和交互式几何图形的重要工具。布尔值&#xff0c;即逻辑值&#xff0c;只有两个可能的取值&#xff1a;真&#xff08;True&#xff09;或假&#xff08;False&#xff09;。通过使用布尔值&#xff0c;我们可以创…...

基于Debian用户安装星火商店

星火商店下载地址&#xff1a;https://www.spark-app.store/ 本文章我以kali linux来做示范 注:基本debian的linux包括ubuntu,mint linux,kali linux,Pop!_OS,deepin等等 1.点击下载最新版本 2.点击下载 3.点击开始下载&#xff08;它会自动跳转网页&#xff09; 4.选择要下载…...

《计算机网络》(第8版)课后习题答案

【1-01】 计算机网络可以向用户提供哪些服务? 解答:这道题没有现成的标准答案,因为可以从不同的角度来看“服务”。 首先要明确的是,计算机网络可以向用户提供的最重要的功能有两个:连通性和共享。所 谓连通性,就是计算机网络使上网用户之间都可以交换信息,好像这些用户…...

我们的网站被狗爬了!

大家好&#xff0c;我是程序员鱼皮。 世风日下&#xff0c;人心不古。我们的程序员面试刷题网站 《面试鸭》 才刚刚上线了一个多月&#xff0c;就由于过于火爆&#xff0c;被不少同行和小人发起网络攻击。 而且因为我们已经有 4500 多道人工整理的企业高频面试题、100 多个各…...

docker安装与container基本使用

安装 Homebrew 的 Cask 已经支持 Docker for Mac, mac用户狂喜 brew install --cask --appdir/Applications docker其他入门用法可参考 Docker Hello World- 菜鸟教程 或网上自行搜索博客学习。本文主要记录我运行go-zero-mall用到的一些注意点。当然&#xff0c;gonivinck项…...

掌握文本搜索的利器:深入解析 Linux grep 命令的强大功能

grep 是一个强大的命令行工具,用于在文件中搜索指定的模式(字符串或正则表达式)。它的名字来源于 "global regular expression print",常用于文本处理、日志分析等任务。以下是 grep 命令的详细介绍和常用操作: 基本用法 搜索匹配的行 grep "pattern"…...

【天机学堂】面试总结

写在前面&#xff0c;首先要将天机学堂包装一下&#xff0c;智慧教育平台》&#xff0c;暂时就想到这个。天机学堂文档 1.包装简历 待更新。。。...

Java中Stream操作

Java中Stream操作 Stream 和 Optional区别 用途不同&#xff1a;Stream 用于处理集合中的元素序列&#xff0c;支持丰富的中间操作和终端操作&#xff1b;Optional 用于表示一个值可能为 null 的情况&#xff0c;提供了一种更优雅的处理方式。数据处理 vs. 容器&#xff1a;S…...

Spring Boot + MinIO 实现文件的分片上传、秒传、续传功能

文件上传是一个常见的功能需求。然而,传统的文件上传方式在面对大文件或不稳定的网络环境时,可能会出现性能瓶颈和上传失败的问题。为了解决这些问题,分片上传、秒传和续传技术应运而生. 技术选型 Spring Boot:一个快速开发框架,简化了 Spring 应用的搭建和配置。 MinIO:…...

Kafka基本概念,工作流程介绍

1、消息队列与Kafka 1.1、Kafka简介 Kafka使用scala开发&#xff0c;支持多语言客户端&#xff08;c、java、python、go等&#xff09; Kafka最先由LinkedIn公司开发&#xff0c;之后成为Apache的顶级项目。 Kafka是一个分布式的、分区化、可复制提交的日志服务 LinkedIn使…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)

LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 题目描述解题思路Java代码 题目描述 题目链接&#xff1a;LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...

「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案

在移动互联网营销竞争白热化的当下&#xff0c;推客小程序系统凭借其裂变传播、精准营销等特性&#xff0c;成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径&#xff0c;助力开发者打造具有市场竞争力的营销工具。​ 一、系统核心功能架构&…...