C++STL——string类与模拟实现

news2025/7/19 16:53:22

STL容器——string类

  • 什么是STL
  • string类
    • 字符串的标准
    • 什么是string
    • string常用接口介绍
      • string的初始化
      • 比较大小与赋值
      • 容量
      • 对象的修改
      • 访问及遍历操作
      • string中的swap与C++库中的swap的区别
      • 非成员函数
  • string类的模拟实现
    • 深浅拷贝与现代写法

什么是STL

STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。
STL的六大组成:仿函数,算法,迭代器,空间配置器,容器,配接器。
注意:
这里我是按照功能归类讲string归类到了STL里面,如果按照发展史其实并不属于STL中的容器。
并且从现在开始我们会更频繁的开始使用这个网站了:
cpulspuls

string类

为什么要学习string呢?C语言中字符串是以‘\0’结尾的,C语言当中提供的str库函数是与字符串分开的,很可能越界访问,也不方便管理,C++主要是OOP思想(抽象”、“封装”、“继承”、“多态),所以出现了string,并且更方便增删查改。

字符串的标准

计算机是二进制,但是如果让我们去理解一堆0和1组成的是什么意思很难理解,所以就有了编码(计算机存值——文字符号,对应关系):
在这里插入图片描述
这些符号就可以组成很多东西了,比如数值,单词等等。
如果你想储存abc,那么在内存中储存的就是

97 98 99

想让计算机流通全世界,那么就要支持各个国家的语言,这个时候就出现了统一码。
在UTF-8中将常用的汉字用两个字节去存储,256*256=65536。(但是这里要兼容ASCII码值所以没有这么多)
有些生僻字需要三个或者四个字节去储存。
UTF-16不兼容ASCII码值,起步用2个字节。
UTF-32不兼容ASCII码值,起步用4个字节。

但是中华文化博大精深,国内又针对函数定义了新的标准,GBK。

什么是string

string是字符串的类,该类添加了很多接口便于操作string类。
string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;
不能操作多字节和变长字节序列。
cplusplus中是这样描述的:
在这里插入图片描述

string常用接口介绍

string的初始化

string()构造空string类的对象
string(const char* s)用字符串初始化新构造string类的的对象
string(const string&s)用string类对象构造新的string类对象

这类接口是调用构造函数。

#include <iostream>
#include <string>
using namespace std;

int main()
{
	string s("abc");//创建string类s,给s初始化abc
	cout << s << endl;
	string s1;//创建string类s1,不进行初始化
	cout << s1 << endl;
	string s2(s);//将s拷贝到s2中
	cout << s2 << endl;
	return 0;
}

在这里插入图片描述

比较大小与赋值

比较的是字符串的ASCII码值。
这些接口都是对于运算符进行重载。
先来看赋值:

string& operator= (const string& str);赋值string类的对象
string& operator= (const char* s);赋值字符串
string& operator= (char c);赋值一个字符

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s1("abc");
	cout << s1 << endl;
	string s2;
	s2 = s1;//赋值string类的对象
	cout << s2 << endl;
	string s3;
	s3 = "adc";//赋值字符串
	cout << s3 << endl;
	s3 = 's';//赋值一个字符
	cout << s3 << endl;
	return 0;
}

在这里插入图片描述
等于,大于,小于等:
返回值为bool,参数是引用类。
正确返回1,错误返回0.

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s1("abc");
	string s2("adc");
	string s3("abc");
	string s4("abb");
	cout << "==:" << endl;
	cout << (s1 == s2) << endl;
	cout << (s1 == s3) << endl;
	cout << "< <=:" << endl;
	cout << (s1 < s2) << endl;
	cout << (s1 <= s2) << endl;
	cout << (s1 < s3) << endl;
	cout << (s1 <= s3) << endl;
	cout << (s1 <= s4) << endl;
	cout << "> >=:" << endl;
	cout << (s1 > s2) << endl;
	cout << (s1 >= s2) << endl;
	cout << (s1 >= s3) << endl;
	cout << (s1 > s4) << endl;
	cout << (s1 >= s4) << endl;
	return 0;
}

在这里插入图片描述

