C++——vector容器的基本使用和模拟实现

news2024/10/5 14:31:04

1、vector的介绍

  1. vector是表示可变大小数组的序列容器。
  2.  就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素 进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自 动处理。
  3.  本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小 为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是 一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
  4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
  5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增 长。
  6. 与其它动态序列容器相比(deques, lists and forward_lists), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起lists和 forward_lists统一的迭代器和引用更好。

注意:string与vector类似,但也有不同之处。string是存放字符的动态数组,vector是存放一个T类型的动态数组,本质都是一个顺序表。并且我们使用vector时需要加头文件#include<vector>

 2、vector的常用接口

构造函数

void test_vector1()
{
	vector<int> v1;
	vector<int> v2(10, 8);//开十个空间都赋值8
	vector<int> v3(++v2.begin(), --v2.end());//用自身的迭代器区间构造
	vector<int> v4(v3);//拷贝构造

	string s("hello world");
	vector<char> v5(s.begin(), s.end());//用string的迭代器区间构造
}

尾插和尾删

vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	v.pop_back();
	v.pop_back();
	v.pop_back();
	v.pop_back();

由于头删和头插效率太低了,vector并没有提供相应的接口。

遍历和[]访问

vector可支持[]下标访问,并且可以改变vector中的值,至于遍历,我们可以用下标遍历,也可以使用范围for来遍历。

//遍历
	for (size_t i = 0; i < v.size(); i++)
	{
		v[i] += 1;//可修改
		cout << v[i] << " ";
	}
	cout << endl;

	//
	vector<int>::iterator it = v.begin();
	//迭代器 it指向vector的第一个数据
	while (it != v.end())
	{
		*it -= 1;
		cout << *it << " ";
		it++;
	}
	cout << endl;
	//范围for 本质也是迭代器
	for (auto e : v)
		//把v中的每个数据遍历的时候给给e
	{
		cout << e << " ";
	}
	cout << endl;

	//int a[] = { 1,2,3 };
	原生指针就是天然的迭代器,数组支持范围for,会被替换指针
	//for (int* p = a; p < a + sizeof(a) / sizeof(int); p++)
	//{}

reserve和resize的使用

    v.reserve(100);   //扩容并只改变capacity空间
	v.resize(100);    //扩容不仅改变capacity空间并且改变size
	v.resize(100, 5); //扩容+初始化 或 删除数据(类比string)
	v.resize(2);      //截取数据但不改变capacity

find和assign的使用

vector<int>::iterator ret = find(v.begin(), v.end(), 3);
	//auto ret = find(v.begin(), v.end(), 3);
	//如果没找到find返回第二个参数
    //如果找到了返回该数下标
    vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	v.assign(10, 5);//给v的前十个值上全部赋值为5,并且会覆盖原来的值

clear、capacity、size、max_size的使用


	cout <<"max_size:"<< v.max_size() << endl;//数据所能存放的最大容量
	cout <<"capacity:"<< v.capacity() << endl;//当前容量
	cout <<"size:"<< v.size() << endl;//当前数据个数

	v.clear();//只清理size的值不改变capacity
	cout << "-------------------";
	cout << "max_size:" << v.max_size() << endl;
	cout << "capacity:" << v.capacity() << endl;
	cout << "size:" << v.size() << endl;

insert、erase的使用

    vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	//v.assign(10, 5);
	//覆盖之前已有的值

	vector<int>::iterator ret = find(v.begin(), v.end(), 3);
	//auto ret = find(v.begin(), v.end(), 3);
	//如果没找到find返回第二个参数
	if (ret != v.end())
	{
		cout << "找到了" << endl;
		v.insert(ret, 30);
		//v.erase(ret);
		//不能在这删,因为ret失效了
		//这个迭代器失效问题,我们后面会细讲
	}
	v.insert(v.begin(), 30);//在v.begin()的前面插入30也就是头插
	vector<int>::iterator pos = find(v.begin(), v.end(), 300);
	if (pos != v.end())
		//找不到的时候就会返回v.end
		//因此找不到的时候不会进入
	{
		v.erase(pos);//删除pos下标的值
		
	}

增容方式

