【C++】vector 模拟实现

news2024/11/29 2:29:27

vector

  • vector 容器
  • vector 基本使用
    • vector 定义
    • 库中各类接口的使用
      • 迭代器
      • 容量相关接口
      • 元素访问相关接口
      • 元素修改相关接口
  • 模拟实现 vector
    • 前期准备
    • 构造与析构
    • 赋值运算符重载
    • 迭代器相关
    • 容量相关
    • 元素访问相关
    • 元素的修改相关
    • 二维数组的创建
    • 对于自定义类型数据的测试

vector 容器

C++ STL 中的 vector 就类似于 C 语言当中的数组,但是 vector 又拥有很多数组没有的接口,使用起来会更加的方便。
相比于 STL 中的 string ,vector 可以定义不同的数据类型

vector 基本使用

vector 定义

template < class T, class Alloc = allocator > class vector;

方式一:创建 vector 对象,不进行初始化

vector (const allocator_type& alloc = allocator_type());

方式二:创建 vector 对象,容量为 n,并赋值为 val

vector (size_type n, const value_type& val = value_type(),
const allocator_type& alloc = allocator_type());

方式三:创建 vector 对象,并采用区间赋值

vector (InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());

方式四:拷贝构造

vector (const vector& x);

代码演示:

    vector<int> v;   //定义一个 int 类型变量
	vector<int> v0{ 1,2,3,4,5,6,7,8,9 };   //定义 int 数组并进行列表赋值
	PrintVector(v0);

	vector<int> v1(10, 5);   //定义一个 int 类型数组,数组内容为 10 个 5
	PrintVector(v1);
	
	int arr[] = { 1,2,3,4,5,6 };      //区间构造
	vector<int> v2(arr, arr + sizeof(arr) / sizeof(arr[0]));
	PrintVector(v2);

	string s("hello");     //采用迭代器构造
	vector<char> v3(s.begin(), s.end());
	PrintVector(v3);

	vector<char> v4(v3);   //拷贝构造
	PrintVector(v4);

定义一个打印函数可以很明显的观察到定义结果:

template<class T>
void PrintVector(const vector<T>& v)
{
	for (auto e : v)
		cout << e << " ";
	cout << endl;
}

在这里插入图片描述

库中各类接口的使用

迭代器

在这里插入图片描述

迭代器的本质是指针,其指针指向如下图:

在这里插入图片描述
begin() 指向空间起始位置,end() 指向最后一个有效元素的下一个位置

在这里插入图片描述

rbegin() 指向最后一个有效元素的下一个位置,rend() 指向空间的起始位置。

代码演示:

在这里插入图片描述

容量相关接口

在这里插入图片描述

代码演示:

(1)测试 size() 、capacity()、以及 resize()

vector<int> v{ 1,2,3,4,5,6 };
	PrintVector(v);
	cout << "v.size() = " << v.size() << endl;
	cout << "v.capacity() = " << v.capacity() << endl;
	cout << "----------------------------------------------------" << endl;
	

	//resize 修改有效元素个数
	v.resize(10, 0);   //将有效元素个数修改为 10,多余空间用 0 来进行填充
	PrintVector(v);
	cout << "v.size() = " << v.size() << endl;
	cout << "v.capacity() = " << v.capacity() << endl;
	cout << "----------------------------------------------------" << endl;

	v.resize(20);
	cout << "v.size() = " << v.size() << endl;
	cout << "v.capacity() = " << v.capacity() << endl;
	cout << "----------------------------------------------------" << endl;

	v.resize(4);        //有效元素个数缩小为 4
	PrintVector(v);
	cout << "v.size() = " << v.size() << endl;
	cout << "v.capacity() = " << v.capacity() << endl;
	cout << "----------------------------------------------------" << endl;

在这里插入图片描述
可以发现:
resize 修改有效元素个数时,size 会进行相应的扩大或缩小变化,capacity 不一定会变化(有效元素增多时,若容量足够则capacity不变,否则会扩容;有效元素减少时,capacity 不变)