容量

这里要注意容量和有效字符长度的区别。
size返回字符串有效长度
capacity返回有效容量长度

size_t size() const;
size_t capacity() const;

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("qwert");
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	return 0;
}

这里有一个与size功能相同的接口length。(原因是因为命名的习惯)
在这里插入图片描述
在这里插入图片描述
empty检测对象是否为空字符串,空返回1,非空返回0
clear清空对象中的有效字符串

bool empty() const;
void clear();

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("qwert");
	cout << s.empty() << endl;
	s.clear();//这里并不改变容量大小
	cout << s.empty() << endl;
	return 0;
}

在这里插入图片描述
reserve为字符串预留空间
resize将有效字符串变成指定长度,多出的长度用指定字符补上

void reserve (size_t n = 0);
void resize (size_t n);
void resize (size_t n, char c);

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s;
	s.reserve(1000);//不明原因会多出一些空间,至少是n
	cout << s.capacity() << endl;
	string s1("qwert");
	cout << s1 << endl;
	int sz = s1.size();
	s1.resize(4);//不到原本字符串长度就将后面的字符串覆盖
	cout << s1 << endl;
	s1 = "qwert";
	s1.resize(4, 'x');//不到原本字符串长度就将后面的字符串覆盖
	cout << s1 << endl;
	s1 = "qwert";
	s1.resize(8, 'x');//不足就用字符x补上
	cout << s1 << endl;
	return 0;
}

在这里插入图片描述

对象的修改

push_back在后面追加一个字符
append在后面追加一个字符串
operator+=在后面追加一个字符串或字符还有对象

void push_back (char c);
string& append (const char* s);
string& operator+= (const string& str);
string& operator+= (const char* s);
string& operator+= (char c);

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("qwe");
	string s1("123");
	s += 'r';
	cout << s << endl;
	s += "ty";
	cout << s << endl;
	s += s1;
	cout << s << endl;
	string s2("zxc");
	s2.push_back('v');
	cout << s2 << endl;
	s2.append("cpp");
	cout << s2 << endl;
	return 0;
}

在这里插入图片描述
insert在指定位置插入指定内容(不推荐,时间复杂度高)
pop_back尾删
erase从指定位置删除指定长度的字符(不推荐,时间复杂度高)
c_str返回C语言的字符串

string& insert (size_t pos, const string& str);
string& insert (size_t pos, const char* s);
void pop_back();
string& erase (size_t pos = 0, size_t len = npos);
const char* c_str() const;

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("qwert");
	string s1("zxc");
	s.insert(1, "ccc");
	cout << s << endl;
	s.insert(0, s1);
	cout << s << endl;
	s.pop_back();
	cout << s << endl;
	s.erase(2, 4);
	cout << s << endl;
	cout << s.c_str() << endl;//这里是为了方便做返回值
}

在这里插入图片描述
find + npos从指定位置向后查找指定位置的字符(npos是string类中特殊的静态常量-1)
rfind从指定位置向前查找指定位置的字符
substr从指定位置截取n个字符返回

size_t find (const string& str, size_t pos = 0) const;
size_t find (const char* s, size_t pos = 0) const;
size_t rfind (const string& str, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos = npos) const;
string substr (size_t pos = 0, size_t len = npos) const;

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("test.cpp");
	int num = s.find("st", 0);
	cout << num << endl;
	num = s.find("st", 5);
	cout << num << endl;
	num = s.rfind("cpp", 7);
	cout << num << endl;
	num = s.rfind("cpp", 4);
	cout << num << endl;
	string s1 = s.substr(0, 4);
	cout << s1 << endl;
	return 0;
}

在这里插入图片描述

访问及遍历操作

operator[]返回对象下标的元素
begin+ end迭代器,begin是字符串最开始的元素,end是字符串末尾的‘\0’
rbegin + rend反向迭代器