int main()
{
	size_t sz;
	std::vector<int> foo;
	sz = foo.capacity();
	std::cout << "making foo trow;\n";
	for (int i = 0; i < 100; i++)
	{
		foo.push_back(i);
		if (sz != foo.capacity())
		{
			sz = foo.capacity();
			std::cout << "capacity changed:" << sz << '\n';
		}
	}
}

 由上图可知vs下vector是以大约1.5增容的。而Linux下g++是以2倍增容的。

vector相关OJ题

1、只出现一次的数

力扣

class Solution {
public:
    int singleNumber(vector<int>& nums) 
    {
        int value=0;
        for(auto e : nums)
        {
            value^=e;//将nums中的值全部互相异或,这样的话相同的数据刚好抵消
        }
        return value;//返回剩下的那个与其他值不相等的数据

    }
};

2、杨辉三角形

力扣

杨辉三角形
class Solution {
public:
	vector<vector<int>> generate(int numRows)
	{
		vector<vector<int>> vv;
		vv.resize(numRows);//先给外层vector开内存
		for (size_t i = 0; i < numRows; i++)
		{
			vv[i].resize(i + 1);//给每一个小vector开内存
			vv[i][0] = vv[i][vv[i].size() - 1] = 1;//小vector中的头尾设为1
		}
		for (size_t i = 0; i < vv.size(); i++)
		{
			for (size_t j = 0; j < vv[i].size(); j++)
			{
				if (vv[i][j] == 0)
				{
					vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
				}
			}
		}
		return vv;
	}
};

3、电话号码的字母组合(重点题,代码中有详细注释)

//回溯力扣题:《电话号码的字母组合》
class Solution {
	string arr[10] = { "","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz" };
	//将0-9(其中0和1不给值)中的每个数字映射一个字符串
public:
	//最关键的一个函数体,会反复使用
	void _letterCombinations(const string& digits, size_t i,
		string combinStr, vector<string>& strV)
		//传入digits的引用并且加const为了防止改变digits并且减少拷贝,digits就是我们传入的字符串
		//传入i为了遍历digits中的每个字符串,因为digits字符串的每个字符还代表这一个字符串:例如2->"abc"
		//combinStr是为了去存放每次递归后的字符串组合
		//strV为了存放所有情况遍历完全之后的字符串总和
	{
		if (i == digits.size())
			//由于i是从0开始的,倘若此时i已经与digits的长度相等那么说明i已经越界了也代表digits的字符串已经遍历完全了
		{
			strV.push_back(combinStr);
			//将我们组合好的combinStr尾插到strV中,strV也就是最终我们需要返回的那个字符串
			return;//立即返回,只要执行该语句,该函数将不再执行接下来的语句,因为此时就需要返回
		}
		string str = arr[digits[i] - '0'];
		//定义一个新的字符串str并且让str中存入我们需要遍历的字符串
		//digits[i]是访问到我们输入字符串中的某个字符
		//digits-'0'为了得到arr的下标   使其得到digits字符串中每个字符中的字符串
		//最后让它赋值给str我们就可以遍历str将其进行组合
		for (size_t j = 0; j < str.size(); j++)//遍历str进行组合,并且继续递归调用_letterCombination函数
		{
			_letterCombinations(digits, i + 1, combinStr + str[j], strV);
			//传入digits   为了继续访问它的字符中的字符串
			//传入i+1  为了访问digits中的下一个字符中的字符串 并且这样的话i不会发生改变 以便下次可以直接继续使用i+1
			//传入 combinStr+str[j]  为了将我们得到的str中的字符尾插到combinStr中存放起来,等遍历结束可以尾插到strV中
			//传入 strV   如果遍历结束可直接把combinStr中的值直接传入strV中
		}
	}
	vector<string> letterCombinations(string digits)
		//digits是我们所选择的字符串
	{
		string combinStr;//定义一个combinStr字符串
		vector<string> strV;//定义一个vector容器里面的值是string值
		if (digits.empty())//为了考虑我们的digits为空的情况下
			return strV;//若为空 直接返回

		//开始递归调用此函数
		_letterCombinations(digits, 0, combinStr, strV);

		return strV;//递归调用完成后返回
	}
};

