STL好难(2):string类的使用

news2024/11/27 22:30:30

【本节目标】

  • 1. 标准库中的string类
  • 2. string类的模拟实现
  • 3. 扩展阅读

目录

【本节目标】

1.标准库中的string类

2. string类对象的常见构造

🍉无参构造

🍉带参构造

🍉拷贝构造

🍉用n字符 # 去初始化

🍉用字符串的前n个字符去初始化

🍉从一个 string 对象的 pos 为值开始,拿 len 个字符去初始化

3. string类对象的容量操作

🍉size

🍉length

🍉max_size

🍉capacity

🍉reserve

🍉resize

🍉clear

🍉empty

4. string类对象的访问及遍历操作

🍉[ ] + 下标

🍉at

🍉begin + end(迭代器 iterator)

🍉rbegin 和 rend(反向迭代器 reserve_iterator)

🍉const 迭代器、const反迭代器(const iterator)、(const_reserve_iterator)

🍉范围for

5. string类对象的操作

🍉operator+=

🍉aappend

🍉push_back

🍉pop_back

🍉insert

🍉erase

🍉replace

🍉swap

6.string类运算符函数

🍉operator= 

🍉operator+=

🍉operator+

🍉operator>> 和 operator<<

🍉relational operators (string)


前言:我们为什么要学string类

C语言中的字符串

C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。

string文档介绍

我们下面的学习,都会以文档内容为标准

string类 就类比数据结构的  字符类型的顺序表  来学习能更好的理解

1.标准库中的string类

1. 字符串是表示字符序列的类
2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。
4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。
5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

编码的本质就是:内存当中存的全是 0 和 1,那么如果我要把它显示成对应的文字,比如:英文、中文、日文、韩文等等,只能通过编码显示出来

在显示之前,会通过一张表去对照着查,这个表就是需要显示值的映射表,比如ASCII表

总结:

  • 1. string是表示字符串的字符串类
  • 2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  • 3. string在底层实际是:basic_string模板类的别名,
    typedef basic_string<char, char_traits, allocator> string;
  • 4. 不能操作多字节或者变长字符的序列

在使用string类时,必须包含#include头文件以及using namespace std;

2. string类对象的常见构造

🍉无参构造

构造函数的string类对象,即空字符串

string();

int main()
{
	string s1;
	
	return 0;
}

🍉带参构造

用常量字符串来构造string对象

string (const char* s);

int main()
{
	string s2("hello world");

	return 0;
}

🍉拷贝构造

拿一个已经存在的对象去初始化另一个未存在的对象(加引用是为了减少拷贝)

string(const string& str);

int main()
{
	string s2("hello world");

	string s3(s2);

	return 0;
}

🍉用n字符 # 去初始化

string 类对象内会有n个字符#

string(size_t n, char c);

int main()
{
	// 用9个¥去初始化s4对象
	string s4(9, '¥');

	return 0;
}

🍉用字符串的前n个字符去初始化

string(const char* s, size_t n);

int main()
{
	// 用字符串的前5个字符去初始化s5对象
	string s5("hello world", 5);

	cout << s5 << endl;

	return 0;
}

string存放的是前5个字符

🍉从一个 string 对象的 pos 为值开始,拿 len 个字符去初始化

string(const string& str, size_t pos, size_t len = npos);

int main()
{
	string s6("STL_is_so_hard");

	// 从s6对象的第0个位置开始(包括第0个位置的字符),往后数7个字符,去初始化s7对象
	string s7(s6, 0, 7);

	cout << s7 << endl;

	return 0;
}

可以看到,len 里面给了个缺省值 nops,那么这个 nops 是多少嘞?

查看文档可以看到:

 npos 其实是 string 类里面的一个静态成员变量,给的值是 -1

但是 size_t 是用无符号来修饰的,也就是说无符号的 -1,它的补码全是1,也就是整形的最大值,所以他的意思就是:从 pos 位置开始,往后取 42 亿多个字符。

也就是代表着如果不给 len 值,那么就是有多少取多少

3. string类对象的容量操作

我们需要学习的以下函数接口:

函数名称功能说明
size(重点)返回字符串有效字符长度
length返回字符串有效字符长度
capacity返回空间总大小
empty(重点)检测字符串释放为空串,是返回true,否则返回false
clear(重点)清空有效字符
reserve(重点)为字符串预留空间**
resize(重点)将有效字符的个数该成n个,多出的空间用字符c填充