char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("qwert");
	cout << s[2] << endl;
	s = "123456";
	string::iterator left1 = s.begin();//可读可写
	string::const_iterator left2 = s.begin();//可读不可写
	while (left1 != s.end())
	{
		*left1 += 1;
		cout << *left1;
		left1++;
	}
	cout << endl;
	while (left2 != s.end())
	{
		cout << *left2;
		left2++;
	}
	cout << endl;
	string::reverse_iterator left3 = s.rbegin();
	string::const_reverse_iterator left4 = s.rbegin();
	while (left3 != s.rend())
	{
		*left3 += 1;
		cout << *left3;
		left3++;
	}
	cout << endl;
	while (left4 != s.rend())
	{
		cout << *left4;
		left4++;
	}
	cout << endl;
	return 0;
}

C++11语法中的for循环就是与迭代器有关。
在这里插入图片描述
这里还有一个类似于operator[]的接口是at,找到的就返回,找不到会抛异常。
在这里插入图片描述

string中的swap与C++库中的swap的区别

string::swap

void swap (string& x, string& y);
交换两个同类对象中的成员

#include <iostream>
#include <assert.h>
using namespace std;
int main()
{
	string s1("asdq7777777777777777777");
	string s2("qwe");
	s1.swap(s2);
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	cout << s2 << endl;
	cout << s2.size() << endl;
	cout << s2.capacity() << endl;
	return 0;
}

在这里插入图片描述
C++库swap
这是一个模板

template <class T> void swap ( T& a, T& b )
{
  T c(a); a=b; b=c;//这里其实就相当于调用了构造函数,因为T会有自定义类型
}

平时我们的内置类型都是不需要进行析构和构造的,但是内置类型进入模板之后就需要了。
使用时要注意深浅拷贝问题,自定义类型要调用 = 。

非成员函数

operator>>
operator<<流插入流提取

istream& operator>> (istream& is, string& str);
ostream& operator<< (ostream& os, const string& str);

这个就很熟悉了上面不知道用了多少。

string类的模拟实现