图解:

 

3、vector的模拟实现

vector的成员变量

private:
	iterator _start; // 指向数据块的开始
	iterator _finish; // 指向有效数据的尾
	iterator _endofStorage; // 指向存储容量的尾

构造函数

默认构造

vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{}

迭代器构造

//一个类模板的成员函数,又可以是一个函数模板
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
			:_start(nullptr)
			,_finish(nullptr)
			,_endofstorage(nullptr)
		{
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}

拷贝构造

//v2(v1)
		//现代写法
		vector(const vector<T>& v)
		{
			vector<T> tmp(v.begin(),v.end());
            
            //没有模拟swap之前可用下列写法
			/*swap(_start, tmp._start);
			swap(_finish, tmp._finish);
			swap(_endofstorage, tmp._endofstorage);*/

			//this->swap(tmp);
			swap(tmp);
		}
v2(v1)传统写法
		//vector(const vector<T>& v)
		//	//拷贝构造(深拷贝)
		//{
		//	_start = new T[v.capacity()];
		//	_finish = _start + v.size();
		//	_endofstorage = _start + v.capacity();

		//  memcpy是浅拷贝
		//	memcpy(_start, v._start, v.size() * sizeof(T));
		//}

这里传统写法不是很推荐,因为会用到memcpy,因为memcpy会用到浅拷贝。

析构函数

~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _endofstorage = nullptr;
			}
		}

赋值运算符重载函数

//v1=v2
		//现代写法
		vector<T>& operator=(vector<T> v)
		{

            //未模拟swap时用下列方法
			/*swap(_start, v._start);
			swap(_finish, v._finish);
			swap(_endofstorage, v._endofstorage);*/


			swap(v);

			return *this;
		}

迭代器

public:
		typedef T* iterator;
		typedef const T* const_iterator;

begin()和end()


		const_iterator begin() const
		{
			return _start;
		}
		const_iterator end() const
		{
			return _finish;
		}
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}

容量函数

size()和capacity()


		size_t size() const
		{
			return _finish - _start;
		}
		size_t capacity() const
		{
			return _endofstorage - _start;
		}

reserve

void reserve(size_t n)
		{
			if (n > capacity())
			{
				//扩容
				size_t sz = size();
				T* tmp = new T[n];
				if (_start)
				{
					//memcpy是浅拷贝
					//memcpy(tmp, _start, sizeof(T) * size());
					for (size_t i = 0; i < sz; i++)
					{
						//T 是int,一个一个拷贝没问题
						//T 是string,一个一个拷贝调用是T的深拷贝复制,也没问题
						tmp[i] = _start[i];
					}
					delete[] _start;
				}
				_start = tmp;
				_finish = _start + sz;
				/*_finish = tmp + size();
				_start = tmp;*/
				_endofstorage = _start + n;

			}
		}

resize


		void resize(size_t n, const T& val = T())
		{
			if (n < size())
			{
				_finish = _start + n;
			}
			else
			{
				if (n > capacity())
				{
					reserve(n);
				}
				while (_finish != _start + n)
				{
					*_finish = val;
					_finish++;
				}
			}
		}

empty

bool empty()const
{
	return _start == _finish;
}

增删查改

push_back

void push_back(const T& x)
		{
			if (_finish == _endofstorage)
			{
				扩容
				//size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
				size_t sz = size();
				//T* tmp = new T[newCapacity];
				//if (_start)
				//{
				//	memcpy(tmp, _start, sizeof(T) * size());
				//	delete[] _start;
				//}
				_start = tmp;
				_finish = _start + sz;
				//_finish = tmp + size();
				//_start = tmp;
				//_endofstorage = _start + newCapacity;

				reserve(capacity() == 0 ? 4 : capacity() * 2);
			} 
			*_finish = x;
			_finish++;
		}

pop_back

void pop_back()
		{
			assert(_finish > _start);//检查是否为空

			_finish--;
		}

insert

iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start);
			assert(pos <= _finish);
			//满了就扩容
			if (_finish == _endofstorage)
			{
				//扩容
				//扩容会导致pos失效,扩容需要更新一下pos
				size_t len = pos - _start;//计算一下扩容前pos与_start直接的距离以便以计算新pos
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;//得到新pos的位置
			}

			//移动数据
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				end--;
			}
			*pos = x;
			_finish++;

			return pos;
		}