🍉size

返回字符串有效长度

size_t size() const;

int main()
{
	string s1("hello world");

	cout << s1.size() << endl;

	return 0;
}

🍉length

返回字符串有效字符长度(和 size 一样)

size_t length() const;

int main()
{
	string s2("hello world");

	cout << s2.length() << endl;

	return 0;
}

size length 方法底层实现原理完全相同,引入 size 的原因是为了与其他容器的接口保持一致,所以一般情况下基本都是用 size

🍉max_size

返回字符串可以达到的最大长度

size_t max_size() const;

int main()
{
	string s3("hello world");

	cout << s3.max_size() << endl;

	return 0;
}

这个实际上就是告诉你,字符串最大能开多长,但是这个函数在实际中并没有什么太大的用处。大家可以试试运行下看看最大能开多大

🍉capacity

 返回分配的存储空间容量大小

size_t capacity() const;

int main()
{
	string s4("hello world");

	cout << s4.capacity() << endl;

	return 0;
}

可以看到,容量的大小默认为 15 ,那么 string类 是怎样扩容的?

可以看到,VS下,capacity第一次是扩2倍,之后是进行1.5倍的扩容

在Linux平台下进行编译会发现又是2倍来进行扩容的,这是因为他们版本不同。VS是PJ版,它是微软进行维护的;Linux下的g++是开源社区维护的。也正是STL并没有明确的扩容机制,所以每个社区或平台上的是不一样的。

另外扩容也是有代价的,需要开新的空间,那么有什么方法能够减少扩容呢?
这就需要我们的 reserve 函数

🍉reserve

为字符串预留空间

void reserve(size_t n = 0);

int main()
{
	string s;
	s.reserve(1000); // 提前开好空间
	size_t sz = s.capacity();
	cout << "扩容" << endl;
	cout << "capacity changed:" << sz << endl;

	// 因为前面开了1000个空间,现在往小的阔,编译器并不会执行,而是保持之前的大小
	for (int i = 0; i < 1000; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "往小的阔_capacity changed: " << sz << endl;;
		}
	}
	return 0;
}

当使用 reserve 改变当前对象的容量大小,并提前开辟空间时,
注意:

  • 当 n 大于对象当前的 capacity 时,将 capacity 扩大到 n 或大于 n。
  • 当 n 小于对象当前的 capacity 时,什么也不做。
  • 此函数对字符串的 size 没有影响,并且无法更改其内容。

如下测试:

void TestString() 
{
	string s("HelloWorld");

	cout << s << endl; //HelloWorld
	cout << s.size() << endl; //10
	cout << s.capacity() << endl; //15

	cout << endl;

	//reverse(n)当n大于对象当前的capacity时,将当前对象的capacity扩大为n或大于n
	s.reserve(20);
	cout << s << endl;
	cout << s.size() << endl; //10
	cout << s.capacity() << endl; //31

	cout << endl;

	//reverse(n)当n小于对象当前的capacity时,什么也不做
	s.reserve(2);
	cout << s << endl;
	cout << s.size() << endl; //4
	cout << s.capacity() << endl; //31
}

结果如下: 

总结:

void reserve (size_t n = 0):为 string 预留空间,不改变有效元素个数,当 reserve 的参数小于 string 的底层空间总大小时,reserver 不会改变容量大小。

🍉resize

将有效字符的个数改成 n 个,多出的空间用字符 c 填充

void resize(size_t n);
void resize(size_t n, char c);

使用 resize 改变当前对象的有效字符个数

  1. 当 n 大于对象当前的 size 时,将 size 扩大到 n,扩大的字符为 c,若 c 未给出,则默认为 0
  2. 当 n 小于对象当前的 size 时,将 size 缩小到 n
void TestString()
{
	string s1("HelloWorld");
	//resize(n)n大于对象当前的size时,将size扩大到n,扩大的字符默认为'\0'
	s1.resize(20);
	cout << s1 << endl; //HelloWorld
	cout << s1.size() << endl; //20
	cout << s1.capacity() << endl; //31

	cout << endl;

	string s2("HelloWorld");
	//resize(n, char)n大于对象当前的size时,将size扩大到n,扩大的字符为char
	s2.resize(20, 'x');
	cout << s2 << endl; //HelloWorldxxxxxxxxxxxxxxxx
	cout << s2.size() << endl; //20
	cout << s2.capacity() << endl; //31

	cout << endl;

	string s3("HelloWorld");
	//resize(n)n小于对象当前的size时,将size缩小到n
	s3.resize(2);
	cout << s3 << endl; //He
	cout << s3.size() << endl; //2
	cout << s3.capacity() << endl; //15
}