(2)测试 reserve

vector<int> v{ 1,2,3,4,5,6 };
	PrintVector(v);
	cout << "v.size() = " << v.size() << endl;
	cout << "v.capacity() = " << v.capacity() << endl;
	cout << "----------------------------------------------------" << endl;

	//reserve 修改容量
	v.reserve(10);
	PrintVector(v);
	cout << "v.size() = " << v.size() << endl;
	cout << "v.capacity() = " << v.capacity() << endl;
	cout << "----------------------------------------------------" << endl;

	v.reserve(30);
	PrintVector(v);
	cout << "v.size() = " << v.size() << endl;
	cout << "v.capacity() = " << v.capacity() << endl;
	cout << "----------------------------------------------------" << endl;

	v.reserve(10);
	PrintVector(v);
	cout << "v.size() = " << v.size() << endl;
	cout << "v.capacity() = " << v.capacity() << endl;
	cout << "----------------------------------------------------" << endl;

在这里插入图片描述

可以发现:
reserve 修改容量时,size 是不会发生变化的(因为有效元素个数不变),若空间容量扩大则 capacity 会相应的进行扩大,若空间容量缩小时 capacity 是不会发生变化的

(3)测试 empty

empty 是进行判空的接口

在这里插入图片描述

元素访问相关接口

在这里插入图片描述

(1)下标运算符访问 operator[]

在这里插入图片描述

越界测试:越界触发 assert 异常

在这里插入图片描述

(2)at 访问

在这里插入图片描述

越界测试:越界抛出 out_of_range 异常

在这里插入图片描述
(3)获取首尾元素 front back

在这里插入图片描述

元素修改相关接口

在这里插入图片描述

(1)尾插 push_back

在这里插入图片描述

(2)尾删 pop_back

在这里插入图片描述

(3)任意位置插入 insert

vector<int> v{ 1,2,3 };
	cout << "v.size() = " << v.size() << endl;
	cout << "v.capacity() = " << v.capacity() << endl;
	cout << "-----------------------------------------" << endl;


	v.insert(v.begin(), 100);  //在起始位置插入 100
	PrintVector(v);
	cout << "v.size() = " << v.size() << endl;
	cout << "v.capacity() = " << v.capacity() << endl;
	cout << "-----------------------------------------" << endl;

	int arr[] = { 0,200,300,400 };
	v.insert(v.begin(), arr, arr + sizeof(arr) / sizeof(arr[0]));    //起始位置插入arr数组中元素
	PrintVector(v);
	cout << "v.size() = " << v.size() << endl;
	cout << "v.capacity() = " << v.capacity() << endl;
	cout << "-----------------------------------------" << endl;


	v.insert(v.end(), 9);   //尾部插入元素 9----------------同理也可以插入数组 arr
	PrintVector(v);
	cout << "v.size() = " << v.size() << endl;
	cout << "v.capacity() = " << v.capacity() << endl;
	cout << "-----------------------------------------" << endl;
	v.insert(v.end(), arr, arr + sizeof(arr) / sizeof(arr[0]));    //尾部插入arr数组中元素
	PrintVector(v);
	cout << "v.size() = " << v.size() << endl;
	cout << "v.capacity() = " << v.capacity() << endl;
	cout << "-----------------------------------------" << endl;

在这里插入图片描述

(4)任意位置删除 erase

在这里插入图片描述

(5)清空 clear

在这里插入图片描述

模拟实现 vector

前期准备

迭代器的本质就是指针,模拟实现 vector 容器,我们需要定义三个指针 :指向起始位置 start,指向最后一个有效元素的下一个位置 finish ,指向容器最后一个位置 endofstorage:

namespace xx {  //自定义命名空间
	template<class T>     //定义模板类型
	class vector{
	public:
		typedef T* iterator;   //迭代器  等价于  T 类型指针
	private:
		iterator start;   //空间起始位置
		iterator finish;  //最后一个有效元素的下一个位置
		iterator endofstorage;  //最后一个容量空间位置
	};
}

