C++ ——string的模拟实现

news2024/12/25 0:42:50

目录

前言

浅记

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)
	{
		//先计算要插入的字符长度,将值赋给临时变量len
		size_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);
	//先计算要插入的字符长度,将值赋给临时变量len
	size_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;
	}
	//构造一个子串sub
		string 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)
		{}*/

		// 短小频繁调用的函数,可以直接定义到类里面,默认是inline
		string(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 = s1
		string& 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)
	{
		//先计算要插入的字符长度,将值赋给临时变量len
		size_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);
		//先计算要插入的字符长度,将值赋给临时变量len
		size_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;
		}
		//构造一个子串sub
			string 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.coloradmin.cn/o/2141358.html

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

相关文章

C++速通LeetCode简单第18题-杨辉三角(全网唯一递归法)

全网唯一递归法&#xff1a; vector<vector<int>> generate(int numRows) {vector<int> v;vector<vector<int>>vn;if (numRows 1){v.push_back(1);vn.push_back(v);v.clear();return vn;//递归记得return}if (numRows 2){v.push_back(1);vn.p…

FPGA与Matlab图像处理之伽马校正

文章目录 一、什么是伽马校正&#xff1f;二、伽马校正的由来三、Matlab实现伽马校正3.1 matlab代码3.2 matlab结果 四、Verilog实现伽马校正4.1 生成初始化ROM文件4.2 Verilog代码4.3 仿真结果 一、什么是伽马校正&#xff1f; Gamma校正是图像处理中用以调整图像的亮度和对比…

代码随想录冲冲冲 Day47 单调栈Part1

739. 每日温度 初步了解单调栈&#xff0c;根本思想就是如果求的是一个元素右边或左边第一个最大的元素 那么就是递增栈&#xff0c;如果是最小的就是递减栈 首先先放入一个0代表 第一个元素的index 之后开始for loop 当后面的值小于等于这个top时 就要先把index放入st中&a…

Leetcode 找到字符串中所有字母异位词

在 C 中&#xff0c;两个 vector<int> 类型的变量进行 操作时&#xff0c;会逐个比较它们的元素&#xff0c;只有当两个向量的长度相同且每个位置上的元素值都相同时&#xff0c; 操作才会返回 true。 因此&#xff0c;在这道题的代码中&#xff0c;sCount pCount 这一…

Flip动画的实现示例demo

Flip动画的实现示例demo 文章说明核心代码效果展示Flip动画工具类的封装 文章说明 文章主要为了学习flip动画的实现思路&#xff0c;并且采用此示例效果来理解该实现思路的含义 参考渡一前端袁老师的讲解视频 核心代码 采用简单的y轴变化的动画效果为示例 <!DOCTYPE html>…

【K230 实战项目】气象时钟

【CanMV K230 AI视觉】 气象时钟 功能描述&#xff1a;说明HMDI资源3.5寸屏幕 使用方法 为了方便小伙伴们理解&#xff0c;请查看视频 B站连接 功能描述&#xff1a; 天气信息获取&#xff1a;通过连接到互联网&#xff0c;实时获取天气数据&#xff0c;包括温度、湿度、天气状…

【STM32】独立看门狗(IWDG)原理详解及编程实践(上)

本篇文章是对STM32单片机“独立看门狗&#xff08;IWDG&#xff09;”的原理进行讲解。希望我的分享对你有所帮助&#xff01; 目录 一、什么是独立看门狗 &#xff08;一&#xff09;简介 &#xff08;二&#xff09;、独立看门狗的原理 &#xff08;三&#xff09;、具体操…

vulkano (rust) 画一个三角形 (vulkan 渲染窗口初始化 (Linux) 下篇)

上文说到, vulkan 相比 OpenGL (ES), 更加贴近底层硬件, 许多东西需要应用软件手动管理, 所以 vulkan 的初始化过程比较麻烦, 或者说学习曲线比较陡峭. 但是, 这种麻烦是一次性的, 一旦学会了, 就能开始享受 vulkan 的诸多好处啦 ~ 本文以绘制一个三角形为例, 介绍 vulkan 的初…

2024最新版,人大赵鑫老师《大语言模型》新书pdf分享