结果:

相比于 reserve 只是用来开空间resize 的作用就是 开空间+初始化

关于 reserve resize,它们在 VS 下都不会缩容量

但是可以看到我们扩容的时候,明明是申请的 20 个空间,为什么打印出来有 31 个呢?这是因为 capacity 的内存对齐

这里可以简单解释一下:
系统去申请内存,需按照整数倍去对齐,就算我们不对齐,那么系统也会自动去对齐的;


比如这里的31,加上最后的 ' \0 '  就是32,刚好时4个字节


为什么要申请对齐呢?
是因为和内存的效率以及内存碎片有关。

🍉clear

擦除字符串的内容,该字符串变为空字符串(长度为 0 个字符)
使用 clear 删除对象的内容,删除后对象变为空字符串,但是对象的容量不会被清理掉

void clear();

int main()
{
	string s1("hello world");
	cout << s1 << endl; //HelloWorld
	cout << s1.size() << endl; //11
	cout << s1.capacity() << endl; //15

	cout << endl;

	s1.clear();
	cout << s1 << endl; //空
	cout << s1.size() << endl; //0
	cout << s1.capacity() << endl; //15

	return 0;
}

clear 只是将 string 对象中有效字符清空,不改变底层空间大小。

🍉empty

判断字符串是否为空,如果字符串长度为 0,则为 true,否则为 false

bool empty() const;

int main()
{
	string s1("hello world");
	string s2;

	// 字符串不为空,返回0
	cout << s1.empty() << endl;

	// 字符串为空,返回1
	cout << s2.empty() << endl;

	return 0;
}

4. string类对象的访问及遍历操作

函数名称功能说明
operator[ ](中点)返回pos位置的字符,const string类对象调用
at返回pos位置的字符,const string类对象调用
begin  +  endbegin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
rbegin +  rend

begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器

范围forC++11支持更简洁的范围for的新遍历方式

🍉[ ] + 下标

string 类 对 [ ] 运算符做了重载,所以我们可以直接使用  [ ] + 下标 访问对象中的元素

并且,重载用的是 引用返回 ,所以我们可以直接通过  [ ] + 下标 来修改对于位置元素

char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;


int main()
{
	string s1("hello world!");

	//1.使用下标访问对象元素
	for (size_t i = 0; i < s1.size(); ++i) 
	{
		cout << s1[i];
	}

	cout << endl;

	//2.使用下标修改对象元素
	for (size_t i = 0; i < s1.size(); ++i) 
	{
		s1[i] = 'x';
	}
	cout << s1 << endl;
}

  [ ] + 下标 也有个const版本,加上const就不能用下标进行修改了

🍉at

at 和 operator[ ]  很相似,区别是:当他们出错时编译器会有不同的警告

int main()
{
	string s1 = "hello world";

	s1[100];
	s1.at(100);

	return 0;
}

operator[ ]:就是 assert() 那种直接中断的报错警告

at :at是抛异常的警告

抛异常是能被 捕获 到的:

int main()
{
	string s1 = "hello world";

	try
	{
		s1.at(100);
	}
	catch(const exception& a)
	{
		cout << a.what() << endl;
	}

	return 0;
}

结果:程序会继续运行,但会出现提示

实际过程中很少用at

🍉begin + end(迭代器 iterator)

begin 获取第一个字符的迭代器 + end 获取最后一个字符下一个位置的迭代器

void TestString() 
{
	string s1("hello world!");

	//使用迭代器访问对象元素
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	//使用迭代器修改对象元素
	string::iterator aaa = s1.begin();
	while (aaa != s1.end())
	{
		*aaa += 1;
		++aaa;
	}
	cout << s1 << endl;
}

对于迭代器,可以理解为像指针一样的东西,或者说就是指针。

🍉rbegin 和 rend(反向迭代器 reserve_iterator)

rbegin 获取之后一个字符的迭代器 + end 获取第一个字符上一个位置的迭代器

rbegin + rend 打印出来的是数组的反串