在这里插入图片描述

构造与析构

构造函数

(1)默认无参构造

vector() :start(nullptr), finish(nullptr), endofstorage(nullptr)
		{}

(2)构造具有 n 个对象值为 val 的容器 (数据类型为模板类型 T)

vector(int n, const T& val = T())
		{
			start = new T[n];     //创建新空间
			for (size_t i = 0; i < n; ++i) {
				start[i] = val;     //对空间进行赋值操作
			}
			finish = start + n;      //修改 finish 指向---最后一个有效元素的下一个位置
			endofstorage = finish;   //修改容量指针
		}

注意:
第二个参数 val 是一个缺省参数,对于内置类型,T() 的值为 0;对于自定义类型, T() 调用的是该自定义类型的默认构造函数
因此,对于自定义类型一定要有默认的构造函数,否则会报错

(3)使用迭代器进行构造

		template<class Iterator>
		vector(Iterator first, Iterator last)  //区间构造
		{
			auto it = first;
			size_t n = 0;
			while (it != last) {
				++it;
				n++;  //统计区间中元素个数
			}

			start = new T[n];   //开辟空间
			finish = start;
			while (first != last) {    //进行赋值
				*finish = *first;
				++first; ++finish;
			}
			endofstorage = finish;    //修改容量指针
		}

(4)拷贝构造

vector(const vector<T>& v)
		{
			size_t n = v.size();     //记录 v 中元素个数
			start = new T[n];     //创建新空间
			for (size_t i = 0; i < n; ++i)
			{
				start[i] = v[i];      //进行赋值操作
			}
			finish = start + n;    //修改指向
			endofstorage = finish;
		}

新写法(参考上一篇博客深浅拷贝问题)

vector(const vector<T>& v)
		{
			vector<T> tmp(v.begin(),v.end());   //定义临时对象--调用迭代器构造方法
			this->swap(tmp);    //进行资源交换
		}

析构函数

~vector()
		{
			if (start) {
				delete[] start;
				start = finish = endofstorage = nullptr;
			}
		}

测试代码

void MyvectorTest0()
{
	xx::vector<int> v1;
	xx::vector<int> v2(10, 5);   

	int arr[] = { 1,2,3,4,5 };  //区间构造
	xx::vector<int> v3(arr, arr + sizeof(arr) / sizeof(arr[0]));

	xx::vector<int> v4(v2);  //拷贝构造


	//遍历一:
	for (int i = 0; i < v2.size(); ++i) {
		cout << v2[i] << " ";
	}
	cout << endl;
	//遍历二:
	for (auto e : v3)
		cout << e << " ";
	cout << endl;
	//遍历三:
	auto it = v4.begin();
	while (it != v4.end()) {
		cout << *it << " ";
		++it;
	}
	cout << endl;

}

会发现在运行代码时候出现的问题:
在这里插入图片描述

分析:

在构造 v2 时候,会调用区间构造方法,进行参数类型的推演,由于构造 v2 的两个参数都是 int 类型,故编译器会根据类型推演的结果来选择合适的构造方法,又因为构造 n 个值为 val 的构造方法中参数类型为 size_t , int,所以编译器认为类型不匹配,排除该构造方法,选用了迭代器区间的构造方法(参数类型实例化之后都为 int 类型),因此,为了实现构造 n 个值为 val 的空间构造,我们需要对构造函数进行一定的修改,使得其调用更准确:

在这里插入图片描述

赋值运算符重载

vector<T>& operator=(vector<T> v) {  
 //因为参数是传值类型,故在传参过程中会进行一次拷贝构造的调用
			//赋值运算符重载
			this->swap(v);    //直接进行交换(可以参考上一篇博客中深浅拷贝内容)
			return *this;
		}

迭代器相关

//迭代器
		iterator begin()
		{
			return start;
		}
		iterator end()
		{
			return finish;
		}

容量相关