earse


		iterator erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos <= _finish);

			iterator begin = pos + 1;
			while (begin < _finish)
			{
				*(begin - 1) = *begin;
				begin++;
			}
			_finish--;
			return pos;
		}

swap

void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endofstorage, v._endofstorage);
		}

下标访问

T& operator[](size_t i)
		{
			assert(i < size());
			return _start[i];
		}

完整代码

#pragma once

namespace mwb
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		
		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{}

		v2(v1)传统写法
		//vector(const vector<T>& v)
		//	//拷贝构造(深拷贝)
		//{
		//	_start = new T[v.capacity()];
		//	_finish = _start + v.size();
		//	_endofstorage = _start + v.capacity();

		//  memcpy是浅拷贝
		//	memcpy(_start, v._start, v.size() * sizeof(T));
		//}
		
		//一个类模板的成员函数,又可以是一个函数模板
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
			:_start(nullptr)
			,_finish(nullptr)
			,_endofstorage(nullptr)
		{
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}
		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endofstorage, v._endofstorage);
		}
		//v2(v1)
		//现代写法
		vector(const vector<T>& v)
		{
			vector<T> tmp(v.begin(),v.end());
			/*swap(_start, tmp._start);
			swap(_finish, tmp._finish);
			swap(_endofstorage, tmp._endofstorage);*/
			//this->swap(tmp);
			swap(tmp);
		}
		//v1=v2
		//现代写法
		vector<T>& operator=(vector<T> v)
		{
			/*swap(_start, v._start);
			swap(_finish, v._finish);
			swap(_endofstorage, v._endofstorage);*/
			swap(v);

			return *this;
		}
		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _endofstorage = nullptr;
			}
		}
		const_iterator begin() const
		{
			return _start;
		}
		const_iterator end() const
		{
			return _finish;
		}
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		T& operator[](size_t i)
		{
			assert(i < size());
			return _start[i];
		}
		size_t size() const
		{
			return _finish - _start;
		}
		size_t capacity() const
		{
			return _endofstorage - _start;
		}

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				//扩容
				size_t sz = size();
				T* tmp = new T[n];
				if (_start)
				{
					//memcpy是浅拷贝
					//memcpy(tmp, _start, sizeof(T) * size());
					for (size_t i = 0; i < sz; i++)
					{
						//T 是int,一个一个拷贝没问题
						//T 是string,一个一个拷贝调用是T的深拷贝复制,也没问题
						tmp[i] = _start[i];
					}
					delete[] _start;
				}
				_start = tmp;
				_finish = _start + sz;
				/*_finish = tmp + size();
				_start = tmp;*/
				_endofstorage = _start + n;

			}
		}
		void resize(size_t n, const T& val = T())
		{
			if (n < size())
			{
				_finish = _start + n;
			}
			else
			{
				if (n > capacity())
				{
					reserve(n);
				}
				while (_finish != _start + n)
				{
					*_finish = val;
					_finish++;
				}
			}
		}
		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start);
			assert(pos <= _finish);
			//满了就扩容
			if (_finish == _endofstorage)
			{
				//扩容
				//扩容会导致pos失效,扩容需要更新一下pos
				size_t len = pos - _start;//计算一下扩容前pos与_start直接的距离以便以计算新pos
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;//得到新pos的位置
			}

			//移动数据
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				end--;
			}
			*pos = x;
			_finish++;

			return pos;
		}
		iterator erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos <= _finish);

			iterator begin = pos + 1;
			while (begin < _finish)
			{
				*(begin - 1) = *begin;
				begin++;
			}
			_finish--;
			return pos;
		}
		void push_back(const T& x)
		{
			if (_finish == _endofstorage)
			{
				扩容
				//size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
				size_t sz = size();
				//T* tmp = new T[newCapacity];
				//if (_start)
				//{
				//	memcpy(tmp, _start, sizeof(T) * size());
				//	delete[] _start;
				//}
				_start = tmp;
				_finish = _start + sz;
				//_finish = tmp + size();
				//_start = tmp;
				//_endofstorage = _start + newCapacity;

				reserve(capacity() == 0 ? 4 : capacity() * 2);
			} 
			*_finish = x;
			_finish++;
		}
		void pop_back()
		{
			assert(_finish > _start);//检查是否为空

			_finish--;
		}
	private:
		iterator _start;
		iterator _finish;
		iterator _endofstorage;
	};
}

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

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