void TestString() 
{
	string s1("hello world!");

	//使用迭代器访问对象元素
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	string::reverse_iterator rit = s1.rbegin();
	while (rit != s1.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
}

🍉const 迭代器、const反迭代器
(const iterator)、(const_reserve_iterator)

我们可以在C++文档中可以看到的begin、end、rbegin、rend中都有个const修饰的类型

以begin为例:

普通对象用普通迭代器,const对象用const迭代器

void Func(const string& s)
{
	//const迭代器的使用,遍历和读容器的数据,不能修改
	string::const_iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}
int main()
{
	string s1 = "hello world";
	Func(s1);
	return 0;
}

对应的还有const反迭代器 const_reserve_iterator

void Func(const string& s)
{
	string::const_reverse_iterator rit = s.rbegin();
	while (rit != s.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
}
int main()
{
	string s1 = "hello world";
	Func(s1);
	return 0;
}

🍉四种迭代器:

  • iterator
  • reserve_iterator
  • const_iterator
  • const_reserve_iterator

这里我们可以直接用 auto 语法来让编译器自动推导

void Func(const string& s)
{
	//string::const_reverse_iterator rit = s.rbegin();
    
    //用auto自动推导
	auto rit = s.rbegin();
	while (rit != s.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
}

🍉范围for

范围for 的底层实现就是通过迭代器实现的。

如果我们是通过范围 for 来修改对象的元素,那么接收元素的变量 e 的类型必须是引用类型,否则 e 只是对象元素的拷贝,对 e 的修改不会影响到对象的元素。

void TestString() 
{
	string s1("hello world!");

	//使用范围for访问对象元素
	for (auto e : s1) 
	{
		cout << e;
	}
	cout << endl;

	//使用范围for修改对象元素
	for (auto& e : s1)
	{
		e = 'x';
	}
	cout << s1 << endl;
}

5. string类对象的操作

 点击查看string类文档

对象的操作有很多,主要可以分为:插入、删除、查找、拼接

🍉operator+=

string 类中对 += 运算符进行了重载,重载后的 += 运算符支持 string 类的复合赋值、字符串的复合赋值以及字符复合的赋值

 1)插入一个string对象

string& operator+= (const string& str);

int main()
{
	string s1;
	string s2("hello");

	s1 += s2;

	cout << s1 << endl;

	return 0;
}

2)插入一个常量字符串

string& operator+= (const char* s);

int main()
{
	string s1("hello");

	s1 += "world";

	cout << s1 << endl;

	return 0;
}

3)插入一个字符

string& operator+= (char c);

int main()
{
	string s1("hello");

	s1 += "!";

	cout << s1 << endl;

	return 0;
}

总结:

在 string尾插字符时,有以下三种方式

  • s.push_back(c) 
  • s.append(1, c) 
  • s += ' c '

三种的实现方式差不多,一般情况下 string 类的 += 操作用的比较多
+= 操作不仅可以连接单个字符,还可以连接字符串

🍉aappend

 在字符串后追加一个字符串(基本用不到,因为用 += 更简单)

1)插入一个string对象

string& append(const string& str);

int main()
{
	string s1("hello");
	string s2("world");

	//直接把s2对象拼接到s1的后面
	s1.append(s2);

	cout << s1 << endl;

	return 0;
}

2)插入一个常量字符串

 

string& append(const char* s);

int main()
{
	string s1("hello");

	//在s1字符串后面拼接新的字符串
	s1.append("world");

	cout << s1 << endl;

	return 0;
}

3)插入 n 个字符 c

 

string& append(size_t n, char c);

int main()
{
	string s1("hello");

	//将3个字符拼接到s1对象后面
	s1.append(3, '!');

	cout << s1 << endl;

	return 0;
}

🍉push_back

尾插,将字符 c 追加到字符串末尾,将其长度增加1

void push_back(char c);

int main()
{
	string s1;

	s1.push_back('h');
	s1.push_back('e');
	s1.push_back('l');
	s1.push_back('l');
	s1.push_back('o');

	cout << s1 << endl; //hello

	return 0;
}

🍉pop_back

尾删,删除string最后一个字符

void pop_back();
int main()
{
	string s1("hello");

	s1.pop_back();

	cout << s1 << endl;

	return 0;
}

🍉insert

 可以看到insert有很多结构,但并不是每个都会用到,这里我们选几个用的最多的来演示

1)在 pos 位置插入一个常量字符串

string& insert(size_t pos, const string& str);