(1)size、capacity、empty 的实现

		size_t size()const {
			return finish - start;
		}
		size_t capacity()const {
			return endofstorage - start;
		}
		bool empty()const {
			return finish == start;
		}

(2)resize :修改有效元素个数

void resize(size_t newsize, const T&val = T())
		{
			size_t oldsize = size();
			if (newsize <= oldsize) { //缩小有效元素
				finish = start + newsize;    //容量不变
			}
			else {//有效元素增大
				//需要扩容
				size_t cap = capacity();
				if(newsize > cap)
					reserve(newsize);

				for (size_t i = oldsize; i < newsize; ++i) {
					//多出来的空间填充
					start[i] = val;
				}
				finish = start + newsize;
				//endofstorage = finish;
			}
		}

(3)reserve:修改容量

void reserve(size_t newcapacity)
		{
			size_t oldcapacity = capacity();
			if (newcapacity > oldcapacity) {
				//开辟新空间
				T* tmp = new T[newcapacity];
				if (start) {
					拷贝元素:memcpy(内存拷贝--------将一段空间中的内容原封不动的拷贝到新空间----浅拷贝) 按字节拷贝
					涉及到资源管理时,memcpy 属于浅拷贝
					//memcpy(tmp, start, sizeof(T)*size());
					
					for (size_t i = 0; i < size(); ++i) {
						tmp[i] = start[i];
					}

					//释放旧空间
					delete[] start;
				}
				size_t sz = size();
				start = tmp;
				finish = start + sz;   //**********
				endofstorage = start + newcapacity;
			}
		}

代码测试:

(1)测试 resize (含 size, capacity 的测试)
在这里插入图片描述
(2)测试 reserve
在这里插入图片描述

元素访问相关

(1)获取首尾元素 front back

T& front()
		{
			return *start;
		}
		const T& front()const
		{
			return *start;
		}
		T& back()
		{
			return *(finish - 1);
		}
		const T& back()const
		{
			return *(finish - 1);
		}

(2)下标访问

T& operator[](size_t index)
		{
			assert(index < size());     //注意区分异常处理方式
			return start[index];
		}
		const T& operator[](size_t index)const
		{
			assert(index < size());
			return start[index];
		}

(3)at 访问

T& at(size_t index)
		{
			if (index >= size())
				throw out_of_range("vector at method: index out_of_range"); //抛出异常
			return start[index];
		}
		const T& at(size_t index)const
		{
			if (index >= size())
				throw out_of_range("vector at method: index out_of_range");
			return start[index];
		}

代码测试:

在这里插入图片描述

元素的修改相关

(1)尾插

void push_back(const T& val)
		{
			//进行尾插,判断容量是否足够
			if (finish == endofstorage) {
				reserve(capacity() * 2 + 3);  //按照2倍进行扩容
			}
			*finish = val;
			++finish;
		}

(2)尾删

void pop_back()
		{
			//进行尾删
			if (empty())
				return;
			--finish;       //直接修改尾指针
		}

(3)任意位置插入

//insert 插入元素的时间复杂度 O(n)
		iterator insert(iterator pos, const T&val)
		{
			//判断插入位置的合法性
			if (pos < begin() || pos > end())
				return end();
			//任意位置进行插入
			if (finish == endofstorage)
				reserve(capacity() * 2); //扩容
			auto it = finish - 1;
			while (it >= pos) {       //元素后移
				*(it + 1) = *it;
				--it;
			}
			*it = val;     //当前 it 指向的就是 pos 的位置
			++finish;
			return it;            //返回新插入的元素的位置
		}

(4)任意位置删除

删除单个元素:

iterator erase(iterator pos)
		{
			//删除任意位置元素
			if (empty())
				return end();
			if (pos < begin() || pos >= end())
				return  end();
			//位置合理
			auto it = pos;
			while (it != end() - 1)  //end() 表示最后一个有效元素的下一个位置
			{
				*it = *(it + 1);      //元素前移
				--it;
			}
			--finish;          //删除元素需要修改尾指针位置
			return pos;
		}

删除区间元素:

iterator erase(iterator start, iterator last)
		{
			if (empty())
				return end();
			if (start < begin() || start >= end())
				return end();
			//位置合法, 删除区间
			auto beg = start;
			auto en = last;

			int n = last - start;    //要删除的元素个数
			while (en != end()){
				*beg = *en;
				++beg; ++en;
				//--finish;
			}
			finish -= n;
			return start;   //返回删除的区间首元素位置
		}

(5)清空

void clear()
		{
			erase(begin(), end());
		}

(6)交换函数

void swap(vector<T>& v)
		{
			std::swap(start, v.start);
			std::swap(finish, v.finish);
			std::swap(endofstorage, v.endofstorage);
		}

测试代码:

(1)测试尾插尾删:

在这里插入图片描述
(2)测试任意位置的插入删除:

在这里插入图片描述

(3)清空:

在这里插入图片描述

二维数组的创建

创建一个五行六列数组,数组中元素值都为 8:

void MyvectorTest3()
{
	xx::vector<xx::vector<int>>  vv(5, xx::vector<int>(6, 8));  
	  //创建有 5 个元素的数组,数组中元素用 vector<int>(6,8) 来进行填充
	for (size_t i = 0; i < vv.size(); ++i)
	{
		for (size_t j = 0; j < vv[i].size(); ++j)
			cout << vv[i][j] << " ";
		cout << endl;
	}
}

在这里插入图片描述

对于自定义类型数据的测试

上述的测试我们都是基于内置类型int数据的测试,发现代码可以正确运行没有报错,那针对于自定义类型数据是否正确呢?

(1)定义一个日期类:

class Date {
public:
	Date(int year = 1990, int month = 1, int day = 20)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{//拷贝构造
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	~Date() {}
private:
	int _year;
	int _month;
	int _day;
};

void MyvectorTest4()
{
	xx::vector<Date> d;      //定义 Date 类型数组
	d.push_back(Date(2023, 1, 1));     //插入元素--------Date 构造函数必须为带缺省值的构造方法
	d.push_back(Date(2023, 1, 2));
	d.push_back(Date(2023, 1, 3));
	d.push_back(Date(2023, 1, 4));
	d.push_back(Date(2023, 1, 5));

	cout << d.size() << endl;
}

运行改代码显式可以正确运行,因为 Date 类不存在资源的处理,那针对于 string 类是否正常?
我们来试试:

(2)定义 string 类:

class String {
public:
	String(const char* str=""):_str(nullptr)
	{
		//构造
		if (nullptr == str)
			 str = "";
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	String(const String& s):_str(new char[strlen(s._str)+1])
	{
		//拷贝构造
		strcpy(_str, s._str);
	}
	String& operator=(const String& s)
	{
		if (this != &s) {
			//不是给自己的赋值
			char* tmp = new char[strlen(s._str) + 1];
			strcpy(tmp, s._str);
			delete[] _str;
			_str = tmp;
		}
		return *this;
	}
	//String& operator=(const String s)
	//{
	//	if (this != &s) {
	//		//新写法
	//		this->swap(s._str);
	//	}
	//	return *this;
	//}
	~String()
	{
		if (_str) {
			delete[] _str;
			_str = nullptr;
		}
	}
private:
	char* _str;
};

void MyvectorTest5()
{
	xx::vector<String> s;
	s.push_back("hello");
	s.push_back("welcom");
	s.push_back("come on");

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

	s.push_back("hahahha");    //此时需要进行扩容发生报错----------memcpy是属于浅拷贝

}

运行发现,在最后一次尾插时发生了错误,我们来看看是什么原因导致的:

因为在第四次尾插时候需要进行扩容,因此产生了错误

在这里插入图片描述

往下运行一步就会发现问题所在了:

在这里插入图片描述

发现,在进行 memcpy 拷贝时候发生了浅拷贝,即将原空间内容原封不动的拷贝到新空间,这就导致了新空间共享旧空间的地址,会造成内存泄漏

因此,在扩容时候我们需要按元素将旧空间中元素交给新空间,而不是将地址空间也赋给新空间

进行修改:

在这里插入图片描述

修改之后程序可以正常运行。

_CrtDumpMemoryLeaks(); //检测内存泄漏

该章节完整代码:

添加链接描述

本篇内容就分享到这里啦!!!

学习编程的道路很长,要注重自我实践与验证,欢迎读者评论探讨~

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

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

相关文章

Python实战之小说下载神器(二)整本小说下载:看小说不用这个程序,我实在替你感到可惜*(小说爱好者必备)

前言 这次的是一个系列内容给大家讲解一下何一步一步实现一个完整的实战项目案例系列之小说下载神器&#xff08;二&#xff09;&#xff08;GUI界面化程序&#xff09; 单章小说下载保存数据——整本小说下载 你有看小说“中毒”的经历嘛&#xff1f;小编多多少少还是爱看小说…

基于react+nodejs+mysql开发用户中心,用于项管理加入的项目的用户认证

基于reactnodejsmysql开发用户中心&#xff0c;用于项管理加入的项目的用户认证用户中心功能介绍页面截图后端采用架构user表projects表project_user表仓库地址用户中心功能介绍 用户中心项目&#xff0c;用于统一管理用户信息、登录、注册、鉴权等 功能如下&#xff1a; 用…

[qiankun]实战问题汇总

[qiankun]实战问题汇总ERROR SyntaxError: Cannot use import statement outside a module问题分析解决方案子应用命名问题问题分析解决方案jsonpFunction详细错误信息问题分析解决方案微应用的注册问题Uncaught Error: application cli5-beta6-test-name died in status LOADI…

2月,真的不要跳槽。

新年已经过去&#xff0c;马上就到金三银四跳槽季了&#xff0c;一些不满现状&#xff0c;被外界的“高薪”“好福利”吸引的人&#xff0c;一般就在这时候毅然决然地跳槽了。 在此展示一套学习笔记 / 面试手册&#xff0c;年后跳槽的朋友可以好好刷一刷&#xff0c;还是挺有必…

Zebec官方辟谣“我们与Protradex没有任何关系”

近日&#xff0c;流支付协议Zebec Protocol在其官方推特上&#xff0c;发表了一个辟谣澄清声明。该条推特推文表示&#xff0c;“Zebec 与 Protradex 没有任何关系或产生关联。他们&#xff08; Protradex &#xff09;声称Zebec 生态正在支持他们&#xff0c;但这是错误的。随…

上海亚商投顾:沪指失守3300点 卫星导航概念全天强势

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。市场情绪指数早间低开后震荡回升&#xff0c;沪指盘中一度翻红&#xff0c;随后又再度走低&#xff0c;创业板指午后跌近1%。…

基于GIS计算降雨侵蚀力R因子

一、数据来源介绍 &#xff08;一&#xff09;行政边界数据 本文所用到的河北唐山行政边界数据来源于中国科学院资源环境科学与数据中心&#xff08;https://www.resdc.cn/Default.aspx&#xff09;。 &#xff08;二&#xff09;降水量数据 本文所用到的降水量数据来源于国家…

【Java基础 下】 025 -- 阶段项目(斗地主)

目录 斗地主 一、斗地主游戏1 -- 准洗发&#xff08;控制台版&#xff09; 1、准备牌 2、洗牌 3、发牌 4、看牌 二、斗地主游戏2 -- 给牌排序①&#xff08;利用序号进行排序&#xff09; 2、洗牌 3、发牌 4、看牌 三、斗地主游戏2 -- 给牌排序②&#xff08;给每一张牌计算价值…

118.Android 简单的分组列表(BaseRecyclerViewAdapterHelper)

//1.第一步 导入依赖库&#xff1a; //RecyclerView implementation com.android.support:recyclerview-v7:28.0.0 //RecyclerAdapter implementation com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.28 //2.第二步 新建SectionActivity页面&#xff1a; //manifest…

【第一章:Spring概述、特点、IOC容器、IOC操作bean管理(基于xml方式)】

第一章&#xff1a;Spring概述、特点、IOC容器、IOC操作bean管理&#xff08;基于xml方式&#xff09; 1.Spring是什么&#xff1f; ①Spring是一款主流的java EE 轻量级开源框架。 ②广义的Spring&#xff1a;Spring技术栈&#xff0c;Spring不再是一个单纯的应用框架&#x…

Centos7+Xshell+Jenkins堆装

windows系统崩坏&#xff0c;重装测试类工具&#xff0c;心情崩了 windows硬盘损坏前&#xff0c;运行应用具慢。。。。。。慢着慢着就走了 从前部署在本地的jenkins&#xff0c;python&#xff0c;gitblit等相关脚本都凉透了&#xff0c;所以这次把服务部署到Centos7上…

数学小课堂:数学的线索(从猜想到定理再到应用的整个过程)

文章目录 引言I 勾股定理1.1 勾三股四弦五1.2 数学和自然科学的三个本质差别1.3 总结引言 从猜想到定理再到应用的整个过程是数学发展和体系构建常常经历的步骤。 I 勾股定理 勾股定理: 直角三角形两条直角边的平方之和等于斜边的平方,这个定理在国外都被称为毕达哥拉斯定理…

空间复杂度(超详解+例题)

全文目录引言空间复杂度例题test1test2&#xff08;冒泡排序&#xff09;test3&#xff08;求阶乘&#xff09;test4&#xff08;斐波那契数列&#xff09;总结引言 在上一篇文章中&#xff0c;我们提到判断一个算法的好坏的标准是时间复杂度与空间复杂度。 时间复杂度的作用…

微服务系统启动,环境从0开始的搭建过程

1. JDK的下载安装&#xff08;傻瓜式&#xff09; 安装过程傻瓜式&#xff0c;直接一步到位。我安装的版本为&#xff1a;jdk-17_windows-x64_bin 2. 集成开发工具的下载安装&#xff1a;IDEA&#xff08;傻瓜式&#xff09; ideaIU-2021.2.1 网上资源很多&#xff0c;自己找…

jsp在线考试系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 jsp 在线考试系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5 开发&#xff0c;数据库为Mysql&#xff0c;使用j…

计算机操作系统和进程

✨个人主页&#xff1a;bit me&#x1f447; ✨当前专栏&#xff1a;Java EE初阶&#x1f447; ✨每日一语&#xff1a;心平能愈三千疾&#xff0c;心静可通万事理。 目 录&#x1f42c;一. 操作系统&#x1f366;1. 操作系统是什么&#xff1f;&#x1f368;2. 操作系统的两个…

Hot 100 | 79. 单词搜索、200. 岛屿数量

LeetCode 79. 单词搜索 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格…

GPT-4——比GPT-3强100倍

GPT-4——比GPT-3强100倍 当前世界上最强大的人工智能系统当属ChatGPT。推出2个月用户数就突破1亿。ChatGPT是当下最炙手可热的话题&#xff0c;科技圈几乎人人都在讨论。这边ChatGPT的热度还在不断攀升&#xff0c;另一边来自《纽约时报》的最新报道称ChatGPT即将被自家超越&…

chatGPT在命令行聊天实现方法

一个简单、轻量级的 shell 脚本&#xff0c;无需安装 python 或 node.js&#xff0c;即可从终端使用 OpenAI 的 chatGPT 和 DALL-E。该脚本将completions端点和text-davinci-003模型用于 chatGPT 以及images/generations用于生成图像的端点。 支持功能 1、从终端与 GPT 聊天 …

某某银行行面试题目汇总--HashMap为什么要扩容

一、HashMap啥时候扩容&#xff0c;为什么扩容&#xff1f; HashMap的默认大小是16。在实际开发过程中&#xff0c;我们需要去存储的数据量往往是大于存储容器的默认大小的。所以&#xff0c;出现容量默认大小不能满足需求时&#xff0c;就需要扩容。而这个扩容的动作是由集合自…