#include <iostream>
#include <assert.h>
using namespace std;
namespace baiye
{
	class string
	{
	public:
		typedef char* iterator;
		string(const char* s = "")//对象初始化,缺省值有一个隐藏的\0
		{
			_arr = new char[strlen(s) + 1];
			strcpy(_arr, s);
			_size = strlen(_arr);
			_capacity = _size;//实际可以储存的大小,不算\0的位置
		}
		~string()//析构
		{
			delete[] _arr;
			_arr = nullptr;
			_size = 0;
			_capacity = 0;
		}
		string(const string& s)//拷贝构造
			:_arr(nullptr)
			,_size(0)
			,_capacity(0)
		{
			string tmp(s._arr);
			swap(tmp);
		}
		string& operator=(string s)//这里不用引用就是临时变量,我们可以让它成为打工人
		{
			swap(s);
			return *this;
		}
		//iterator
		iterator begin()const
		{
			return _arr;
		}
		iterator end()const
		{
			return _arr + _size - 1;
 		}
		// modify
		const char* c_str()const
		{
			return _arr;
		}
		void push_back(char c)
		{
			if (_size == _capacity)
			{
				size_t len = _size == 0 ? 4 : _capacity * 2;//防止空对象扩容失败
				reserve(len);
			}
			_arr[_size] = c;
			_size++;//注意\0
			_arr[_size] = '\0';
		}
		void append(const char* str)
		{
			if (_size + strlen(str) > _capacity)
			{
				reserve(_size + strlen(str) + 1);//不能二倍扩容,万一新加的字符串更大就不行了
			}
			strcpy(_arr + _size, str);
			_size = strlen(_arr);
		}
		string& operator+=(char c)
		{
			push_back(c);
			return *this;
		}
		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}
		void clear()
		{
			_arr[0] = '\0';
			_size = 0;
		}
		void swap(string& s)
		{
			std::swap(_arr, s._arr);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		//capacity
		size_t size()const//返回长度
		{
			return _size;
		}
		size_t capacity()const//返回容量
		{
			return _capacity;
		}
		bool empty()const
		{
			return _size;
		}
		void resize(size_t n, char c = '\0')
		{
			if (n <= _size)
			{
				_arr[n] = '\0';
				_size = n;
			}
			else
			{
				reserve(n);
				while (_size < n)
				{
					_arr[_size] = c;
					_size++;
				}
				_arr[n] = '\0';
				_size = n;
			}
		}
		void reserve(size_t n)
		{
			char* tmp = new char[n + 1];//+1是为了算\0
			strcpy(tmp, _arr);
			delete[] _arr;
			_arr = tmp;
			_capacity = n;
		}
		// access
		char& operator[](size_t x)//可读可写
		{
			assert(x < _size);
			return _arr[x];
		}
		const char& operator[](size_t x)const//可读不可写
		{
			assert(x < _size);
			return _arr[x];
		}
		//relational operators
		int judge(const string& s)
		{
			return strcmp(_arr, s._arr);//1大于,0等于,-1小于
		}
		bool operator<(const string& s)
		{
			int a = judge(s);
			if (a < 0)
				return 1;
			return 0;
		}
		bool operator<=(const string& s)
		{
			int a = judge(s);
			if (a > 0)
				return 0;
			return 1;
		}
		bool operator>(const string& s)
		{
			int a = judge(s);
			if (a > 0)
				return 1;
			return 0;
		}
		bool operator>=(const string& s)
		{
			int a = judge(s);
			if (a < 0)
				return 0;
			return 1;
		}
		bool operator==(const string& s)
		{
			return !judge(s);
		}
		bool operator!=(const string& s)
		{
			return judge(s);
		}
		// 返回c在string中第一次出现的位置
		size_t find(char c, size_t pos = 0) const
		{
			assert(pos < _size);
			while (pos < _size)
			{
				if (_arr[pos] == c)
					return pos;
				pos++;
			}
			return npos;
		}
		// 返回子串s在string中第一次出现的位置
		size_t find(const char* s, size_t pos = 0) const
		{
			assert(pos < _size);
			const char * p =strstr(_arr + pos, s);
			if (p == nullptr)
			{
				return npos;
			}
			else
			{
				return p - _arr;
			}
		}
		// 在pos位置上插入字符c/字符串str,并返回该字符的位置
		string& insert(size_t pos, char c)
		{
			if (_size == _capacity)
			{
				size_t len = _size == 0 ? 4 : _capacity * 2;//防止空对象扩容失败
				reserve(len);
			}
			int end = _size + 1;
			while (end > pos)
			{
				_arr[end] = _arr[end - 1];
				end--;
			}
			_arr[pos] = c;
			_size++;
			return *this;
		}
		string& insert(size_t pos, const char* str)
		{
			int len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len + 1);//不能二倍扩容,万一新加的字符串更大就不行了
			}
			int end1 = _size + 1;
			int end2 = _size + len;
			while (end1 > pos)
			{
				_arr[end2] = _arr[end1 - 1];
				end1--;
				end2--;
			}
			strncpy(_arr + pos, str, len);
			_size = strlen(_arr);
			return *this;
		}
		// 删除pos位置上的元素,并返回该元素
		string& erase(size_t pos, size_t len = npos)//nops是默认值
		{
			if (len == npos || pos + len >= _size)//删除pos后面所有的数据
			{
				_arr[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_arr + pos, _arr + pos + len);
				_size -= len;
			}
			return *this;
		}
	private:
		char* _arr;//字符串储存的地方
		int _size;//大小
		int _capacity;//容量
		const static size_t npos = -1;//C++只允许整形的静态成员在类的内部进行初始化
	};
	ostream& operator<<(ostream& out, const string& s)//不一定非要是友元
	{
		for (int i = 0; i < s.size(); i++)
		{
			out << s[i];
		}
		return  out;
	}
	istream& operator >> (istream& in, string& s)
	{
		s.clear();//清空原来s中的内容
		char buff[128] = { '\0' };//船舰一个容纳输入数据的数组
		char c = in.get();
		int i = 0;
		while (c != ' ' && c != '\n')
		{
			if (i == 127)
			{
				i = 0;
				s += buff;//数组满了放入s中,防止s不断扩容
			}
			buff[i++] = c;
			c = in.get();
		}
		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}
		return in;
	}
}

深浅拷贝与现代写法