int main()
{
	string s("hello");

	// 在第0个位置插入字符串xxx
	s.insert(3, "xxx");  

	cout << s << endl;  // helxxxlo 

	return 0;
}

2)在 pos 位置插入 n 个字符串 c

 

string& insert(size_t pos, size_t n, char c);

int main()
{
	string s("hello");

	// 在第3个位置插入5个字符y
	s.insert(3, 5, 'y');

	cout << s << endl; //helyyyyylo

	return 0;
}

3)使用迭代器来进行插入

 

iterator insert(iterator p, char c);

int main()
{
	string s("hello");

	// 从begin开始的5个位置插入字符y
	s.insert(s.begin() + 5, 'y');

	cout << s << endl; //helloy

	return 0;
}

begin(),是s对象的第一个位置的指针

🍉erase

从字符串中删除字符

1)从 pos 位置开始,删除 len 个字符

 

string& erase(size_t pos = 0, size_t len = npos);

int main()
{
	string s1("helloworld");

	从s1下标为5的位置开始,往后删除2个字符
	s1.erase(5, 2); // 删除 w 和 o

	cout << s1 << endl; //hellorld


	return 0;
}

注意:len 参数的缺省值是 npos,不给值会将后面的全删掉,删到' /0 ' 

2)从迭代器的位置删除字符

 

iterator erase(iterator p);

int main()
{
	string s1("helloworld");

	//删除s1字符串第一个位置的元素
	s1.erase(s1.begin());

	cout << s1 << endl; //elloworld

	return 0;
}

3)从迭代器开始的位置,一直删除到迭代器结束的位置

 

iterator erase(iterator first, iterator last);

int main()
{
	string s1("helloworld");

	//从begin+5的位置开始,一直删除到end的位置
	s1.erase(s1.begin() + 5, s1.end());

	cout << s1 << endl; // hello

	return 0;
}

🍉replace

替换字符串的一部分

替换也有很多接口,我们只了解圈出来的两个即可

 1)从 pos 位置开始的第 len 个字符替换为一个字符串

 

string& replace(size_t pos, size_t len, const char* s);

int main()
{
	string s1("helloworld");

	//将第6个位置开始的4个字符替换为字符串xxxyyy
	s1.replace(6, 4, "xxxyyy");

	cout << s1 << endl; //hellowxxxyyy

	return 0;
}

 2)从 pos 位置开始的第 len 个字符替换为 n 个字符 c

string& replace(size_t pos, size_t len, size_t n, char c);

int main()
{
	string s1("helloworld");

	//将第5个位置开始的1个字符替换为3个字符x
	s1.replace(5, 1, 3, 'x');

	cout << s1 << endl; //helloxxxorld

	return 0;
}

🍉swap

交换两个字符串的值

void swap(string& str);

int main()
{
	string s1("hello");
	string s2("world");

	cout << "交换前" << endl;
	cout << "s1:" << s1 << endl;
	cout << "s2:" << s2 << endl;

	//使用string类的成员函数swap交换s1和s2
	s1.swap(s2);

	cout << "交换后" << endl;
	cout << "s1:" << s1 << endl;
	cout << "s2:" << s2 << endl;

	return 0;
}

对于string里面的swap我们还要说一点,我们要知道,在我们全局里面也有一个swap函数,他能完成各种类型的交换,当然也包括string

int main()
{
	string s1("hello");
	string s2("world");

	cout << "交换前" << endl;
	cout << "s1:" << s1 << endl;
	cout << "s2:" << s2 << endl;

	//使用全局swap函数交换s1和s2
	swap(s1, s2);

	cout << "交换后" << endl;
	cout << "s1:" << s1 << endl;
	cout << "s2:" << s2 << endl;

	return 0;
}

那么这两个swap的区别是什么,用哪个实现起来更效果更高呢?

string 里面的 swap 是直接交换指针的指向,而全局的swap是进行拷贝,
所以用 string 里面的 swap 效率高

6.string类运算符函数

🍉operator= 

string类中,对=运算符进行了重载,使其能支持string类的赋值、字符串的赋值以及字符的赋值

1)支持string类对象之间的赋值

 

int main()
{
	string s1;
	string s2("hello world");

	s1 = s2;

	cout << s1 << endl;

	return 0;
}

2)支持字符串赋值

 

int main()
{
	string s1;

	s1 = "hello world";

	cout << s1 << endl;

	return 0;
}

🍉operator+=

上面已经有过介绍、这里就不多赘述了

🍉operator+

