C++ ——string的模拟实现

目录

前言

浅记

1. reserve(扩容) 

2. push_back(尾插) 

3. iterator(迭代器)

4. append(尾插一个字符串)

5. insert 

5.1 按pos位插入一个字符

5.2 按pos位插入一个字符串

6. erase 

7. find

7.1 查找字符

7.2 查找字符串

8. substr 

 代码汇总

string.h

string.cpp


前言

        C++ —— 关于string类-CSDN博客icon-default.png?t=O83Ahttps://blog.csdn.net/hedhjd/article/details/142023625?spm=1001.2014.3001.5501


浅记

char* _str;字符串存储空间首地址指针
size_t _size; 当前存储的有效数据个数
size_t _capacity;可用容量

*
_str:指向字符串存放的空间的指针
_size:当前存储的有效数据个数 ,指向最后一个字符的下一个位置
_capacity:代表当前可存储的最大容量
nops:此值设置为 -1,无符号整型转换就是42亿,且此值为const和静态参数具有全局效应,某些函数设置其为缺省参数

 


1. reserve(扩容) 

void string::reserve(size_t n)
{//如果字符串存储的数据大于容量if (n > _capacity){//cout << "reserve:" << n << endl;//申请新空间赋给临时变量tmp  + 1是位\0申请的空间char* tmp = new char[n + 1];//把数据拷贝到临时变量里strcpy(tmp, _str);//释放旧空间delete[] _str;//指向新空间_str = tmp;//字符串存储的数据等于容量_capacity = n;}
}


2. push_back(尾插) 

//尾插
void string::push_back(char ch)
{//如果当前的有效数据个数和最大容量相等 if (_size == _capacity){//那么扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}//因为size指向最后一个字符的下一个位置,所以直接插入_str[_size] = ch;++_size;//最后要加一个\0,不然会乱码_str[_size] = '\0';
}

先判断是否还有剩余空间如果满了就进行扩容操作。扩容后在_size位置放上我们要插入的字符,然后++_size,最后在_size的后一个位置补上'\0',防止乱码


3. iterator(迭代器)

const size_t string::npos = -1;string::iterator string::begin()
{return _str;
}string::iterator string::end()
{return _str + _size;
}string::const_iterator string::begin() const
{return _str;
}string::const_iterator string::end() const
{return _str + _size;
}

 


4. append(尾插一个字符串)

//尾插一个字符串//_str:指向字符串存放的空间的指针//_size:当前存储的有效数据个数, 指向最后一个字符的下一个位置void string::append(const char* str){//先计算要插入的字符长度,将值赋给临时变量lensize_t len = strlen(str); //如果当前存储的有效数据个数 加上 要插入的字符 大于 容量if (_size + len > _capacity){// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}//将目标地址到\0的位置中间的值拷贝过去strcpy(_str + _size, str);//尾插_size += len;}

如果尾插后的字符串所需空间大于现有空间就扩容,然后使用strcpy函数将需要尾插的字符串从_str + _size的位置开始拷贝,最后插入len即可


5. insert 

5.1 按pos位插入一个字符

//按pos位插入一个字符
void string::insert(size_t pos, char ch)
{assert(pos <= _size);//如果当前的有效数据个数和最大容量相等 if (_size == _capacity){//那么扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}// 挪动数据//_size + 1:\0的后一位//把end指向\0的后一位size_t end = _size + 1;//循环将pos之后的数据都向后挪动一位while (end > pos){_str[end] = _str[end - 1];--end;}//将字符ch放入pos位_str[pos] = ch;++_size;
}

先判断是否需要扩容,然后定义一个end指向'\0'的下一个位置,然后将pos之后的数据都向后挪动一位,最后将字符ch放入pos位

5.2 按pos位插入一个字符串