相关文章

【动手学深度学习PyTorch版】18 使用块的网络 VGG

上一篇请移步【动手学深度学习PyTorch版】17 深度卷积神经网络 AlexNet_水w的博客-CSDN博客 目录 一、使用块的网络 VGG 1.1 AlexNet--->VGG ◼ VGG网络简介 1.2 VGG架构 1.3 总结 二、VGG网络的代码实现 2.1 VGG网络&#xff08;使用自定义&#xff09; 一、使用块的…

软件测试基本概念

目录本章要点什么是软件测试?软件测试的特定?软件测试和开发的区别?软件测试和软件开发中的调试有什么区别?软件测试在不同公司的定位?一个优秀的测试人员应该具备的素质(你为啥要选择测试开发)需求是衡量软件测试的依据从软件测试人员角度看需求为啥需求对软件测试人员如…

SpringBoot 面试题总结 (JavaGuide)

SpringBoot 面试题总结 &#xff08;JavaGuide&#xff09; 用 JavaGuide 复习 SpringBoot 时&#xff0c;找到一些面试题&#xff0c;没有答案&#xff0c;自己花了一天时间在网上找资料总结了一些&#xff0c;有些答案的来源比较杂忘了没有标注&#xff0c;望见谅。 1. 简单…

Visual Studio 2022开发Arduino详述

目录&#xff1a; 一、概述 二、软件的下载与安装 1、前言 2、Visual Studio 2022的下载与安装 3、Visual Micro扩展插件的导入 4、Visual Micro的使用 1&#xff09;安装修改插件 2&#xff09;搜索 : Visual.Micro.Processing.Sketch.dll 3&#xff09;打开Visual.…

【Linux学习】基础IO

目录前言一、C语言文件IO1. C语言文件接口以及打开方式2. 对当前路径的理解3. 默认打开的三个流二、 系统文件IO1. 系统接口openwritereadclose系统接口和库函数2. 文件描述符及其分配规则文件描述符文件描述符分配原则3. 重定向及dup2系统调用重定向标准输出和标准错误的区别d…

Linux XWindow的安装和配置

1.开始安装XWindow必须需要的组件 输入指令&#xff1a;yum groupinstall "X Window System" yum groupinstall "X Window System" 选择y继续安装。 当看到complete表示已经安装成功了。 输入startx测试一下 看到如上界面就证明你的XWindow安装成功了。 2…

Python数据分析(3):pandas

文章目录二. pandas入门2.1 数据结构2.1.1 Series对象2.1.2 DataFrame对象2.2 读取数据2.2.1 读取Excel&#xff1a;read_excel()1. 读取特定工作簿&#xff1a;sheet_name2. 指定列标签&#xff1a;header3. 指定行标签&#xff1a;index_col4. 读取指定列&#xff1a;usecols…

TypeScript接口——interface

目录 一、接口概述&#xff1a; 二、接口类型介绍&#xff1a; 1、属性接口&#xff1a; 2、 函数接口&#xff1a; 3、可索引接口&#xff1a; &#xff08;1&#xff09;可索引接口约束数组示例&#xff1a; &#xff08;2&#xff09; 可索引接口约束对象示例&#xf…

【Python】numpy矩阵运算大全

文章目录前言0 遇事不决&#xff0c;先查官网&#xff0c;查着查着就查熟了1 矩阵运算及其必要性2 矩阵的创建2.1 普通矩阵2.2 特殊矩阵3 矩阵的索引3.1 str, list, tupple的索引3.2 numpy索引4 矩阵的运算4.1 通用函数与广播机制4.3 矩阵乘法4.4 矩阵求逆4.5 矩阵转置4.6 向量…

SpringBoot整合mybatis-plus 实现增删改查和分页查询