这里最重要的是深浅拷贝的现代写法,之前说过类的默认拷贝函数只能实现浅拷贝无法实现深拷贝,需要自定义拷贝函数,类与对象二。
现代写法是让一个新创建的对象帮你拷贝,然后与你进行交换,相当于你有了一个打工人。

string(const string& s)//拷贝构造
	:_arr(nullptr)//将被拷贝的对象进行初始化
	,_size(0)
	,_capacity(0)
{
	string tmp(s._arr);//打工人tmp
	swap(tmp);//这里虽然只传参了一个tmp,但是还有一个隐藏的this指针
}
string& operator=(string s)//这里不用引用就是临时变量,我们可以让它成为打工人
{
	swap(s);
	return *this;
}
void swap(string& s)
{
	std::swap(_arr, s._arr);
	std::swap(_size, s._size);
	std::swap(_capacity, s._capacity);
}

在这里插入图片描述
之后tmp的成员 _arr指向的就是空指针,进行析构也不会报错,其他成员全都变成0,而需要被拷贝的*this就成功的得到了想要的数据。

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

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

相关文章

WRFV3.8.1编译报错,无法显示exe文件

问题报错&#xff1a;在WRF中遇到了一个可能和ubuntu系统有关的报错&#xff0c;主要表现为random seed过小&#xff0c;找不到&#xff0c;无法进行compile&#xff0c;导致compile em_real后无法生成4个*.exe文件。第一个报错出现位置为&#xff1a;。附件为compile.log。 图…

【树莓派不吃灰】命令篇④ Linux 常用命令学习

目录1. 常用命令1.1 操作文件及目录1.2 系统常用命令1.3 压缩解压缩1.4 linux系统常用快捷键及符号命令2. Linux 命令大全❤️ 博客主页 单片机菜鸟哥&#xff0c;一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2022-11-18 ❤️❤️ 本篇更新记录 2022-11-18 ❤️&#x…

YOLO系列改进之四十四——融入适配GPU的轻量级 G-GhostNet

文章目录前言一、解决问题二、基本原理三、​添加方法总结前言 作为当前先进的深度学习目标检测算法YOLOv7&#xff0c;已经集合了大量的trick&#xff0c;但是还是有提高和改进的空间&#xff0c;针对具体应用场景下的检测难点&#xff0c;可以不同的改进方法。此后的系列文章…

Adafruit_GFX matrix ws2812像素屏库使用教程AWTRIX2.0像素时钟

AWTRIX2.0像素时钟很炫酷但必须要与服务器配合使用。这个库可以做自己的点阵时钟离线版。想怎么玩就怎么玩不受服务器牵绊。 第一步&#xff1a;下载mixy库然后倒入&#xff0c;必须有以下库文件&#xff1a; Adafruit_GFX FastLED FastLED_NeoMatrix TomThumb #include <Li…

Seata 1.5.2 源码学习(Client端)

在上一篇中通过阅读Seata服务端的代码&#xff0c;我们了解到TC是如何处理来自客户端的请求的&#xff0c;今天这一篇一起来了解一下客户端是如何处理TC发过来的请求的。要想搞清楚这一点&#xff0c;还得从GlobalTransactionScanner说起。 启动的时候&#xff0c;会调用Global…

【计算机毕业设计】新冠疫情隔离人员信息管理系统+vue源码

一、系统截图&#xff08;需要演示视频可以私聊&#xff09; 摘 要 网络的广泛应用给生活带来了十分的便利。所以把基于小程序的社区疫情防控管理与现在网络相结合&#xff0c;利用ssm框架技术建设基于小程序的社区疫情防控系统&#xff0c;实现基于小程序的社区疫情防控的信息…

双线路捆绑

双线路捆绑是在服务器上接入两条上网线路并行使用 以达到提高链路上下行带宽&#xff08;即上传和下载速度&#xff09;的目的 默认情况下双线路捆绑采用负载均衡模式&#xff0c;并可更改为互为备份模式。 在负载均衡模式下&#xff0c;双线路的使用是基于会话的&#xff0…

已经有 MESI 协议,为什么还需要 volatile 关键字?