//按pos位插入一个字符串
void string::insert(size_t pos, const char* str)
{assert(pos <= _size);//先计算要插入的字符长度,将值赋给临时变量lensize_t len = strlen(str);//如果当前存储的有效数据个数 加上 要插入的字符 大于 容量if (_size + len > _capacity){// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}//定义一个end指向_size + len的位置上size_t end = _size + len;//通过循环把pos后的len个数据向后挪动len个位置while (end > pos + len - 1){_str[end] = _str[end - len];--end;}// 这里不能用 strcpy 会把 '\0' 拷贝过来//使用memcpy函数进行拷贝的原因是memcpy函数不会自动补上'\0'// 而strcpy函数会在拷贝后自动补上'\0’,//把str里的len个数据拷贝到_str + pos里memcpy(_str + pos, str, len);//插入字符串_size += len;
}

 先计算要插入的字符长度,将值赋给临时变量len,判断是否需要扩容,然后定义一个end指向_size + len 的位置。通过循环来控制将pos后的len个数据向后挪动len个位置,然后使用memcpy函数把str里的len个数据拷贝到_str + pos里


6. erase 

//从pos位置开始删除长度为的len的字符串
//_str:指向字符串存放的空间的指针
//_size:当前存储的有效数据个数, 指向最后一个字符的下一个位置
void string::erase(size_t pos, size_t len)
{//判断是否会越界assert(pos < _size);//如果要删除的字符  大于等于  当前存储的有效数据个数 减去 当前指向数据的位置if (len >= _size - pos){//直接将pos位置置为\0_str[pos] = '\0';_size = pos;}//如果要删除的字符  小于  当前存储的有效数据个数减去当前指向数据的位置else{//将_str + pos + len(要保留的数据)位置的字符串直接拷贝到_str + pos(要删除的数据)位置直接覆盖掉strcpy(_str + pos, _str + pos + len);_size -= len;}
}

 先进行判断len是否大于等于pos后面的元素个数,如果大于等于的话,就将pos位及其之后的元素全部删除,直接将pos位置置为'\0',然后将有效数据个数置为pos

如果len小于pos后面的元素个数的话,就将_str + pos + len位置的字符串直接拷贝到_str + pos位置,直接将要删除的那len个元素覆盖,最后有效数据更新即可


7. find

7.1 查找字符

//查找字符//查找对应的字符,返回对应的下标size_t string::find(char ch, size_t pos){assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}


7.2 查找字符串

strstr:在一个字符串中查找另一个字符串 ,返回子串在原串里第一个出现的位置
str1:原串       str2:子串
const char * strstr ( const char * str1, const char * str2 );


size_t string::find(const char* str, size_t pos)
{assert(pos < _size);//通过strstr函数来将str作为子串找到它的地址const char* ptr = strstr(_str + pos, str);//匹配失败if (ptr == nullptr){return npos;}else//匹配成功{//ptr的地址减去_str的地址就是我们要找的字符串的起始位置的下标return ptr - _str;}
}

通过strstr函数来将str作为子串找到它的地址,然后sub的地址减去_str的地址就是我们要找的字符串的起始位置的下标


8. substr 

//从pos位置开始截取长度为len的字符再构造一个子串,子串返回
string string::substr(size_t pos, size_t len)
{assert(pos < _size);// 如果len大于剩余字符长度if (len > _size - pos){//把len更新成为一个有效的长度,有多少长度取多少空间len = _size - pos;}//构造一个子串substring sub;//先给sub预留len个空间sub.reserve(len);//for循环遍历要截取的字符for (size_t i = 0; i < len; i++){//将从pos位置开始长度为len的字符尾插到sub中sub += _str[pos + i];}return sub;
}

先判断len是否大于剩余字符的长度,如果len大于剩余字符的长度就把len更新成为一个有效的长度,有多少长度取多少空间,然后再构造一个子串sub,先给sub预留len个空间,然后通过遍历将从pos位置开始长度为len的字符尾插到sub中最后直接返回sub 


 代码汇总