string类中,对+运算符进行了重载,使其可以进行+string类、+字符串、字符的操作

 

int main()
{
	string s11;
	string s12;
	string s13;
	string s2("hello");
	string s3("world");
	char str[] = "C++";
	char a = '!';
	//string类 + string类
	s11 = s2 + s3;

	//string类 + 字符串,或者:字符串 + string类
	s12 = s11 + str;	//s12 = str + s11;

	//string类 + 字符,或者:字符 + string类
	s13 = s12 + a;		//s13 = a + s12;

	cout << s11 << endl;
	cout << s12 << endl;
	cout << s13 << endl;


	return 0;
}

结果如下:

🍉operator>> 和 operator<<

string也对>>和<<进行了重载,可以再cin和cout中直接使用string类进行输入和输出

int main()
{
	string s1;

    //流提取
	cin >> s1; 

    //流插入
	cout << s1 << endl; 

	return 0;
}

🍉relational operators (string)

string还对其他一系列操作符进行了重载,分别是:==,!=,<=,>=,<,>

 

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

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

相关文章

二进制部署高可用Kubernetes集群

SUMMARY 架构图 设备规划 序号名字功能VMNET 1备注 1备注 2备注 3 备注 4备注 50orgin界面192.168.164.10haproxykeepalived192.168.164.2001reporsitory仓库192.168.164.16yum 仓库registoryhaproxykeepalived2master01H-K8S-1192.168.164.11kube-apicontrollerscheduler…

约瑟夫问题及求解方法

文章目录 什么是约瑟夫问题&#xff1f;求解方法代码实现 什么是约瑟夫问题&#xff1f; 约瑟夫问题是一个经典的数学难题&#xff0c;其一般形式可以描述为&#xff1a; n个人&#xff08;编号从1到n&#xff09;&#xff0c;围坐在一张圆桌周围。从第一个人开始报数&#x…

chatgpt赋能Python-mac系统的python

在Mac系统上运行Python&#xff1a;一个简介 介绍 Python是一种流行的、易于学习的编程语言&#xff0c;被广泛用于各种用途&#xff0c;从数据分析到机器学习。如果您是Mac用户&#xff0c;那么您已经安装了Python&#xff0c;因为它是系统的一部分。本文将介绍如何在Mac系统…

Web基础 ( 五 ) JavaScript BOM

4.4.BOM浏览器对象模型 window代表窗体, 内置多种对象, 每种对象包含多种方法及属性 4.4.1.location 地址栏 window.location.href "url"; // 当前窗口加载指定的页面location.reload(); //刷新4.4.2.history 访问历史记录 window.history.back(); // 返回上一…

搞一搞用例图

前言 基于公司技术方案的设计比较重视用例图&#xff0c;重新学习一下相关内容。用例要说明参与者与用例之间的关系&#xff0c;那么对用例图相关要点进行梳理 用例图的定义及组成要素用例图的4种关系常用的用例图软件 定义与组成 用例图核心作用是将系统需求和参与者之间的…

DEJA_VU3D - Cesium功能集 之 110-椭圆(标绘+编辑)