SpringBoot整合mybatis-plus 实现增删改查和分页查询整体的运行图片&#xff1a;一、环境搭建&#xff1a;1、依赖2、application.yml文件3、数据库二、实体类&#xff1a;三、数据层开发——基础CRUD四、业务层开发——分页功能制作4.1分页配置类 configuration4.2service接口…

【Node.js】模块化学习

Node.js教学 专栏 从头开始学习 目录 模块化的基本概念 什么是模块化 现实中的模块化 编程领域中的模块化 模块化规范 Node.js中的模块化 Node.js中模块的分类 加载模块 Node.js中的模块作用域 什么是模块作用域 模块作用域好处 向外共享模块作用域中的成员 module对象 modu…

第二站:分支与循环(终幕)一些经典的题目

目录 一、计算n的阶乘 1.一般解法 2.优化不能表示出较大数的阶乘 二、 计算 1!2!3!……10! 1.循环嵌套解法 2.一次循环解法(优化计算时间) 三、在一个有序数组中查找具体的某个数字n 1.遍历查找 2.二分查找算法&#xff08;优化了查找时间&#xff09; 四、编写代码&am…

IDEA Out of memory 问题

文章目录1. 前提2. 问题记录与解决方案1. 前提 阅读本文之前&#xff0c;读者要首先把 Out of memory 这个问题的解决方案多搜几个帖子&#xff0c;先按照其他帖子的解决方案&#xff08;修改配置文件Xmx属性等&#xff09;尝试一遍&#xff0c;不能解决再参考本文。 本文所描…

前端小游戏——植物大战僵尸

给大家分享一个植物大战僵尸网页游戏源代码&#xff0c;感兴趣的小伙伴可收藏学习 &#x1f449;完整源码 文章目录⌛️效果展示⌛️游戏介绍⌛️游戏内容&#xff08;1&#xff09;冒险模式&#xff08;2&#xff09;小游戏⌛️图片资源⌛️代码展示&#xff08;1&#xff09;…

【黑猩猩算法】基于加权反对技术和贪婪搜索进化黑猩猩优化算法求解多模态工程问题附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

终于拿到了阿里P8架构师分享的JCF和JUC源码分析与实现笔记java岗

时代的一粒尘&#xff0c;落在每个人身上&#xff0c;就是一座山”。 时代更迭变换&#xff0c;我们好像都知道今天与昨天不同&#xff0c;又好像肉眼看不出哪里不同。 但其实它就正在以各种各样的方式体现在每一个普通人身上。 疫情爆发三个月的时间&#xff0c;截止2020年…

~外中断~

目录 一、接口芯片和端口 二、外中断信息 三、PC机键盘的处理过程 一、接口芯片和端口 外设的输出不直接送入内存和CPU&#xff0c;而是送入相关的接口芯片的端口中&#xff1b;CPU向外设的输出也不是直接送入外设&#xff0c;而是先送入端口&#xff0c;再由相关的芯片送到…

C语言程序设计--火车订票系统

任务要求: 创建一个火车票管理系统&#xff0c;功能包括&#xff1a; &#xff08;1&#xff09;录入班次信息(信息用文件保存),可不定时地增加班次数据 &#xff08;2&#xff09;浏览班次信息,可显示出所有班次当前状总(如果当前系统时间超过了某班 次的发车时间,则…

js中map()的使用详解

引入&#xff1a; 有网友有如下困惑&#xff1a; map是数组的方法&#xff0c;有一个参数&#xff0c;参数是一个函数&#xff0c;函数中有3个参数 参数1&#xff1a;item必须。当前元素的值 参数2&#xff1a;index&#xff0c;可选。当前元素在数组中的索引值 参数3&#xff…

CentOS 7迁移Anolis OS 7 ——筑梦之路

迁移注意事项 Anolis OS 7生态上和依赖管理上保持跟CentOS7.x兼容&#xff0c;一键式迁移脚本centos2anolis.py&#xff0c;实现CentOS7.x到Anolis OS 7的平滑迁移。 使用迁移脚本前需要注意如下事项&#xff1a; 迁移涉及到软件包的重新安装&#xff0c;是不可逆过程&#…