模拟实现string【C++】

文章目录

  • 全部的实现代码放在了文章末尾
  • 准备工作
    • 包含头文件
    • 定义命名空间和类
      • 类的成员变量
  • 构造函数
    • 默认构造
    • 拷贝构造
  • 重载赋值拷贝函数
  • 析构函数
  • 迭代器和获取迭代器
    • 迭代器
    • 获取迭代器
  • resize【调整size】
    • 图解
  • reserve【调整capacity】
  • empty【判断串是否为空】
  • operator[]
  • append
  • push_back
  • operator+=
  • insert【在pos之前插入字符串】
  • erase【删除从pos开始的len个字符】
  • swap
  • find
  • substr
  • operator+
  • compare
  • 比较运算符重载
    • operator>
    • operator==
    • operator<
    • operator>
    • operator<=
    • operator!=
  • c_str
  • operator<<【输出运算符重载】
  • operator>>【输入运算符重载】
  • 全部代码
    • mystring.h
    • mystring.cpp

全部的实现代码放在了文章末尾

准备工作

创建三个文件,一个头文件mystring.h,两个源文件mystring.cpp tesr.cpp
因为是简单实现,所以只实现了string里放char这一种实现,就没有用模板了

  1. mystring.h:存放包含的头文件,命名空间的定义
  2. mystring.cpp:存放成员函数和命名空间中的函数的定义
  3. test.cpp:存放main函数,以及测试代码

包含头文件

  1. iostream:用于输入输出
  2. string.h:C语言的头文件,用于使用其中的操作字符数组的函数
  3. assert.h:用于使用报错函数

定义命名空间和类

在文件mystring.hmystring.cpp中都定义上一个命名空间mystring
mystring.h中类的声明放进命名空间,把mystring中的函数实现也放进命名空间

注意:
不同源文件的同名的命名空间经过编译链接之后可以合成在一起

类的成员变量

在这里插入图片描述


构造函数

默认构造

在这里插入图片描述

给默认构造的str加上缺省值(“”)就可以实现不传参数时就是空串了


拷贝构造

因为成员str申请了堆区空间,所以要手写拷贝构造,并且要实现深拷贝
在这里插入图片描述


重载赋值拷贝函数

因为成员str申请了堆区空间,所以要手写赋值拷贝,并且要实现深拷贝
在这里插入图片描述
为什么要防止自己给自己赋值?
【this指针指向接收赋值的对象,所以只要this传入的参数的地址相等就是自己赋值给自己】

因为要深拷贝,所以要把一个对象中的所有成员都拷贝一遍,时间复杂度是
O(N),所以有必要防止自己给自己赋值


析构函数

因为成员str申请了堆区空间,所以要手写析构,不能用编译器给的默认析构

在这里插入图片描述


迭代器和获取迭代器

迭代器

因为存放字符的空间的地址是连续的,且只是简单模拟
所以我用了char*作为普通迭代器,const char*作为const迭代器

直接把char*重命名为iterator,把const char*重命名为const_iterator就完成了迭代器的实现


获取迭代器

在这里插入图片描述
因为使用了char*作为迭代器
所以str就是第一个有效元素,str+size就是最后一个有效字符的下一个位置(\0)

又因为const修饰的对象只能调用const修饰的成员函数
所以如果是const修饰的对象调用begin()和end()的时候,就会自动调用到const修饰的begin和end.
在这里插入图片描述


resize【调整size】

