公益 建网站/官网排名优化

公益 建网站,官网排名优化,wordpress html编辑器,网站运营公司哪家值得推荐目录 前情提要Member functions —— 成员函数构造函数拷贝构造函数赋值运算符重载析构函数 Element access —— 元素访问Iterator —— 迭代器Capacity —— 容量sizecapacityclearemptyreserveresize Modifiers —— 修改器push_backappendoperator(char ch)operator(const …

目录

  • 前情提要
  • Member functions —— 成员函数
    • 构造函数
    • 拷贝构造函数
    • 赋值运算符重载
    • 析构函数
  • Element access —— 元素访问
  • Iterator —— 迭代器
  • Capacity —— 容量
    • size
    • capacity
    • clear
    • empty
    • reserve
    • resize
  • Modifiers —— 修改器
    • push_back
    • append
    • operator+=(char ch)
    • operator+=(const char* s)
    • 在pos位置插入n个字符
    • 删除pos位置的n个元素
    • swap
  • String Operations —— 字符串操作
    • 从pos位置开始找指定的字符
    • 从pos位置开始找指定的字符串(找子串)
    • 从pos位置开始取len个有效字符(取子串)
  • 流插入和流提取
    • 流插入
    • 流提取
  • swap函数解析
  • 源码

前情提要

因为我们接下来实现的类和和库中std命名空间的string类的类名相同,所以我们为了防止冲突,用一个bit命名的命名空间解决这个问题

namespace bit
{class string {public://...private:size_t _size;size_t _capacity;char* _str;};
}
  • 接下去呢,就在测试的test3.cpp中包含一下这个头文件,此时我们才可以在自己实现的类中去调用一些库函数
#include <iostream>
#include <assert.h>
using namespace std;#include "string.h"

Member functions —— 成员函数

构造函数

  • 这里我们把构造函数的声明放在string.h的头文件中,然后用分文件编写的设计在stirng.cpp中实现构造函数的源代码
string::string():_str(new char[1] {'\0'}) , _size(0), _capacity(0)
{}
  • 我们利用构造函数的初始化列表来初始化类的3个成员变量,_str表示存储的string的内存空间,_size表示string对象的长度,_capacity表示这个string 对象的占用空间是多少个字节

或许有的兄弟会有疑问,为什么初始化_str的时候,开辟_str的空间要用 new char[1]而不是new char,这是因为我们string的数据存储都是连续存储在一起的,用\0标识结束位置,如果用new char那么单独在各个不连续的空间并不能让每个数据后面都有\0,所以我们new char[]连续的空间,存储在一起,在这块连续的空间后放上\0。

  • 然后我们立即来测试一下,因为我们自己实现的 string类 是包含在了命名空间bit中的,那么我们在使用这个类的时候就要使用到 域作用限定符::
bit::string s1;

接下来有了无参的构造函数,我们再重载一个有参的字符串构造函数

	string::string(const char* str):_size(strlen(str)){_capacity = _size;_str = new char[_size + 1];strcpy(_str, str);}
  • 先说一下为什么初始化列表我值初始化了_size
    在这里插入图片描述

在这里插入图片描述

  • 看到了吗?不是,哥们,怎么_size都还没初始化就去把_str初始化了,这个时候问题就不来了吗,开的空间大小就是随机的一个值。
  • 那为什么会出现这个情况呢?
    在这里插入图片描述
  • 这个我在类和对象的文章里面讲过,初始化列表要按照类中成员变量的声明顺序来初始化,很明显_str这个变量比_size这个变量先声明,所以这里就会出现先初始化_str变量需要用_size,但是_size还没有初始化的问题

综上,这就是为什么在初始化列表初始只初始化_size的原因,这样保证一个变量的顺序一定是正确的。其余的变量在函数体里面初始化, 当然第一个无参构造也可以这么写,我这里提出来这个写法就是想说明注意这个问题。

拷贝构造函数

  • 在类和对象的文章中,我讲过,一个对象拷贝给另一个对象,拷贝构造函数对于内置类型不做处理,对于自定义类型那么就要调用那个被拷贝对象的默认构造函数来拷贝给另一个对象。那么这个时候就会发生浅拷贝的问题。
    在这里插入图片描述
  • 所谓的浅拷贝,就是如上面一样, s2是s1的拷贝,但是这种拷贝他不会让s1指向原来的空间,s2指向新开辟的空间,浅拷贝只是把s1中3个成员变量的值拷贝过去,并不会执行开空间操作,这时候两个对象的_str的成员变量都指向一个空间,就会导致其中一个对象已经析构了这块空间,另一个对象销毁的时候又对这块已经被析构了的空间造成二次析构,这相当于就是内存泄露,一块空间已经还给操作系统了,我们还通过一个指针来访问这块空间,这时候编译器就会报错了。
  • 在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 所以我们就要自定义来实现一个拷贝构造函数解决,两个指针指向同一块空间造成两次析构的问题。
	string::string(const string& s){_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}
  • 这段代码,我们就单独给_str开了和被拷贝对象一样大的空间,然后把被拷贝对象的数据拷贝到_str中,完成了深拷贝

赋值运算符重载

对于赋值运算符重载这一块我们知道它也是属于类的默认成员函数,如果我们自己不去写的话类中也会默认地生成一个

  • 但是呢默认生成的这个也会造成一个 浅拷贝 的问题。看到下面图示,我们要执行s1 = s3,此时若不去开出一块新空间的话,那么s1和s3就会指向一块同一块空间,此时便造成了下面这些问题

1.又会造成上面拷贝构造的问题,两次析构
2.因为他们指向同一块空间,修改一个对象就会影响另一个对象
3.原先s1所指向的那块空间没人维护了,就造成了内存泄漏的问题

在这里插入图片描述

	string& string::operator = (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;}}
  • 和拷贝构造一样,但是多了的是我们要把被赋值的对象的_str内存释放了,不然那块空间就没人管了,就会导致内存泄露。
  • 再补充一点这里为啥要判断this != &s ,就是自己给自己赋值,也许大部分人不会这么做,但是不一定有人会用错赋值,就像汽车的车窗防夹功能一样,没人会主动让车窗夹,但是总有些特殊情况。

下面我们来写一个现代的懒人写法

string& string::operator = (string s)
{if (this != &s){swap(s);return *this;}
}
  • 是不是非常的简洁,这个就是用了一个swap函数来解决,来现在我们就来详细说一下这个swap函数是怎么完成赋值拷贝的。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 这就完美的完成了我们s1得到了s2的数据,又把原来s1的空间释放了
    在这里插入图片描述
  • 附上swap的源代码,就是和我们模拟的一样,改变了_str的指向
string::string(const string& s)
{string tmp(s.c_str());swap(tmp);
}
  • 那么拷贝构造也可以利用这个swap函数来完成拷贝给this对象的问题

析构函数

最后的话就是析构函数这一块,前面在调试的过程中我们已经看到很多遍了,此处不再细述

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

Element access —— 元素访问

  • 嘿嘿,这个接口可是非常的好用,让我们string可以像数组一样使用,爽得很。
char& string::operator[](size_t pos)
{assert(pos >= 0 && pos < _size);return _str[pos];
}
  • 因为我们string底层封装的用来存储数据的变量就是一个char*的_str指针,我们在C语言阶段说过,指针是可以像数组那样使用的,所以直接返回_str的pos位置元素就行了,另外注意pos一定是在有效的范围内,所以断言一下
// 可读不可写
const char& operator[](size_t pos) const
{assert(pos < _size);return _str[pos];
}
  • 这个版本就是提供给我们const的string对象使用的

那现在有人问,所以这玩意实现来有什么用?不急,请看VCR
在这里插入图片描述

在这里插入图片描述

  • 是不是很轻松就拿到了string对象中的每个数据

在这里插入图片描述

在这里插入图片描述

  • 看到没,可以像数组一样更改sting对象的数据

所以非常的方便,const对象一样用法,就不展示了。

Iterator —— 迭代器

  • 当然,除了[]可以访问我们的string对象的数据,迭代器也可以
    -而对于迭代器而言我们也是要去实现两种,一个是非const的,一个则是const的
typedef char* iterator;
typedef const char* const_iterator;
  • 这里的话我就实现一下最常用的【begin】和【end】,首位的话就是_str所指向的这个位置,而末位的话则是_str + _size所指向的这个位置
    iterator begin()
iterator begin()
{return _str;
}iterator end()
{return _str + _size;
}
  • const迭代器就是照葫芦画瓢了,只需要重载就行了
const_iterator begin() const
{return _str;
}const_iterator end() const
{return _str + _size;
}

在这里插入图片描述
在这里插入图片描述

Capacity —— 容量

size

  • 首先是size, 这个接口非常的简单,就是统计一下元素个数就行了. 因为不会改变this变量,所以加上一个 const
size_t size() const
{return _size;
}

capacity

  • 对于 capacity() 也是同样的道理
size_t capacity() const
{return _capacity;
}

clear

  • 这个注意只清理元素个数,不会清理内存空间。我们直接在_str[0]这个位置放上一个\0即可,并且再去修改一下它的_size = 0即可
void clear()
{_str[0] = '\0';_size = 0;
}

empty

  • 对于 empty() 来说呢就是对象中没有数据,那么使用0 == _size即可
bool empty() const
{return 0 == _size;
}

reserve

  • 当我们构造函数初始化开辟的空间内存不够的时候,我们就要进行扩容。
// 扩容(修改_capacity)
void reserve(size_t newCapacity = 0)
{// 当新容量大于旧容量的时候,就开空间if (newCapacity > _capacity){// 1.以给定的容量开出一块新空间char* tmp = new char[newCapacity + 1];// 2.将原本的数据先拷贝过来strcpy(tmp, _str);// 3.释放旧空间的数据delete[] _str;// 4.让_str指向新空间_str = tmp;// 5.更新容量大小_capacity = newCapacity;}
}

resize

1.如果n小于_size,那么就把元素个数调整到n就行
2.如果n大于_size小于_capacity,那么把元素个数调整到n,但是不扩容,把多的内存初始为\0
3.如果这个 n > _size 的话,我们便要选择去进行扩容了

void string::resize(size_t n, char ch)
{if (n > _size){if (n > _capacity){reserve(n);}for (size_t i = _size; i < n; i++){_str[i] = ch;}}else{_size = n;_str[n] = '\0';}
}

Modifiers —— 修改器

push_back

  • 首先明确一点,我们只要是要一直插入数据,就需要足够大的空间,需要空间我们要动态的扩容,这里我们设置默认空间4, 每次扩容两倍
  • 最后扩容完,我们就可以安心插入数据了,但是要特别注意在尾插完加上一个\0
	void string::push_back(char ch){//插入之前,检查是否需要扩容if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}_str[_size++] = ch;_str[_size] = '\0';}

append

  • 接下来我们要追加的是一个字符串,首先我们要先计算出这个字符串的长度,然后在我们原有的元素个数上加上这个字符串的长度,如果总长度大于我们的内存再扩容到满足装下这个字符串的长度,否则两倍扩容即可,有效利用空间。
	void string::append(const char* str){size_t len = strlen(str);if (_size + len >= _capacity){int NewCapacity = _capacity == 0 ? 4 : 2 * _capacity;if (NewCapacity < _size + len){NewCapacity = _size + len;}reserve(NewCapacity);}int j = 0;for (size_t i = _size; i <= _size + len; i++){_str[i] = str[j++];}_size += len;}

operator+=(char ch)

  • 首先的话是去【+=】一个字符,这里我们直接复用前面的push_back()接口即可,最后因为【+=】改变的是自身,所以我们return *this,那么返回一个出了作用域不会销毁的对象,可以采取 引用返回 减少拷贝
string& operator+=(char ch)
{push_back(ch);return *this;
}

operator+=(const char* s)

  • 而对于【+=】一个字符串,我们则是去复用前面的append()即可
string& operator+=(const char* s)
{append(s);return *this;
}

在pos位置插入n个字符

	void string::insert(size_t pos, size_t n, char ch){assert(pos <= _size);if (_size + n >= _capacity){int NewCapacity = _capacity == 0 ? 4 : 2 * _capacity;if (NewCapacity < _size + n){NewCapacity = _size + n;}reserve(NewCapacity);}int j = _size;for (size_t i = _size + n; i >= pos + n ; i--){_str[i] = _str[j--];}j = 0;for (size_t i = pos; i <pos + n; i++){_str[i] = ch;}_size += n;}- 首先计算我们插入n个字符后的长度,如果大于内存,我们就需要扩容。然后

在这里插入图片描述
在这里插入图片描述

删除pos位置的n个元素

	void string::erase(size_t pos, size_t len){assert(pos <= _size);int j = pos;if (len != npos){for (size_t i = pos + len; i <= _size; i++){_str[j++] = _str[i];}_size -= len;}else{_str[pos + 1] = '\0';_size = pos + 1;}}

其实就是从pos + len 个位置的元素开始往前覆盖,就行,然后减少长度,在遍历的时候因为我们是遍历到长度的位置就不会遍历到长度之外的字符,然后后面插入的时候也能覆盖

在这里插入图片描述

swap

void swap(string& s)
{std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);
}

String Operations —— 字符串操作

从pos位置开始找指定的字符

  • 从0开始遍历到长度的位置查找有没有指定的字符,如果有返回下标,没有返回npos
size_t find(char ch, size_t pos) const
{assert(pos <= _size);for (size_t i = 0; i < _size; i++){if (_str[i] == ch){return i;}}return npos;
}
  • npos是一个在const静态成员变量的无符号整数,用于标识没查找到指定的内容,原则来说静态成员变量应该在类外初始化,因为他要给类的所以对象使用,可是这里在缺省参数的位置初始化,这个位置原本是留给初始化列表中没初始化成功的,但是这是一个例外.条件必须是const常量 并且整形的数据才能这样写
    在这里插入图片描述

从pos位置开始找指定的字符串(找子串)

  • 这可以使用strstr子串查找函数,如果返回指针为空就没有,否则会返回子串的起始地址,如果我们想要得到子串在_str中的指针距离起始位置指针-指针即可
size_t find(const char* s, size_t pos)	const
{assert(pos < _size);char* tmp = strstr(_str, s);if (tmp){// 指针相减即为距离return tmp - _str;}return npos;
}

从pos位置开始取len个有效字符(取子串)

string string::substr(size_t pos, size_t len)
{assert(pos < _size);if (len > (_size -= pos)){len = _size - pos;	}string sub;sub.reserve(len);for (size_t i = 0; i <= len; i++){sub += _str[pos + i];}return sub;
}
  • 如果截取的长度大于_size - = pos,从pos开始的总长度,最多只能截取到 _size - pos,后面就复用sub += 尾插了

流插入和流提取

流插入

  • 如果不想写s1 << cout这种就需要吧this这个在类中固定第一个位置的参数放在后面去,这样我们就不能重载在类中,重载在全局中
ostream& operator<<(ostream& os, const string& s)
{for (size_t i = 0; i < s.size(); i++){os << s[i];}return os;
}

流提取

istream& operator>>(istream& is,  string& s)
{s.clear(); // 对原来的字符串清理,重新输入char ch;ch = is.get();char buffer[256];int i = 0;while (ch != ' ' && ch != '\n'){buffer[i++] = ch;if (i == 255){buffer[i] = '\0';s += buffer;i = 0;}ch = is.get();}if (i > 0){buffer[i] = '\0';s += buffer;}return is;
}
  • 1.这里输入ch一定要用流提取的get函数,不然cin 和scanf会直接忽略空格和\n, 不会写入到ch里面导致不能结束,get就不会忽略
    2.这里用buffer数组的原因是:尽量减少扩容的次数和空间浪费的情况
    3.所以我们使用一个数组buffer暂存里面,如果buffer存储满了再扩容,这时候只需要扩容一次,而且buffer是在栈上开辟的,是可以这个函数结束就销毁了

在这里插入图片描述

swap函数解析

  • 为啥要自己写一个成员函数swap?可以看一下算法库swap的过程
    在这里插入图片描述在这里插入图片描述

在这里插入图片描述

源码

string.h
#define  _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<assert.h>
using namespace std;
namespace bit
{class string{public:typedef char* iterator;typedef const char* const_iterator;string();string(const char* str);string(const string& s);~string();void reserve(size_t n);iterator begin();iterator end();char& operator[](size_t pos);const char& operator[](size_t pos) const;void insert(size_t pos, char ch);void insert(size_t pos, const char* str);void insert(size_t pos, size_t n, char ch);void erase(size_t pos, size_t len = npos);void clear();void swap(string& s);size_t size() const;const_iterator begin() const;const_iterator end() const;void push_back(char ch);void append(const char* str);void resize(size_t n, char ch = '\0');size_t find(char c, size_t pos = 0);size_t find(const char* str, size_t pos = 0);string& operator+=(char ch);string& operator+=(const char* str);string& operator = (string s);string substr(size_t pos, size_t len = npos);const char* c_str() const{return _str;}private:char* _str = nullptr;size_t _size = 0;size_t _capacity = 0;public:static const size_t npos = -1;};ostream& operator<<(ostream& os, const string& s);istream& operator>>(istream& is,  string& s);istream& getline(istream& is, string& s, char delim = '#');void swap(string& s1, string& s2);
}
string.cpp
#include"String.h"
#include<iostream>
using namespace std;
namespace bit
{typedef char* iterator;typedef const char* const_iterator;string::string():_str(new char[1] {'\0'}) //不能初始化为null实现c_str的时候防止cout对空指针解引用, _size(0), _capacity(0){}string::string(const char* str):_size(strlen(str)){_capacity = _size;_str = new char[_size + 1];strcpy(_str, str);}//传统写法//string::string (const string& s)//{//	_str = new char[s._capacity + 1];//	strcpy(_str, s._str);//	_size = s._size;//	_capacity = s._capacity;//}string::string(const string& s){string tmp(s.c_str());swap(tmp);}string::~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}void string:: reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}iterator string::begin(){return _str;}char& string::operator[](size_t pos){assert(pos >= 0 && pos < _size);return _str[pos];}void string::resize(size_t n, char ch){if (n > _size){if (n > _capacity){reserve(n);}for (size_t i = _size; i < n; i++){_str[i] = ch;}}else{_size = n;_str[n] = '\0';}}const char& string::operator[](size_t pos) const{assert(pos >= 0 && pos <= _size);return _str[pos];}size_t string::size() const{return _size;}iterator string::end(){return _str + _size;}const_iterator string::begin() const{return _str;}const_iterator string::end() const{return _str + _size;}void string::push_back(char ch){//插入之前,检查是否需要扩容if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}_str[_size++] = ch;_str[_size] = '\0';}void string::append(const char* str){size_t len = strlen(str);if (_size + len >= _capacity){int NewCapacity = _capacity == 0 ? 4 : 2 * _capacity;if (NewCapacity < _size + len){NewCapacity = _size + len;}reserve(NewCapacity);}int j = 0;for (size_t i = _size; i <= _size + len; i++){_str[i] = str[j++];}_size += len;}void string::insert(size_t pos, char ch) {assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}for (int i = _size + 1; i > pos; i--){_str[i] = _str[i - 1];}_str[pos] = ch;_size++;_str[_size] = '\0';}void string::insert(size_t pos, size_t n, char ch){assert(pos <= _size);if (_size + n >= _capacity){int NewCapacity = _capacity == 0 ? 4 : 2 * _capacity;if (NewCapacity < _size + n){NewCapacity = _size + n;}reserve(NewCapacity);}int j = _size;for (size_t i = _size + n; i >= pos + n ; i--){_str[i] = _str[j--];}j = 0;for (size_t i = pos; i <pos + n; i++){_str[i] = ch;}_size += n;}void string::insert(size_t pos, const char* str){assert(pos <= _size);int len = strlen(str);if (_size + len >= _capacity){int NewCapacity = _capacity == 0 ? 4 : 2 * _capacity;if (NewCapacity < _size + len){NewCapacity = _size + len;}reserve(NewCapacity);}int j = _size;for (int i = _size + len ; i >= pos + len; i--){_str[i] = _str[j--];}j = 0;for (int i = pos; i < pos + len; i++){_str[i] = str[j++];}_size += len;}void string::erase(size_t pos, size_t len){assert(pos <= _size);int j = pos;if (len != npos){for (size_t i = pos + len; i <= _size; i++){_str[j++] = _str[i];}_size -= len;}else{_str[pos + 1] = '\0';_size = pos + 1;}}void string::clear(){_size = 0;_str[0] = '\0';}size_t string::find(char c, size_t pos){assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == c){return i;}}return npos;}size_t string::find(const char* str, size_t pos){assert(pos < _size);const char* ptr = strstr(_str + pos, str);if (ptr == nullptr){return npos;}else{return ptr - _str;}}string& string::operator+=(char ch){push_back(ch);return *this;}string& string::operator+=(const char* str){append(str);return *this;}/*string& string::operator = (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& string::operator = (string s){if (this != &s){swap(s);return *this;}}string string::substr(size_t pos, size_t len){assert(pos < _size);if (len > (_size -= pos)){len = _size - pos;	}string sub;sub.reserve(len);for (size_t i = 0; i <= len; i++){sub += _str[pos + i];}return sub;}ostream& operator<<(ostream& os, const string& s){for (size_t i = 0; i < s.size(); i++){os << s[i];}return os;}istream& operator>>(istream& is,  string& s){s.clear(); // 对原来的字符串清理,重新输入char ch;ch = is.get();char buffer[256];int i = 0;while (ch != ' ' && ch != '\n'){buffer[i++] = ch;if (i == 255){buffer[i] = '\0';s += buffer;i = 0;}ch = is.get();}if (i > 0){buffer[i] = '\0';s += buffer;}return is;}istream& getline(istream& is, string& s, char delim){s.clear(); // 对原来的字符串清理,重新输入char ch;ch = is.get();char buffer[256];int i = 0;while ( ch != delim){buffer[i++] = ch;if (i == 255){buffer[i] = '\0';s += buffer;i = 0;}ch = is.get();}if (i > 0){buffer[i] = '\0';s += buffer;}return is;}void string::swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}void swap(string& s1, string& s2){s1.swap(s2);}
}

这就是stirng的底层模拟实现,看完去实现一下吧

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

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

相关文章

计算机网络相关知识小结

计算机网络 1.计算机网络&#xff1a;独立计算机&#xff0c;通信线路连接&#xff0c;实现资源共享 2.组成&#xff1a;资源子网和通信子网 3.拓扑分类 4.范围&#xff1a;LAN, MAN. WAN 5、有线和无线 6.按照方向&#xff1a;单工、双工&#xff0c;全双工 7.传输对象方式&a…

16-CSS3新增选择器

知识目标 掌握属性选择器的使用掌握关系选择器的使用掌握结构化伪类选择器的使用掌握伪元素选择器的使用 如何减少文档内class属性和id属性的定义&#xff0c;使文档变得更加简洁&#xff1f; 可以通过属性选择器、关系选择器、结构化伪类选择器、伪元素选择器。 1. 属性选择…

【弹性计算】异构计算云服务和 AI 加速器(四):FPGA 虚拟化技术

《异构计算云服务和 AI 加速器》系列&#xff0c;共包含以下文章&#xff1a; 异构计算云服务和 AI 加速器&#xff08;一&#xff09;&#xff1a;功能特点异构计算云服务和 AI 加速器&#xff08;二&#xff09;&#xff1a;适用场景异构计算云服务和 AI 加速器&#xff08;…

鸿蒙harmonyOS:笔记 正则表达式

从给出的文本中&#xff0c;按照既定的相关规则&#xff0c;匹配出符合的数据&#xff0c;其中的规则就是正则表达式&#xff0c;使用正则表达式&#xff0c;可以使得我们用简洁的代码就能实现一定复杂的逻辑&#xff0c;比如判断一个邮箱账号是否符合正常的邮箱账号&#xff0…

[首发]烽火HG680-KD-海思MV320芯片-2+8G-安卓9.0-强刷卡刷固件包

烽火HG680-KD-海思MV320芯片-28G-安卓9.0-强刷卡刷固件包 U盘强刷刷机步骤&#xff1a; 1、强刷刷机&#xff0c;用一个usb2.0的8G以下U盘&#xff0c;fat32&#xff0c;2048块单分区格式化&#xff08;强刷对&#xff35;盘非常非常挑剔&#xff0c;usb2.0的4G U盘兼容的多&a…

大模型架构记录12【Agent实例-tool】

运行根目录下几个ipynb文件- Learn-Agent.ipynb- 学习《Custom agent 自定义代理》部分- v1-Create-Custom-Agent.ipynb- v2-Create-Custom-Agent.ipynb- 基于v1&#xff0c;新增一些职位描述&#xff08;JD&#xff09;信息- v3-Create-Custom-Agent.ipynb- 基于v2&#xff0c…

在MCU工程中优化CPU工作效率的几种方法

在嵌入式系统开发中&#xff0c;优化 CPU 工作效率对于提升系统性能、降低功耗、提高实时性至关重要。Keil 作为主流的嵌入式开发工具&#xff0c;提供了多种优化策略&#xff0c;包括 关键字使用、内存管理、字节对齐、算法优化 等。本文将从多个方面介绍如何在 Keil 工程中优…

Java开发者指南:深入理解HotStuff新型共识算法

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、全栈领域优质创作者、高级开发工程师、高级信息系统项目管理师、系统架构师&#xff0c;数学与应用数学专业&#xff0c;10年以上多种混合语言开发经验&#xff0c;从事DICOM医学影像开发领域多年&#xff0c;熟悉DICOM协议及…

opencv图像处理之指纹验证

一、简介 在当今数字化时代&#xff0c;生物识别技术作为一种安全、便捷的身份验证方式&#xff0c;正广泛应用于各个领域。指纹识别作为生物识别技术中的佼佼者&#xff0c;因其独特性和稳定性&#xff0c;成为了众多应用场景的首选。今天&#xff0c;我们就来深入探讨如何利…

【STM32】知识点介绍一:硬件知识

文章目录 一、电源引脚简介二、电平信号三、电路分析 一、电源引脚简介 VCC、GND、VDD和VSS是电子电路中常见的术语&#xff0c;代表着不同的电源引脚或电压。 VCC&#xff08;Voltage at the Common Collector&#xff09;&#xff1a;VCC是指集电极&#xff08;Collector&am…

什么是 SEO(搜索引擎优化)?

您有网站吗&#xff0c;或者您正在考虑创建一个网站&#xff1f;您想吸引更多人加入您的业务吗&#xff1f;如果答案是肯定的&#xff0c;那么毫无疑问&#xff1a;SEO 应该是您营销工作的一部分。这是建立品牌和吸引用户访问您的网站的好方法。但它实际上意味着什么呢&#xf…

鸿蒙HarmonyOS NEXT设备升级应用数据迁移流程

数据迁移是什么 什么是数据迁移&#xff0c;对用户来讲就是本地数据的迁移&#xff0c;终端设备从HarmonyOS 3.1 Release API 9及之前版本&#xff08;单框架&#xff09;迁移到HarmonyOS NEXT&#xff08;双框架&#xff09;后保证本地数据不丢失。例如&#xff0c;我在某APP…

【现代深度学习技术】现代卷积神经网络04:含并行连接的网络(GoogLeNet)

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上&#xff0c;结合当代大数据和大算力的发展而发展出来的。深度学习最重…

【ESP32】ESP32与MQTT通信:实现传感器数据监测与设备控制

ESP32与MQTT通信 1 项目概览2 硬件组成3 MQTT协议解析MQTT协议简介MQTT核心概念本项目中的MQTT应用 4 MQTT Broker选择EMQX Broker其他常用MQTT Broker 5 代码解析初始化与配置MQTT消息处理发布传感器数据 6 MQTT话题TOPIC设计7 EMQX的优势在IoT项目中的体现8 MQTT通信流程9 应…

每天一篇目标检测文献(六)——Part One

今天看的是《Object Detection with Deep Learning: A Review》 目录 一、摘要 1.1 原文 1.2 翻译 二、介绍 2.1 信息区域选择 2.2 特征提取 2.3 分类 三、深度学习的简要回顾 3.1 历史、诞生、衰落和繁荣 3.2 CNN架构和优势 一、摘要 1.1 原文 Due to object dete…

Arthas线上问题诊断器

Arthas是Alibaba开源的java诊断工具 解决问题 这个类从哪个jar 包加载的&#xff1f;为什么会报各种相关的Exception&#xff1f; 遇到问题无法在线上debug&#xff0c;不能直通过加载日志再重新发布 有什么办法可以监控到JVM的实时运行状态&#xff1f; …

[Lc5_dfs+floodfill] 简介 | 图像渲染 | 岛屿数量

目录 0.floodfill算法简介 1.图像渲染 题解 2.岛屿数量 题解 之前我们在 bfs 中有介绍过[Lc15_bfsfloodfill] 图像渲染 | 岛屿数量 | 岛屿的最大面积 | 被围绕的区域&#xff0c;现在我们来看看 dfs 又是如何解决的呢 0.floodfill算法简介 floodfill算法又叫洪水灌溉或者…

JVM类加载器详解

文章目录 1.类与类加载器2.类加载器加载规则3.JVM 中内置的三个重要类加载器为什么 获取到 ClassLoader 为null就是 BootstrapClassLoader 加载的呢&#xff1f; 4.自定义类加载器什么时候需要自定义类加载器代码示例 5.双亲委派模式类与类加载器双亲委派模型双亲委派模型的执行…

【SPP】RFCOMM 层在SPP中互操作性要求深度解析

蓝牙串口协议&#xff08;SPP&#xff09;通过 RFCOMM 协议实现 RS232 串口仿真&#xff0c;其互操作性是设备互联的关键。本文基于蓝牙核心规范&#xff0c;深度解析 RFCOMM 层的能力矩阵、信号处理、流控机制及实战开发&#xff0c;结合状态机、流程图和代码示例&#xff0c;…

Gossip协议:分布式系统中的“八卦”传播艺术

目录 一、 什么是Gossip协议&#xff1f;二、 Gossip协议的应用 &#x1f4a1;三、 Gossip协议消息传播模式详解 &#x1f4da;四、 Gossip协议的优缺点五、 总结&#xff1a; &#x1f31f;我的其他文章也讲解的比较有趣&#x1f601;&#xff0c;如果喜欢博主的讲解方式&…