string.h

 

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once#include<iostream>
#include<string>
#include<assert.h>
using namespace std;namespace bit
{class string{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():_str(new char[1]{'\0'}),_size(0),_capacity(0){}*/// 短小频繁调用的函数,可以直接定义到类里面,默认是inlinestring(const char* str = ""){_size = strlen(str);// _capacity不包含\0_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}// 深拷贝问题// // s2(s1)string(const string& s){_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}// s2 = s1// s1 = s1string& operator=(const string& s){if (this != &s){delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;}~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}const char* c_str() const{return _str;}//将字符串的内容清空void clear(){_str[0] = '\0';_size = 0;}size_t size() const{return _size;}size_t capacity() const{return _capacity;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos) const{assert(pos < _size);return _str[pos];}void reserve(size_t n);void push_back(char ch);void append(const char* str);string& operator+=(char ch);string& operator+=(const char* str);void insert(size_t pos, char ch);void insert(size_t pos, const char* str);void erase(size_t pos, size_t len = npos);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);string substr(size_t pos = 0, size_t len = npos);private: //设置私有,不允许随便访问底层数据char* _str;//字符串存储空间首地址指针size_t _size; //当前存储的有效数据个数size_t _capacity;//可用容量//static const size_t npos = -1;static const size_t npos;/*_str:指向字符串存放的空间的指针_size:当前存储的有效数据个数 ,指向最后一个字符的下一个位置_capacity:代表当前可存储的最大容量nops:此值设置为 -1,无符号整型转换就是42亿,且此值为const和静态参数具有全局效应,某些函数设置其为缺省参数*/};bool operator<(const string& s1, const string& s2);bool operator<=(const string& s1, const string& s2);bool operator>(const string& s1, const string& s2);bool operator>=(const string& s1, const string& s2);bool operator==(const string& s1, const string& s2);bool operator!=(const string& s1, const string& s2);ostream& operator<<(ostream& out, const string& s);istream& operator>>(istream& in, string& s);
}


string.cpp

 

#include"string.h"//char* _str;字符串存储空间首地址指针
//size_t _size; 当前存储的有效数据个数
//size_t _capacity;可用容量
//static const size_t npos = -1;
/*_str:指向字符串存放的空间的指针
_size:当前存储的有效数据个数 ,指向最后一个字符的下一个位置
_capacity:代表当前可存储的最大容量
nops:此值设置为 -1,无符号整型转换就是42亿,且此值为const和静态参数具有全局效应,某些函数设置其为缺省参数*/namespace bit
{const size_t string::npos = -1;//扩容void string::reserve(size_t n){//如果字符串存储的数据大于容量if (n > _capacity){//cout << "reserve:" << n << endl;//申请新空间赋给临时变量tmp  + 1是位\0申请的空间char* tmp = new char[n + 1];//把数据拷贝到临时变量里strcpy(tmp, _str);//释放旧空间delete[] _str;//指向新空间_str = tmp;//字符串存储的数据等于容量_capacity = n;}}//尾插void string::push_back(char ch){//如果当前的有效数据个数和最大容量相等 if (_size == _capacity){//那么扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}//因为size指向最后一个字符的下一个位置,所以直接插入_str[_size] = ch;++_size;//最后要加一个\0,不然会乱码_str[_size] = '\0';}//尾插一个字符串//_str:指向字符串存放的空间的指针//_size:当前存储的有效数据个数, 指向最后一个字符的下一个位置void string::append(const char* str){//先计算要插入的字符长度,将值赋给临时变量lensize_t len = strlen(str);//如果当前存储的有效数据个数 加上 要插入的字符 大于 容量if (_size + len > _capacity){// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}//将目标地址到\0的位置中间的值拷贝过去strcpy(_str + _size, str);//尾插_size += len;}//尾插一个字符string& string:: operator+=(char ch){push_back(ch);return *this;}//尾插一个字符串string& string::operator+=(const char* str){append(str);return *this;}//按pos位插入一个字符void string::insert(size_t pos, char ch){assert(pos <= _size);//如果当前的有效数据个数和最大容量相等 if (_size == _capacity){//那么扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}// 挪动数据//_size + 1:\0的后一位//把end指向\0的后一位size_t end = _size + 1;//循环将pos之后的数据都向后挪动一位while (end > pos){_str[end] = _str[end - 1];--end;}//将字符ch放入pos位_str[pos] = ch;++_size;}//按pos位插入一个字符串void string::insert(size_t pos, const char* str){assert(pos <= _size);//先计算要插入的字符长度,将值赋给临时变量lensize_t len = strlen(str);//如果当前存储的有效数据个数 加上 要插入的字符 大于 容量if (_size + len > _capacity){// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}//定义一个end指向_size + len的位置上size_t end = _size + len;//通过循环把pos后的len个数据向后挪动len个位置while (end > pos + len - 1){_str[end] = _str[end - len];--end;}// 这里不能用 strcpy 会把 '\0' 拷贝过来//使用memcpy函数进行拷贝的原因是memcpy函数不会自动补上'\0'// 而strcpy函数会在拷贝后自动补上'\0’,//把str里的len个数据拷贝到_str + pos里memcpy(_str + pos, str, len);//插入字符串_size += len;}//从pos位置开始删除长度为的len的字符串//_str:指向字符串存放的空间的指针//_size:当前存储的有效数据个数, 指向最后一个字符的下一个位置void string::erase(size_t pos, size_t len){//判断是否会越界assert(pos < _size);//如果要删除的字符  大于等于  当前存储的有效数据个数 减去 当前指向数据的位置if (len >= _size - pos){//直接将pos位置置为\0_str[pos] = '\0';_size = pos;}//如果要删除的字符  小于  当前存储的有效数据个数减去当前指向数据的位置else{//将_str + pos + len(要保留的数据)位置的字符串直接拷贝到_str + pos(要删除的数据)位置直接覆盖掉strcpy(_str + pos, _str + pos + len);_size -= len;}}//查找字符//查找对应的字符,返回对应的下标size_t string::find(char ch, size_t pos){assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}//查找字符串//strstr:在一个字符串中查找另一个字符串 // 返回子串在原串里第一个出现的位置//str1:原串       str2:子串//const char * strstr ( const char * str1, const char * str2 );size_t string::find(const char* str, size_t pos){assert(pos < _size);//通过strstr函数来将str作为子串找到它的地址const char* ptr = strstr(_str + pos, str);//匹配失败if (ptr == nullptr){return npos;}else//匹配成功{//ptr的地址减去_str的地址就是我们要找的字符串的起始位置的下标return ptr - _str;}}//从pos位置开始截取长度为len的字符再构造一个子串,子串返回string string::substr(size_t pos, size_t len){assert(pos < _size);// 如果len大于剩余字符长度if (len > _size - pos){//把len更新成为一个有效的长度,有多少长度取多少空间len = _size - pos;}//构造一个子串substring sub;//先给sub预留len个空间sub.reserve(len);//for循环遍历要截取的字符for (size_t i = 0; i < len; i++){//将从pos位置开始长度为len的字符尾插到sub中sub += _str[pos + i];}return sub;}//string比较大小按照ascii码比//strcmp:如果第一个数大于/小于/等于第二个数,那么返回>0/<0/0//小于bool operator<(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) < 0;}//小于等于bool operator<=(const string& s1, const string& s2){return s1 < s2 || s1 == s2;}//大于bool operator>(const string& s1, const string& s2){return !(s1 <= s2);}//大于等于bool operator>=(const string& s1, const string& s2){return !(s1 < s2);}//等于bool operator==(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) == 0;}//不等于bool operator!=(const string& s1, const string& s2){return !(s1 == s2);}//流插入
ostream& operator<<(ostream& out, const string& s)
{for (auto ch : s){out << ch;}return out;
}//流提取
istream& operator>>(istream& in, string& s)
{s.clear();const int N = 256;char buff[N];int i = 0;char ch;//in >> ch;ch = in.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}//in >> ch;ch = in.get();}if (i > 0){buff[i] = '\0';s += buff;}return in;
}


感谢观看~

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

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

相关文章

后端入门 (JQuery基础) 01

引入jQuery资源&#xff08;https://cdn.staticfile.net/jquery/1.10.2/jquery.min.js&#xff09; <script src"jquery.js"></script> <!-- 引入jQuery资源 --> 绑定事件的方式&#xff1a; 1. 直接使用事件函数 $("p").click(func…

C++第五十一弹---IO流实战:高效文件读写与格式化输出

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 目录 1. C语言的输入与输出 2. 流是什么 3. CIO流 3.1 C标准IO流 3.2 C文件IO流 3.2.1 以写方式打开文件 3.2.1 以读方式打开文件 4 stringstre…

flask框架

Flask 1 flask简介 我们之所以在浏览器中输入localhost:8080然后就可以把webapps下面的项目文件以浏览器的方式打开&#xff0c;功臣在与tomcat。python语言写的项目&#xff0c;转换为web&#xff0c;Flask框架 轻量级web应用框架。 环境准备&#xff1a; pip install fl…

【C语言】内存函数详细讲解

文章目录 前言strerror的声明和使用字符串分类函数字符转换函数内存拷贝函数&#xff08;memcpy)memcpy的声明和使用memcpy函数的模拟实现 内存拷贝函数&#xff08;memmove&#xff09;memmove的声明和使用memmove模拟实现 内存比较函数&#xff08;memcmp&#xff09;memcmp的…

UDP_SOCKET编程实现

文章目录 socket编程接口认识struct sockaddr类 编写一个server服务Client代码查看启动结果代码修正1.获取内核分配给客户端的信息2.修正不匹配ip不能访问的问题 不同机器之间的通信利用xftp将udp_client传给wsl的ubuntu机器进行演示现在模拟在windows下的udp_client代码: 对方…

时序预测 | MATLAB实现BKA-XGBoost(黑翅鸢优化算法优化极限梯度提升树)时间序列预测

时序预测 | MATLAB实现BKA-XGBoost(黑翅鸢优化算法优化极限梯度提升树)时间序列预测 目录 时序预测 | MATLAB实现BKA-XGBoost(黑翅鸢优化算法优化极限梯度提升树)时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 Matlab实现BKA-XGBoost时间序列预测&a…

WPF UpdateSourceTrigger属性

在WPF&#xff08;Windows Presentation Foundation&#xff09;中&#xff0c;UpdateSourceTrigger 是一个属性&#xff0c;通常用于数据绑定中&#xff0c;它控制着何时将绑定目标&#xff08;即UI元素&#xff09;的值更新到绑定源&#xff08;即数据对象&#xff09;。当UI…

Go语言现代web开发08 if和switch分支语句

if语句 If is the most common conditional statement in programming languages. If the result of the condition caculation is positive(true), the code inside if statement will be executed. In the next example, value a will be incremented if it is less than 10…

《黑神话:悟空》:中国游戏界的新篇章

引言&#xff1a; 在数字娱乐的浪潮中&#xff0c;游戏已成为连接全球文化的重要媒介。 《黑神话&#xff1a;悟空》的问世&#xff0c;不仅是中国游戏产业的一个里程碑&#xff0c;更是文化自信的闪耀展现。 这款游戏以其独特的艺术风格和深刻的文化内涵&#xff0c;在全球范…

k8s中的认证授权

目录 一、kubernetes API 访问控制 1.1 UserAccount与ServiceAccount 1.1.1 ServiceAccount 1.1.2 ServiceAccount示例 二、认证(在k8s中建立认证用户) 2.1 创建UserAccount 2.2 RBAC&#xff08;Role Based Access Control&#xff09; 2.2.1 基于角色访问控制授权&…

RT-DETR改进策略:BackBone改进|使用StarNet改进RT-DERT,显著提升性能与效率

摘要 本文介绍了我们如何将最新的StarNet模型成功应用于实时目标检测任务中,特别是用于改进RT-DERT(一种高效的实时目标检测网络)的主干网络部分。通过详尽的实验和理论分析,我们证明了StarNet不仅能够显著增强RT-DERT的检测精度,同时保持了高效的计算性能和低延迟特性。…

C++从入门到起飞之——继承下篇(万字详解) 全方位剖析!

&#x1f308;个人主页&#xff1a;秋风起&#xff0c;再归来~&#x1f525;系列专栏&#xff1a;C从入门到起飞 &#x1f516;克心守己&#xff0c;律己则安 目录 1、派⽣类的默认成员函数 1.1 四个常⻅默认成员函数 1.2 实现⼀个不能被继承的类 ​编辑 2. 继承与友…

力扣题解2390

大家好&#xff0c;欢迎来到无限大的频道。 今日继续给大家带来力扣题解。 题目描述​&#xff08;中等&#xff09;&#xff1a; 从字符串中移除星号 给你一个包含若干星号 * 的字符串 s 。 在一步操作中&#xff0c;你可以&#xff1a; 选中 s 中的一个星号。 移除星号…

力扣刷题(6)

两数之和 II - 输入有序数组 两数之和 II - 输入有序数组-力扣 思路&#xff1a; 因为该数组是非递减顺序排列&#xff0c;因此可以设两个左右下标当左右下标的数相加大于target时&#xff0c;则表示右下标的数字过大&#xff0c;因此将右下标 - -当左右下标的数相加小于targ…

HashMap线程不安全|Hashtable|ConcurrentHashMap

文章目录 常见集合线程安全性HashMap为什么线程不安全&#xff1f;怎么保证HashMap线程安全 HashtableConcurrentHashMap 引入细粒度锁代码中分析总结 小结 常见集合线程安全性 ArrayList、LinkedList、TreeSet、HashSet、HashMap、TreeMap等都是线程不安全的。 HashTable是线…

C语言:数组

1. 数组的概念 数组是⼀组相同类型元素的集合&#xff1b;从这个概念中我们就可以发现2个有价值的信息&#xff1a; • 数组中存放的是1个或者多个数据&#xff0c;但是数组元素个数不能为0。 • 数组中存放的多个数据&#xff0c;类型是相同的。 数组分为⼀维数组和多维数组…

【C语言必学知识点七】你知道在动态内存管理中存在的内存泄露问题吗?遇到内存泄露时应该如何处理?今天跟你好好介绍一下如何正确使用calloc与realloc!!!

动态内存管理——动态函数&#xff08;calloc、realloc&#xff09;的使用 导读一、calloc函数1.1 函数介绍1.2 calloc的使用1.3 calloc与malloc 二、realloc函数2.1 函数介绍2.2 realloc的使用2.3 realloc的空间分配2.3.1 空间分配成功——地址的改变2.3.2 空间分配失败——内…

【在Linux世界中追寻伟大的One Piece】数据链路层

目录 1 -> 数据链路层 2 -> 对比理解“数据链路层”和“网络层” 3 -> 以太网 3.1 -> 以太网的帧格式 4 -> 认识MAC地址 4.1 -> 对比理解MAC地址和IP地址 5 -> 认识MTU 5.1 -> MTU对IP协议的影响 5.2 -> MTU对UDP协议的影响 5.3 -> MT…

ElasticSearch介绍+使用

ElasticSearch 1.背景 ElasticSearch的最明显的优势在于其分布式特性&#xff0c;能够扩展到上百台服务器&#xff0c;极大地提高了服务器的容错率。在大数据时代背景下&#xff0c;ElasticSearch与传统的数据库相比较&#xff0c;能够应对大规模的并发搜索请求&#xff0c;同…

JavaScript网页设计案例分析

JavaScript网页设计案例分析 随着互联网技术的发展&#xff0c;JavaScript 已经成为现代网页设计中不可或缺的一部分。从简单的页面交互到复杂的应用程序开发&#xff0c;JavaScript 都发挥着至关重要的作用。本文将探讨几个运用 JavaScript 进行网页设计的经典案例&#xff0…