void string::resize(size_t n,char c='\0')
{if (n > _capacity) 当要调整的容量n大于最大容量时,就要扩容{char* tmp = new char[n +1];申请size+1个空间,那多出来的1是给'\0'strcpy(tmp, _str);拷贝字符串(把右参数拷贝给左参数)delete[] _str;释放扩容前str指向的空间_str = tmp;完成扩容for (; _size <n; _size++)把多出来的有效字符用c补上{_str[_size] = c;}_str[_size] = '\0'; 补完之后加上字符串结束标志'\0'_capacity = n;更新最大容量}else{if (n > _size)如果调整之后的size  大于  原来的size就要把少(n-size)的有效字符用c补上{for (; _size < n; _size++)把多出来的有效字符用c补上{_str[_size] = c;}_str[_size] = '\0';补完之后加上字符串结束标志'\0'}else 如果调整之后的size  小于  原来的size就要把多的字符删除{_size = n;调整有效字符大小_str[_size] = '\0';直接把n位置改成'\0'即可删除多余字符}}
}

图解

在这里插入图片描述

在这里插入图片描述


reserve【调整capacity】

在这里插入图片描述


empty【判断串是否为空】

在这里插入图片描述


operator[]

返回值要是char&这样才能像字符数组一样访问和修改串中的字符
在这里插入图片描述


append

在这里插入图片描述

在这里插入图片描述


push_back

可以直接服用append
在这里插入图片描述


operator+=

也可以直接服用append

在这里插入图片描述


insert【在pos之前插入字符串】

在这里插入图片描述


erase【删除从pos开始的len个字符】

在这里插入图片描述


swap

因为存放字符串的空间是在堆区开辟的,用成员str去指向的
所以直接交换两个对象的str中存放的地址就可以完成存储的字符串的交换了

不需要拷贝
在这里插入图片描述

在这里插入图片描述


find

在这里插入图片描述


substr

在这里插入图片描述


operator+

直接复用operator+=
因为+不改变字符串本身,所以要用一个临时对象存储+=之后的字符,再用传值返回即可

在这里插入图片描述


compare

在这里插入图片描述


比较运算符重载

operator>

复用compare
在这里插入图片描述


operator==

复用compare
在这里插入图片描述


operator<

复用operator>operator==
在这里插入图片描述


operator>

复用operator>operator==
在这里插入图片描述


operator<=

复用operator>

在这里插入图片描述


operator!=

复用operator==
在这里插入图片描述


c_str

作用是获取string对象中的str成员。

一般是要在C++中使用C语言函数时使用,因为C语言不支持string,所以只能用字符指针代替一下

在这里插入图片描述

operator<<【输出运算符重载】

重载了之后就可以
直接用cout输出string实例化的对象了

string a(“aaaaa”);
cout<<a<<endl;

在这里插入图片描述


operator>>【输入运算符重载】

重载了之后就可以
直接用cin把字符串输入到string实例化的对象里面了

istream是输入流对象,比如我们常用的  cin  就是  istream实例化的对象istream& operator>>(istream& is, string& obj)
{char str[100];  存储  输入的  每一行的字符int sum = 0;  使用sum记录输入的  每一行  的字符个数char c = 0;\n是换行符(回车),所以  没遇到  \n就  没换行while ((c = is.get()) != '\n')  一次读取一个字符{if (sum == 99)  当sum等于99时说明  str数组存不下了{str[sum] = '\0';  末尾加上了\0才是字符串obj += str;  使用+=把str数组中的字符先加上去sum = 0;  sum置成0,继续记录}else  否则{把读取到的字符存进str数组里str[sum++] = c;}}sum!=0说明最后输入的最后一行字符个数  小于99个,没有+=if (sum != 0){str[sum] = '\0';  末尾加上了\0才是字符串obj += str;  使用+=把str数组中的字符先加上去}return is;  为支持链式编程,返回  输入流对象  的引用
}

全部代码

mystring.h