本文已收录到 GitHub AndroidFamily&#xff0c;有 Android 进阶知识体系&#xff0c;欢迎 Star。技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 进 Android 面试交流群。 前言 大家好&#xff0c;我是小彭。 在上一篇文章里&#xff0c;我们聊到了 CPU 的缓存一致性问…

树莓派使用docker搭建owncloud私有云--外挂硬盘

一&#xff0e;安装docker 1. 一键脚本&#xff1a; sudo curl -sSL https://get.docker.com | sh2. 查看docker是否安装成功 docker -v出现版本号即为成功 二&#xff0e;每次开机自动挂载硬盘到树莓派 sudo nano /etc/fstab在最后一行加入挂载信息 /dev/sda1 /home/pi/…

[附源码]java毕业设计农村政务管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

[附源码]SSM计算机毕业设计智慧农业销售平台JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

多进程编程 VS 多线程编程

目录 一、进程 & 线程 二、进程与线程的优劣势 三、在什么场景下需要使用多进程编程&#xff1f; 进程也可以称为是“任务”。操作系统要想执行一个具体的“动作”&#xff0c;就需要创建出一个对应的进程。 一个程序在没有运行的时候&#xff0c;它仅仅是一个“可执行…

RHCE学习 --- 第六次作业

RHCE学习 — 第六次作业 首先要先装DNS服务器需要的包 [rootlocalhost ~]# yum install bind -y然后开始配置DNS服务 配置文件位置在/etc/named.conf下&#xff0c;建议先备份 注&#xff1a;备份的时候要cp -a&#xff0c;否则所属组会变&#xff0c;导致文件不可用 然后编辑…

WinForm,可能是Windows上手最快的图形框架了

文章目录Label和控件属性按钮和回调逻辑事件常用控件Label和控件属性 WinForm是一门非常经济实惠的技术&#xff0c;就是说&#xff0c;可以在短时间内学会&#xff0c;并迅速借此进行项目开发。尽管在很多方面不够现代&#xff0c;做出来的东西又Low又丑&#xff0c;但绝大多…

Redis的优惠券秒杀问题(六)超卖问题、一人一单问题

Redis的优惠券秒杀问题&#xff08;六&#xff09;超卖问题、一人一单问题 超卖问题 问题描述 使用Jmeter进行压测 发生超卖问题原因分析 解决方案 悲观锁与乐观锁 1. 版本号 2. CAS法 CAS三大问题&#xff08;题外话&#xff01;&#xff09; CAS三大问题的解…

误差和梯度下降

Datawhale开源学习&#xff0c;机器学习课程&#xff0c;项目地址&#xff1a;https://github.com/datawhalechina/leeml-notes 之前讲了线性模型&#xff0c;提到了误差&#xff0c;那么误差来自哪里&#xff1f;本节内容将介绍「偏差」、「方差」对模型拟合度的影响&#xff…

西电计组II 实验1

西电计组II 实验1 文章目录西电计组II 实验18086汇编 IO操作环境搭建8086汇编 helloworldassumesegmentdb编译链接lstmapobjexesymdobint 21H 软件中断程序设计要求全局变量函数设计putchargetcharprintnewlineinputmemsetexithexbinarycircle程序入口完整代码8086汇编 IO操作 …

wav to image 的数据集制作代码

🍿*★,*:.☆欢迎您/$:*.★* 🍿 目录 背景 正文 总结 背景描述

python+django网吧会员管理系统

系统项目截图 本网吧管理系统主要包括三大功能模块&#xff0c;即管理员、会员、网管。 &#xff08;1&#xff09;管理员模块&#xff1a;首页、个人中心、会员管理、网管管理、商品类型管理、商品信息管理、购买商品信息管理、呼叫网管管理、电脑信息管理、用户上机管理、用户…

汇编语言外中断

外中断 文章目录外中断1.外中断概念2.PC机键盘的处理过程1.外中断概念 CPU在计算机系统中&#xff0c;除了能够执行指令&#xff0c;进行运算以外&#xff0c;还应该能够对外部设备进行控制&#xff0c;接收它们的输入&#xff0c;向它们进行输出&#xff08;I/O能力&#xff0…