本书主要面向希望系统学习大语言模型技术的读者&#xff0c;将重点突出核心概念与 算法&#xff0c;并且配以示例与代码&#xff08;伪代码&#xff09;帮助读者理解特定算法的实现逻辑。由于大语言模型技术的快速更迭&#xff0c;本书无法覆盖所有相关内容&#xff0c;旨在梳理…

瓶中水位检测系统源码分享

瓶中水位检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

【数据结构】图的概念和存储结构

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《C游记》《进击的C》《Linux迷航》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、图的概念二、图的存储结构2.1 邻接矩阵2.1.1 成员变量与默认成员函数2.1.2 GetIndex2.1.3 AddEdge2.1.4 Pr…

使用 Java 初步搭建简单Spring 项目框架:

一、准备工作 安装 Java Development Kit (JDK)&#xff0c;确保环境变量配置正确。 安装一个集成开发环境&#xff08;IDE&#xff09;&#xff0c;如 IntelliJ IDEA 或 Eclipse。 二、创建项目——具体步骤 在 ider 中创建一个新的 Maven 项目 使用 Maven&#xff1a; 在…

Linux bash脚本本地开发环境(Git Bash)配置

参考资料 VSCode: Windows 下配置 VSCode运行shellVSCodeを使用したシェルスクリプトの開発環境作成 目录 一. 必备VSCode插件二. 插件配置说明2.1 Bash IDE2.2 Code Runner2.3 shell-format 一. 必备VSCode插件 Bash IDE 该插件为 Bash 脚本提供了一些实用的开发工具和功能&…

鸿蒙 ArkUI组件二

ArkUI组件&#xff08;续&#xff09; 文本组件 在HarmonyOS中&#xff0c;Text/Span组件是文本控件中的一个关键部分。Text控件可以用来显示文本内容&#xff0c;而Span只能作为Text组件的子组件显示文本内容。 Text/Span组件的用法非常简单和直观。我们可以通过Text组件来显…

重生归来之挖掘stm32底层知识(1)——寄存器

概念理解 要使用stm32首先要知道什么是引脚和寄存器。 如下图所示&#xff0c;芯片通过这些金属丝与电路板连接&#xff0c;这些金属丝叫做引脚。一般做软件开发是不需要了解芯片是怎么焊的&#xff0c;只要会使用就行。我们平常通过编程来控制这些引脚的输入和输出&#xff0c…

应用软件系统开发实操二:任务需求描述

工信部软件界信息技术服务业2020、2021、2022年度数据&#xff08;目前只有这3年的完整数据&#xff09;&#xff0c;以SQL的格式&#xff0c;存放在实操平台上&#xff0c;通过浏览器下载的方式获取。获取数据后&#xff0c;采用自己选择的技术对数据进行处理。阅读下面的要求…

php语言基本语法

HP&#xff08;Hypertext Preprocessor&#xff09;是一种广泛使用的开源服务器端脚本语言&#xff0c;特别适合于Web开发。 它能够嵌入到HTML中&#xff0c;执行动态网页内容。 PHP的一些基本语法元素&#xff1a; 1. 基本结构 PHP代码通常嵌入到HTML中&#xff0c;以<…

C/C++实现植物大战僵尸(PVZ)(打地鼠版)

&#x1f680;欢迎互三&#x1f449;&#xff1a;程序猿方梓燚 &#x1f48e;&#x1f48e; &#x1f680;关注博主&#xff0c;后期持续更新系列文章 &#x1f680;如果有错误感谢请大家批评指出&#xff0c;及时修改 &#x1f680;感谢大家点赞&#x1f44d;收藏⭐评论✍ 游戏…

Django_Vue3_ElementUI_Release_003_前端Vue3项目初始化

1. 概念扫盲 Node.js是基于ChromeV8引擎&#xff0c;让JS在服务端运行的开发平台&#xff0c;就是JS的一种解释器WebPack就是模块打包机&#xff0c;把浏览器不能直接运行的拓展语言找到并打包为合适的格式给浏览器直接使用Vue基于WebPack构件项目的&#xff0c;并带有合理默认…

MoCo对比损失

MoCo&#xff08;Momentum Contrast&#xff0c;动量对比学习&#xff09;是一种自监督学习方法&#xff0c;由Facebook AI Research提出&#xff0c;主要用于无监督学习视觉表示。在MoCo中&#xff0c;对比损失&#xff08;Contrastive Loss&#xff09;扮演着至关重要的角色&…