前言 编写这个专栏主要目的是对工作之中基于Cesium实现过的功能进行整合,有自己琢磨实现的,也有参考其他大神后整理实现的,初步算了算现在有差不多实现小140个左右的功能,后续也会不断的追加,所以暂时打算一周2-3更的样子来更新本专栏(每篇博文都会奉上完整demo的源代码…

【手撕红黑树】

前言 相信很多人初学者听到了红黑树后心中不免有些心慌&#xff0c;那你看到了这篇文章后相信会有所收获&#xff0c;我其实刚开始也是对红黑树抱着一种害怕甚至是恐惧&#xff0c;但是在老师的帮助下也终于慢慢的不在恐惧了&#xff0c;你想知道为什么的话就继续往下看吧。&am…

【C,C++】内存管理new和delete

内存管理 前言正式开始几道热身题C语言动态内存管理方式C内存管理new/delete操作内置类型new和delete对于内置类型new开辟失败 operator new与operator delete函数new和delete的实现原理内置类型自定义类型 定位new表达式面试常考&#xff1a;malloc/free和new/delete的区别 前…

板子短路了?

有段时间没更新了&#xff0c;主要是最近有点忙&#xff0c;当然也因为有点“懒”。 做这行业的都知道&#xff0c;下半年都是比较忙的&#xff0c;相信大家也是&#xff01; 相信做硬件的小伙伴们&#xff0c;遇到过短路的板子已经不计其数了。 短路带来的危害&#xff1a;…

关于单目视觉 SLAM 的空间感知定位技术的讨论

尝试关于单目视觉 SLAM 的空间感知定位技术的学习&#xff0c;做以调查。SLAM算法最早在机器人领域中提出&#xff0c;视觉SLAM又可以分为单目、双目和深度相机三种传感器模式&#xff0c;在AR应用中通常使用轻便、价格低廉的单目相机设备。仅使用一个摄像头作为传感器完成同步…

Web基础 ( 四 ) JavaScript 介绍

4.JavaScript 4.1.概念 4.1.1.什么是JavaScript 通过浏览器中内置的解析器&#xff0c;逐行解析执行的一种脚本语言 主要是处理系统使用者的行为逻辑的 4.1.2.与Java语言的比较 代码格式不同 ​ Java与HTML无关的格式 ​ JavaScript代码是一种文本字符格式&#xff0c;可…

chatgpt赋能Python-numpy归一化函数

介绍&#xff1a;numpy归一化函数 在数据处理和分析中&#xff0c;常常需要将数据归一化到一定范围内&#xff0c;以便于不同数据之间进行比较和处理。在Python的数据科学方面&#xff0c;numpy库是非常常用的工具之一&#xff0c;其中的归一化函数非常便捷和有效。 在这篇文…

如何快速入门 Java?

在一线互联网公司做开发 13 年了&#xff0c;“精通”Java&#xff0c;“吊打”一众面试官&#xff0c;如何快速入门 Java&#xff0c;对我来说简直就是小儿科&#xff0c;相信看完后你一定能收获满满、醍醐灌顶&#xff0c;今年秋招拿下阿里、美团等互联网大厂的 offer。 逼装…

django ORM框架 第二章 表与表的关系关联表

目录 一、表的几种关联关系 1.1 一对一 1、介绍&#xff1a; 2、举例 3、建表原则&#xff1a; 4、django ORM 框架实现 一对一 的表的创建 1.2 一对多 1、介绍&#xff1a; 2、举例 3、建表原则&#xff1a; 4、django ORM 框架实现 一对多 的表的创建 1.3 多对多 1…

汇编八、汇编控制静态数码管显示数字

1、实现目标 通过汇编语言&#xff0c;实现单个静态数码管依次循环显示0~9。 2、数码管 2.1、数码管外观 2.2、数码管工作原理 (1)数码管的亮灭是由内部LED的亮灭实现的。 (2)一位数码管内部有八颗LED灯&#xff0c;利用内部的LED灯的亮和灭让数码管显示不同的数字。 3、…

chatgpt赋能Python-mac怎么用python

Mac如何使用Python&#xff1a;从入门到实践 简介 Mac操作系统上的Python开发环境非常受欢迎&#xff0c;因为它是一种优雅的编程语言&#xff0c;具有良好的可读性&#xff0c;可以轻松处理不同类型的任务&#xff0c;包括网站开发、机器学习和数据分析等领域。本文将介绍如…

干外包3年,彻底寄了...

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了6年的功能测试&…

瑞吉外卖 - 删除分类功能(13)

某马瑞吉外卖单体架构项目完整开发文档&#xff0c;基于 Spring Boot 2.7.11 JDK 11。预计 5 月 20 日前更新完成&#xff0c;有需要的胖友记得一键三连&#xff0c;关注主页 “瑞吉外卖” 专栏获取最新文章。 相关资料&#xff1a;https://pan.baidu.com/s/1rO1Vytcp67mcw-PD…

chatgpt赋能Python-minhash_python

MinHash Python算法&#xff1a;优化大数据处理和搜索引擎 在如今互联网化和其他技术转型的时代&#xff0c;SEO已经成为许多企业和个人的必要条件。SEO方法(搜索引擎优化)一直在不断的发展&#xff0c;MinHash算法是其中之一。本篇文章将会介绍MinHash算法和它在Python中的实…

万金油表示真干不过,部门新来的00后测试员已把我卷崩溃,想离职了...

在程序员职场上&#xff0c;什么样的人最让人反感呢? 是技术不好的人吗?并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗?也不是。技术很强的同事&#xff0c;可遇不可求&#xff0c;向他学习还来不及呢。 真正让人反感的&#xff0c;是技术平平&#x…