#include<iostream>
#include<string.h>
#include<assert.h>
using namespace std;namespace mystring
{class string{public:typedef char* iterator;typedef const char* const_iterator;string(const string& obj);string(const char* str = "");string& operator=(const string&obj);~string();iterator begin();const_iterator begin() const;iterator end();const_iterator end() const;size_t size() const;size_t capacity() const;void resize(size_t n, char c='\0');void reserve(size_t n = 0);void clear();bool empty() const;char& operator[](size_t pos);const char& operator[](size_t pos)const;string& append(const string& obj);string& append(char ch);void push_back(char c);string& operator+=(const string& obj);string& operator+=(char c);string& assign(const string& str);string& insert(size_t pos, const string& str);string& insert(size_t pos,char c);string& erase(size_t pos = 0, size_t len = npos);void swap(string& str);const char* c_str() const;size_t find(const string& str, size_t pos = 0) const;size_t find(char c, size_t pos = 0) const;string substr(size_t pos = 0, size_t len = npos) const;int compare(const string& str) const;string operator+(const string& obj)const;string operator+(char c)const;bool operator>(const string&obj)const;bool operator<(const string& obj)const;bool operator>=(const string& obj)const;bool operator<=(const string& obj)const;bool operator==(const string& obj)const;bool operator!=(const string& obj)const;private:char* _str;//指向存放字符串的堆区空间的指针size_t _size;//字符串的有效字符个数size_t _capacity;//字符串的最大容量static const size_t npos;//理论上可以存储的最大字符个数};ostream& operator<< (ostream& os, const string& obj);istream& operator>>(istream& is,string& obj);
}

mystring.cpp

#include"string.h"namespace mystring
{const size_t string::npos = -1;string::string(const string& obj)//因为成员在堆区申请了空间所以要写深拷贝的拷贝构造{_str = new char[obj._size + 1];// 申请size + 1个空间,那多出来的1是给'\0'的strcpy(_str, obj._str);//使用该函数把字符串把obj中的字符串拷贝过来_capacity = obj._capacity;_size = obj._size;}string::string(const char* str) //让str的缺省值为""(空字符串):_size(strlen(str))//构造函数会先走成员初始化列表,借此先计算出size{assert(str != nullptr);//防止传入的字符指针是空的_str = new char[_size + 1];//申请size+1个空间,那多出来的1是给'\0'的strcpy(_str, str);//使用该函数把字符串str中的字符拷贝过来_capacity = _size;//设置初始最大容量和size一样大}string& string::operator=(const string&obj){if (this != &obj)//防止自己赋值给自己{delete[] _str;//先释放接收赋值之前str指向的堆区空间//因为接收赋值之后,str中存放的地址就被覆盖了_str = new char[obj._size + 1];//申请size+1个空间,那多出来的1是给'\0'的strcpy(_str, obj._str);//拷贝字符串(把右参数拷贝给左参数)_size = obj._size;_capacity = obj._capacity;}return *this;}string::~string(){delete[] _str;//释放str指向的堆区空间_str = nullptr;_size = 0;_capacity = 0;}string::iterator string::begin()//普通起始迭代器{return _str;}string::const_iterator string::begin() const//const起始迭代器{return _str;}string::iterator  string::end()//普通结束迭代器{return _str + _size;}string::const_iterator  string::end() const//const结束迭代器{    return _str + _size;}size_t  string::size() const{return _size;}void string::resize(size_t n,char c){if (n > _capacity)//当要调整的size,n大于最大容量时,就要扩容{char* tmp = new char[n +1];//申请size+1个空间,那多出来的1是给'\0'的strcpy(tmp, _str);//拷贝字符串(把右参数拷贝给左参数)delete[] _str;//释放扩容前str指向的空间_str = tmp;//完成扩容for (; _size <n; _size++)//把多出来的有效字符用c补上{_str[_size] = c;}_str[_size] = '\0'; //补完之后加上字符串结束标志'\0'_capacity = n;//更新最大容量}else{if (n > _size)//如果调整之后的size  大于  原来的size//就要把少(n-size)的有效字符用c补上{for (; _size < n; _size++)//把多出来的有效字符用c补上{_str[_size] = c;}_str[_size] = '\0';//补完之后加上字符串结束标志'\0'}else//如果调整之后的size  小于  原来的size//就要把多的字符删除{_size = n;//调整有效字符大小_str[_size] = '\0';//直接把n位置改成'\0'即可删除多余字符}}}size_t string::capacity() const{return _capacity;}void string::reserve(size_t n)//注意:n是指元素个数,不是字节数{if (n > _capacity)//当要调整的容量n大于capacity时,才扩容{char* tmp = new char[n + 1];//申请size+1个空间,那多出来的1是给'\0'的strcpy(tmp, _str);//拷贝字符串(把右参数拷贝给左参数)delete[] _str;//拷贝之后再释放旧空间_str = tmp;//指向新开辟的空间_capacity = n;//更改最大容量}}void string::clear(){_size = 0;_str[0] = '\0';}bool string::empty() const{return _size == 0;//如果size==0就为真,就会return true//如果size!=0就为假,就会return false}char& string::operator[](size_t pos){assert(pos<_size);//防止越界访问return _str[pos];//因为存放字符的空间是连续的//所以直接像数组一样,使用pos位置的字符就可以}//const修饰的对象会自动调用下面这个const char& string::operator[](size_t pos)const{assert(pos < _size);//防止越界访问return _str[pos];}//在串尾加上一个string对象或者  字符串【可以隐式类型转换为string对象】string& string::append(const string& obj){if (_capacity < obj._size + _size)//如果容量不够了{reserve(obj._size + _size);//就扩容}//从指定地址开始  拷贝字符串(把右参数拷贝给左参数)strcpy(_str + _size, obj._str);_size += obj._size;//改变有效字符个数return *this;}//在串尾加上一个字符string& string::append(char ch){if (_capacity <_size+1)//如果容量不够了{reserve(_size + 1);//就扩容}_str[_size++] = ch;_str[_size] = '\0';//\0被ch覆盖了,再加回来return *this;}void string::push_back(char c){append(c);//复用append,尾插一个字符c}string& string::operator+=(const string& obj){append(obj);//复用append,尾插一个string对象/字符串return *this;}string& string::operator+=(char c){append(c);//复用append,尾插一个字符creturn *this;}string& string::assign(const string& obj){*this = obj;return *this;}string& string::insert(size_t pos, const string& obj){if (_capacity < obj._size + _size)//如果容量不够了{reserve(obj._size + _size);//就扩容}//从要插入的pos位置开始,把pos和其之后的字符都//向后移动  传入的对象的size个位置for (int i = _size; i >=(int) pos; i--){_str[i + obj._size] = _str[i];}//把字符串插入进去for (int i = pos,j=0; i<obj._size+pos; i++,j++){_str[i] = obj._str[j];}_size += obj._size;_str[_size] = '\0';//再补上\0return *this;}string& string::insert(size_t pos, char c){if (_capacity < _size + 1){reserve(_size + 1);}for (int i = _size; i >=(int) pos; i--){_str[i + 1] = _str[i];}_str[pos] = c;return *this;}string& string:: erase(size_t pos , size_t len){if (len > _size - pos)//如果len大于pos及其之后的字符的长度  或者 len==npos{_str[pos] = '\0';//就直接把pos及其之后的字符  全部删除_size = pos;//把size更改成新的有效长度}else//否则{//把从pos开始的字符都  用它+len之后的字符进行覆盖,即可完成删除for (int i = pos; i <=_size-len; i++){_str[i] = _str[i + len];}_size -= len;//把size更改成新的有效长度}return *this;}void string::swap(string& obj){//使用库里面的swap把 两个对象的成员变量交换即可std::swap(_str, obj._str);std::swap(_size, obj._size);std::swap(_capacity, obj._capacity);}//获取string对象中的  str成员const char* string::c_str() const{return _str;}//从pos位置开始查找字符串size_t string::find(const string&obj, size_t pos) const{const char* p = NULL; //p为找到的字符串的首地址//使用string.h里面的strstr查找子串,如果  找不到  就返回NULLif ((p=strstr(_str + pos, obj._str)) == NULL){return npos;//找不到  就返回  npos}else{return p - _str;//返回下标,p为找到的字符串的  首地址//p-字符数组的首地址str  等于str到p之前的元素个数-1,即下标}}size_t string::find(char c, size_t pos ) const{for (int i = pos; i < _size; i++){if (_str[i] == c)return i;}return npos;}//把从pos开始的长度为len的子串  作为一个新的字符串返回string string::substr(size_t pos, size_t len) const{if (len > _size - pos)//如果len大于pos及其之后的所有 字符的长度或者len==npos{string tmp(_str + pos);//直接用默认构造把pos及其之后的字符全部  做新串返回return tmp;}else//否则{//申请长度为len+1的空间,多出的1是给\0的char* p = new char[len + 1];strncpy(p, _str+pos, len);//把从pos开始的长度为len的子串拷贝给pp[len] = '\0';string tmp(p);//用默认构造创建出新字符串return tmp;}}//比较两个字符串的大小//返回值大于0就是  左>右// 返回值等于0就是  左=右// 返回值小于0就是  左<右int string::compare(const string& obj) const{//使用string.h里面的  strcmp即可完成判断return strcmp(_str, obj._str);}string string::operator+(const string& obj)const{string tmp(*this);//拷贝构造出一个临时对象tmp += obj;//让临时对象去+=,就不会改变字符串自己了return tmp;//传值返回}string string::operator+(char c)const{string tmp(*this);//拷贝构造出一个临时对象tmp += c;return tmp;}bool string::operator>(const string& obj)const{if (compare(obj) > 0)//返回值大于0就是  左>右//即调用函数的对象>传入的对象return true;elsereturn false;}bool string::operator<(const string& obj)const{if (!(*this >= obj))// < 就是>=取反{return true;}elsereturn false;}bool string::operator>=(const string& obj)const{//大于等于  是  大于或者等于if (*this > obj || *this == obj)return true;elsereturn false;}bool string::operator<=(const string& obj)const{//小于等于就是  不大于,即大于取反if (!(*this > obj))return true;elsereturn false;}bool string::operator==(const string& obj)const{if (compare(obj) == 0)//返回值大于0就是  左=右//即调用函数的对象=传入的对象return true;elsereturn false;}bool string::operator!=(const string& obj)const{//不等于就是  等于取反if (!(*this==obj))return true;elsereturn false;}//ostream是输出流对象,比如我们常用的cout就是  ostream实例化的对象ostream& operator<< (ostream& os, const string& obj){const char* p = obj.c_str();//获取string对象中的 str成员os << p;//可以用字符指针直接输出  它指向  的字符串return os;//为支持链式编程,返回输出流对象的引用}//istream是输入流对象,比如我们常用的  cin  就是  istream实例化的对象istream& operator>>(istream& is, string& obj){char str[100];//存储  输入的  每一行的字符int sum = 0;//使用sum记录输入的  每一行  的字符个数char c = 0;//\n是换行符(回车),所以  没遇到  \n就  没换行while ((c = is.get()) != '\n')//一次读取一个字符{if (sum == 99)//当sum等于99时说明  str数组存不下了{str[sum] = '\0';//末尾加上了\0才是字符串obj += str;//使用+=把str数组中的字符先加上去sum = 0;//把sum置成0,继续记录}else//否则{//把读取到的字符存进str数组里str[sum++] = c;}}//sum!=0说明最后输入的最后一行字符个数  小于99个,没有+=上if (sum != 0){str[sum] = '\0';//末尾加上了\0才是字符串obj += str;//使用+=把str数组中的字符先加上去}return is;//为支持链式编程,返回  输入流对象  的引用}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

超详细的Pycharm使用虚拟环境搭建Django项目并创建新的虚拟环境教程

一、什么是虚拟环境&#xff1f; 通过软件虚拟出来的开发环境&#xff0c;不是真实存在的&#xff0c;一般在多套环境开发时会用到。 二、为什么要使用虚拟环境&#xff1f; 虚拟环境为不同的项目创建不同的开发环境&#xff0c;开发环境内所有使用的工具包互不影响。比如项…

Android笔记-adb keycode大全

使用方法 用adb发送按键事件时&#xff0c;可以使用下面表中的枚举值或者直接使用数值&#xff0c;比如 adb shell input keyevent KEYCODE_HOME 或者 adb shell input keyevent 3 下面按三种排序方法列出所有按键的 keycode&#xff0c; 分别是&#xff1a; 按功能分 按枚…

【Linux】高级IO——五种IO模型和基本概念 ,非阻塞IO,fcntl,实现非阻塞IO,同步通信和异步通信

文章目录 Linux高级IO1. 五种IO模型1.1 阻塞IO1.2 非阻塞IO1.3 信号驱动IO1.4 IO多路转接1.5 异步IO 2. 同步通信和异步通信3. 阻塞和非阻塞 Linux高级IO 1. 五种IO模型 IO是什么&#xff1f; IO是计算机领域中的缩写&#xff0c;指的是输入/输出&#xff08;Input/Output&…

设置日历程序

目录 一 设计原型 二 后台源码 一 设计原型 二 后台源码 namespace 设置日历 {public partial class Form1 : Form{public Form1(){InitializeComponent();}private void dateTimePicker1_ValueChanged(object sender, EventArgs e){richTextBox1.Text dateTimePicker1.T…

linux系统中vim ls grep等命令无法使用

linux突然vim ls grep等命令无法使用 系统配置路径被修改导致无法使用: echo $PATH 查看配置路径 添加路径 执行以下命令 export PATH$PATH:/root/bin export PATH$PATH:/usr/sbin

基于ARM的通用的Qt移植思路

文章目录 实验环境介绍一、确认Qt版本二、确认交叉编译工具链三、配置Qt3.1、修改qmake.conf3.2、创建autoConfig.sh配置文件 四、编译安装Qt五、移植Qt安装目录六、配置Qt creator6.1、配置qmake6.2、配置GCC编译器6.3、配置G编译器6.4、配置编译器套件6.5、创建应用 七、总结…

Keil Pack Installer

本文仅介绍了安装Pack&#xff0c;今晚2024-6-28会录制视频&#xff0c;详细讲解安装卸载的各种方法 前言 大家好&#xff0c;我是梁国庆。 收到粉丝留言&#xff0c;说 Keil 安装 Pack 不太明白&#xff0c;可不可以详细演示一下&#xff1f; 当然可以有&#xff0c;本篇安…

搭建一个简单的xxljob

数据库表结构&#xff1a; YyJobInfo&#xff1a; public class YyJobInfo {//定时任务idprivate int id;//该定时任务所属的执行器的idprivate int jobGroup;//定时任务描述private String jobDesc;//定时任务添加的时间private Date addTime;//定时任务的更新时间private D…

百问网全志D1h开发板投屏功能实现

投屏功能实现 D1系列号称点屏神器&#xff0c;不仅能点屏&#xff0c;还能用于投屏。 源码准备 百问网为 【百问网D1h开发板】提供了投屏功能需要使用的源码&#xff0c;直接git下载即可&#xff1a; git clone https://github.com/DongshanPI/DongshannezhaSTU_DLNA_Scree…

Web应用安全测试-专项漏洞(一)

Web应用安全测试-专项漏洞&#xff08;一&#xff09; 专项漏洞部分注重测试方法论&#xff0c;每个专项仅列举一个例子。实际测试过程中&#xff0c;需视情况而定。 文章目录 Web应用安全测试-专项漏洞&#xff08;一&#xff09;Web组件&#xff08;SSL/WebDAV&#xff09;漏…

擎耀解码汽车大灯照明系统电动调节步进电机位置反馈的解决方案

在现代汽车设计中&#xff0c;智能照明系统扮演着至关重要的角色。其中&#xff0c;汽车大灯的电动调节功能不仅提高了夜间行车的安全性&#xff0c;还增强了车辆的科技感和便利性。然而&#xff0c;要实现精准的大灯角度调节&#xff0c;步进电机的位置反馈机制尤为关键。擎耀…

数据库原理与安全复习笔记(未完待续)

1 概念 产生与发展&#xff1a;人工管理阶段 → \to → 文件系统阶段 → \to → 数据库系统阶段。 数据库系统特点&#xff1a;数据的管理者&#xff08;DBMS&#xff09;&#xff1b;数据结构化&#xff1b;数据共享性高&#xff0c;冗余度低&#xff0c;易于扩充&#xff…

SpringBoot脚手架MySpringBootAPI(PgSQL+Druid+MyBatisPlus+Lombok)

MySpringBootAPI SpringBoot脚手架&#xff0c;基于SpringBootDruidPgSQLMyBatisPlusFastJSONLombok&#xff0c;其他的请自行添加和配置。 Author powered by Moshow郑锴(大狼狗) , https://zhengkai.blog.csdn.net 如何运行 1.首先确保你是JDK17&#xff0c;推荐微软的MSJDK…

Links: Challenging Puzzle Game Template(益智游戏模板)

链接:挑战益智游戏 《Links》是一款独特且具有挑战性的益智游戏,即将发布。 每个级别都会向玩家展示不同的棋盘。目标是通过移动和旋转所有棋子来连接它们。每个棋子都有自己的特点和功能-你可以移动它们,旋转它们,或者两者兼而有之。连接所有棋子,以解决难度和挑战不断增…

【系统架构设计师】七、信息安全技术基础知识(访问控制技术|抗攻击技术|计算机系统安全保护能力等级)

目录 一、访问控制技术 二、信息安全的抗攻击技术 2.1 分布式拒绝服务DDoS与防御 2.3 ARP欺骗攻击与防御 2.4 DNS欺骗与防御 2.5 IP欺骗与防御 2.6 端口扫描&#xff08;Port Scanning&#xff09; 2.7 强化TCP/IP堆栈以抵御拒绝服务攻击 2.8 系统漏洞扫描 三、信息安…

实现矩阵乘法【矩阵乘法复杂度优化】

实现矩阵乘法【矩阵乘法复杂度优化】 题目描述&#xff1a;解题思路一&#xff1a;使用NumPy库解题思路二&#xff1a;三个for循环解题思路三&#xff1a;分块矩阵乘法, 利用多线程或多进程 题目描述&#xff1a; 实现矩阵乘法【矩阵乘法复杂度优化】 解题思路一&#xff1a;…

面试突击:Java 集合知识体系梳理

本文已收录于&#xff1a;https://github.com/danmuking/all-in-one&#xff08;持续更新&#xff09; 前言 哈喽&#xff0c;大家好&#xff0c;我是 DanMu。在 Java 开发中&#xff0c;集合类对象绝对是被使用最频繁的对象之一。因此&#xff0c;深入了解集合类对象的底层数…

World of Warcraft T2.5

World of Warcraft T2.5 猎人和术士套装需要的材料&#xff0c;好多啊&#xff0c;废墟和神殿打材料 猎人&#xff1a; 术士&#xff1a;

k8s学习--k8s群集部署zookeeper应用及详细解释

文章目录 zookeeper什么是zookeeper基本概念主要功能工作原理使用场景优点缺点 k8s集群部署zookeeper环境一、zookeeper部署YAML资源清单准备二、zookeeper部署及部署验证三、zookeeper应用验证 zookeeper 什么是zookeeper ZooKeeper 是一个开源的分布式协调服务&#xff0c;…

多线程(基础)

前言&#x1f440;~ 上一章我们介绍了什么是进程&#xff0c;对于进程就了解那么多即可&#xff0c;我们作为java程序员更关注线程&#xff0c;线程内容比较多&#xff0c;所以我们要分好几部分才能讲完 目录 进程的缺点 多线程&#xff08;重要&#xff09; 进程和线程的区…