【c++】——STL容器之vector的使用和模拟实现

2023-10-27

目录

1.vector的概述

2.vector常用接口

2.1 构造函数

2.2 迭代器的使用:

2.3 修改的接口

push_back

pop_back

insert

erase

 find

reverse

 2.4 关于容量接口

resize

reverse 

2.5 数据的访问

3 vector的迭代器

迭代器失效的问题

4. vector的模拟实现

4.1reserve接口的实现

 4.2 resize

4.3 insert

 4.4 push_back

4.5 erase

 4.6 pop_back

4.7 构造函数


1.vector的概述

vector本质是数据结构中的线性表,它是动态空间的数组,如果vector中的空间满了以后,它会先开辟一块更大的新空间,然后将旧空间的数据拷贝给新空间,再把旧空间的给释放掉。vector开辟的新空间的容量一般是旧空间的容量的两倍或者1.5倍,不同的编译器增容方式可能是不同的。例如再g++中vector是以两倍增长的,vs中vector是以1.5倍增长的。

vector可以储存任意类型的数据,包括自定义类型,当定义vector的时候,需要指明vector存储的数据是什么类型的,定义格式:

 vector<类型> 名字;

	std::vector<int> v1;//v1是存储int类型的数据
	std::vector<string> v2;//v2存储的是string类型的数据
	std::vector<char> v3;//v3是存储char类型的数据

2.vector常用接口

vector的接口有很多,在这里我就不一 一讲解,我只讲一些我们经常会用到的接口,如果遇到哪个接口不懂的话,自己可以去查一下文档:vector - C++ Reference

2.1 构造函数

vector 无参的构造函数
vector size_type n, const value_type& val = value_type()
构造并初始n个val
vector (const vector& x);
拷贝构造
vector (InputIterator fifirst, InputIterator last);
利用迭代器进行初始化构造
	std::vector<int> v1;//无参的构造函数
	std::vector<int> v2(10, 2);//构造并初始化10个2
	std::vector<int> v3(v2.begin(), v2.end());//利用v2的迭代器初始化v3
	vector<int> v4(v2);//拷贝构造

2.2 迭代器的使用:

  正向迭代器:begin+end  返回的的类型是iterator/const_iterator

  反向迭代器:rbegin+rend 返回的类型是reverse_iterator/const_reverse_iterator

 利用迭代器遍历vector v1,v1中包含元素有 1 ,2 ,3,4,5

void test(vector<int> v)
{
	vector<int>::iterator it = v.begin();
	cout << "正向迭代器遍历:";
	while (it != v.end())//正向迭代器遍历
	{
		cout << *it << ' ';
		it++;
	}
	cout << endl;

	vector<int>::reverse_iterator rt = v.rbegin();
	cout << "反向迭代器遍历:";
	while (rt != v.rend())//反向迭代器遍历
	{
		cout << *rt << ' ';
		rt++;
	}	
	cout << endl;
}

输出:

正向迭代器遍历:1 2 3 4 5

反向迭代器遍历:5 4 3 2 1

2.3 修改的接口

                  push_back         在末尾插入数据
                  pop_back         删除末尾的数据
                   insert           在position之前插入val
                  erase         删除position位置的数据
                  find           查找的某个数据的位置
               operator[ ]             像数组一样去访问vector
              swap           与另一个vector进行交换
            reverse         将vector中的数据进行逆置

push_back

void push_back (const value_type& val);

push_back接口的参数只有一个,它可以在vector的末尾插上一个数据。

pop_back

void pop_back();

pop_back接口没有参数,它直接删除vector末尾的一个数据。

insert

insert有3种传参的方式。

方式一:

 iterator insert (iterator position, const value_type& val);

在position之前插入一个val。position是迭代器类型

方式二

void insert (iterator position, size_type n, const value_type& val);

在position之前插入n个val。positon是迭代器类型

方式三

template <class InputIterator>

void insert (iterator position, InputIterator first, InputIterator last);

position 和first,last都是迭代器类型。

将一个vector的[first,last)区间的数据插入到另一个相同类型的vector的position位置之前。

 pisition不会随着数据的移动而移动。

erase

erase有两种传参的方式:

iterator erase (iterator position);

方式一:删除position位置的数据、

iterator erase (iterator first, iterator last);

方式二:删除迭代器区间 [ first , lasr ) 中的元素。

 find

template <class InputIterator, class T>

InputIterator find (InputIterator first, InputIterator last, const T& val);

在[ first , last )区间查找val,找到了就返回相应的迭代器,找不到就返回last。

find不是vector中的中的接口,是算法中的函数,只要有迭代器都可以通过find进行查找

reverse

template <class BidirectionalIterator>

void reverse (BidirectionalIterator first, BidirectionalIterator last);

传vector的迭代区间,将vector的迭代区间中的元素进行逆置,例如:将一个vector中1 2 3 4 5 进行逆置就成 5 4 3 2 1

	std::vector<int> v1;//无参的构造函数
    v1.push_back(1);//尾插
	v1.push_back(2);//尾插
	v1.push_back(3);//尾插
	v1.push_back(4);//尾插
	v1.push_back(5);//尾插

	//查找3的位置,并将返回的迭代器存储在pos
	vector<int>::iterator pos = find(v1.begin(), v1.end(), 3);
	v1.insert(pos, 30);//在pos位置之前插入30
	reverse(v1.begin(), v1.end());//逆置vector
	//查找3的位置,并将返回的迭代器存储在it
	vector<int>::iterator it = find(v1.begin(), v1.end(), 4);
	v1.erase(it);//删除it位置的数据

        

 2.4 关于容量接口

             size                        获取数据个数
         capacity                 获取容量的大小
          empty              判断vector是否为空
          reserve             改变vector的capacity
           resize

            改变vector的size

resize


void resize (size_type n, value_type val = value_type());

使size到n个,如果不足本身的size不足n,则用val补齐vector到n个数据。如果本身的size大于n,则不需要进行任何操作。

reverse 

void reserve (size_type n);

使vector有n个容量空间,如果原本的capacity大于n,则不会缩容。

	std::vector<int> v;
	cout << v.capacity() << endl;//输出0
	cout << v.size() << endl;//输出0
	v.reserve(10);//预留10个capacity的空间大小
	cout << v.capacity() << endl;//输出10
	cout << v.size() << endl;//输出0
	v.resize(20,10);//预留20个数据
	cout << v.capacity() << endl;// 输出20
	cout << v.size() << endl;//输出20

2.5 数据的访问

operator[ ] 可以像数组下标去访问vector中的元素
front 返回vector中的第一个数据
back 返沪vector中最后一个数据

3 vector的迭代器

vector是一个连续的空间,它的迭代器就是原生指针,因为vector中的原生指针可以满足迭代器 operator*,operator[ ],operator++,operator--,operator+=,operator-=的操作,所以vector的迭代器就只需要给原生指针起个别名就够了。如下:

  template<class T>
    class vector
    {
    public:
        typedef T* iterator; //vector的迭代器就是原生指针
        typedef const T* const_iterator;

      ...

}

迭代器失效的问题

在我们用vector中,经常会碰到迭代器失效的问题,那么什么是迭代器失效呢?

我们先来看一段代码,如下:

void test2()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(10);
	v.push_back(4);
    vector<int>::iterator pos = find(v.begin(), v.end(), 2);
	v.insert(pos,10);
	v.insert(pos, 20);
}

这段代码在vs运行下会奔溃掉,为什么呢?

 

 当我们删除掉2后,pos指向的位置的值就变为10,那么我们pos的意义也就改变了,此时的pos就迭代器就已经失效了,当我们再去使用它的时候,vs编译器就检查出来。

那么我再来看一下下面这个场景:

上面pos已经是野指针,因为旧空间被释放掉所以不知道它指向的是什么值。所以该指针旧已经失效了。

所以迭代器失效有两种方式:

一种是使用insert,erase使迭代器指向的数值发生改变,此时的迭代器就失去意义。这种有

些编译器会检查例如vs,有些编译器不会检查,例如g++

另一种是插入数据的时候,容量满的时候会开辟新空间,旧空间被释放,导致pos指向的数据

不知道是什么,此时的pos成了野指针,这个任何编译器都会报错。

4. vector的模拟实现

namespace sjp
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator; //vector的迭代器是可以修改的
		typedef const T* const_iterator;

        iterator begin()//返回vector迭代区间的头
		{
			return _first;
		}
		iterator end()//返回vector的迭代区间的尾
		{
			return _end;
		}

		const_iterator begin()const
		{
			return _first;
		}

		const_iterator end()const
		{
			return _end;
		}

		size_t size()const//返回vector的数据个数
		{
			return _end - _first;
		}

		size_t capacity()const//返回vector的容量
		{
			return _end_of_storage - _first;
		}

        bool empty()const//判断vector是否为空
		{
			return _first == _end;
		}

		const T& operator[](size_t i)const
		{
			return *(_first + i);
		}

		T& operator[](size_t i)
		{
			return *(_first + i);
		}

		void clear()//清空vector
		{
			_end = _first;
		}


		const T& back()const//返回vector最后一个元素
		{
			return *(back - 1);
		}


		const T& front()const//返回vector第一个元素
		{
			return *(front);
		}


	private:
		iterator _first;//表示目前使用空间的头
		iterator _end;//表示目前使用空间的尾
		iterator _end_of_storage;//表示目前可用空间的尾
	};

在上面接口中,我们发现

1.有些接口在后面需要加上const,例如 empty ,size, capacity这些接口,因为调用这些接口的时候不会修改它的成员变量,所以我们加上const可以防止它的成员变量被修改,并且可以让const对象和非const对象都可以调用这些接口(注意非const对象是可以调用const的接口,但const对象不能调用非const的接口

2.有些接口需要实现const和非const的版本,例如begin ,end,operator[]这些接口,

非const对象调用非const的接口,返回的对象是可读可写的,const对象调用的是const的接口

返回的对象是只能读。例如,const对象返回的也是const的迭代器,就是不能通过迭代器去修改它指向的值。

4.1reserve接口的实现

     void reserve(size_t n)
		{
			size_t sz = size();//先保存原本的size
			if (capacity() < n)
			{
				T* tmp = new T[n];//重新开一块空间
				if (_first)//如果_first不为空指针
				{
					for (int i = 0; i < size(); i++)//将原空间的值拷贝给新空间
					{
						tmp[i] = _first[i];
					}
					delete[] _first;//释放旧空间
				}
				//让迭代器指向新空间
				_first = tmp;
				_end = _first + sz;
				_end_of_storage = _first + n;
			}
		}

这里有一个问题,上面的原空间的值拷贝给新空间中的:

                    for (int i = 0; i < size(); i++)
                    {
                        tmp[i] = _first[i];
                    }

可不可用memcpy(tmp, _first, sz*sizeof(T));来替代

memcpy进行的浅拷贝,当vector存储的像string开辟动态空间的之类就会出错

 

 也就是说memcpy只能拷贝string中的指针,没有将拷贝string的存储字符串的空间,当旧空间的中的存储的指针被释放掉后,同时指针指向的子符串也会被释放掉。

那这段代码为什么可以呢?

   for (int i = 0; i < size(); i++)
   {
              tmp[i] = _first[i];                
   }

 4.2 resize

		void resize(size_t n,T val=T())
		{
			if (n > size())
			{
				if (n > capacity())//如果预留数据个数大于容量则需要增容
				{
					reserve(n);
				}
				size_t sz = n - size();//将数据补齐到n个
				for (int i = 0; i < sz; i++)
				{
					push_back(val);
				}
			}
		}

 如果n大于size的时候就插入val,再进行判断,如果数据大于capacity的时候就需要进行增容,最后将val值补齐使vector的数据个数为n个。

4.3 insert

 		void insert(iterator pos,const T& x)
		{
			assert(pos >= _first && pos <= _end);
			if (_end == _end_of_storage)//判断容量是否满了
			{
				size_t lenth = pos - _first;//如果换新空间,需要保留pos在vector的位置
				int newcapacity = capacity() == 0 ? 5 : capacity() * 2;
				reserve(newcapacity);//预留新空间
				pos =_first+lenth;//跟新pos
			}
			//将x插入到pos位置的前面
			iterator cur = end();
			while (cur != pos)
			{
				*(cur) = *(cur-1);
				cur--;
			}
			*pos = x;	
			_end += 1;//数据个数再加一
		}

 

上面提到了insert迭代器会失效的问题,那么我们可不可以对insert适当修改一下使我们使用insert

不会发生迭代器失效的问题?

只需要在上面的代码的基础,在pos迭代器加上引用&,然后插入数据后,pos加1,这样插入数据后,pos就可以一直指向原本那个数据。

 4.4 push_back

		void push_back(const T& x)//尾插,直接在最后一个位置插入数据即可
		{
			insert(_end, x);
			//if (_end == _end_of_storage)
			//{
			//	int newcapacity = capacity() == 0 ? 5 : capacity() * 2;
			//	reserve(newcapacity);
			//}
			//*_end = x;
			//++_end;
		}

4.5 erase

		iterator erase(iterator pos)
		{
			assert(pos < _end);	
			iterator cur = pos;//将pos位置后的所有数据向前挪一步
			while (cur != _end - 1)
			{
				*cur = *(cur + 1);	
				cur++;
			}
			_end--;//数据个数再减一
			return pos;
		}

 4.6 pop_back

		void pop_back()
		{
			--_end;
		}

4.7 构造函数

		vector(size_t n, T val)//构造n个val值的vector
		{
			reserve(n);//先预留n个数据的空间
			for (int i = 0; i < n; i++)//再将val存满这块空间
			{
				push_back(val);
			}
		}
      
            
         //_first,_end,_end_of_strage赋值为空指针是因为
         //capacity是通过_end_of_storage和_first进行计算的
		vector()//无参的拷贝构造
		 :_first(nullptr),_end(nullptr),_end_of_storage(nullptr)
		{

		}

        vector(iterator first, iterator end)//利用迭代器区间构造vector
			:_first(nullptr), _end(nullptr), _end_of_storage(nullptr)
		{
			while (first != end)
			{
				push_back(*first);
				first++;
			}
		}

        //v2(v1);
		vector(const vector<T>& v)//拷贝构造函数
			:_first(nullptr),_end(nullptr),_end_of_storage(nullptr)
		{
			reserve(v.capacity());//预留v1相同的空间
			for ( auto e: v)//然后将v1中的数据一个一个的推进v2
			{
				push_back(e);
			}
		}

        //v2=v1
		vector<T>& operator=(const vector<T>& v)//赋值构造函数
		{
			vector<T> tmp(v);
			swap(_first, tmp._first);//不能用用=赋值进行赋值,tmp出函数作业域或被析构掉。
			swap(_end, tmp._end);
			swap(_end_of_storage, tmp._end_of_storage);
			return *this;
		}

v1=v2,将v1赋值给v2,需要将v1的空间大小和值跟v2是一模一样的,在赋值过程中,先拷贝构造一个跟v1一模一样的tmp,然后将tmp和v2中_first,_end, _end_of_storage交换过去,出函数作用域的时候,tmp会被析构函数给释放掉。此时v1的空间大小和值跟v2是一模一样的。

总结:在上面中的push_back,pop_back,insert,erase,clear等接口中在后面不需要加上const,因为const对象本身不能被修改的,const的vector中的数据个数和数据都不能被改变,所以说const对象不能调用这些接口。

好了,今天的知识就分享到这里,喜欢的小伙伴们可以给博主点个赞 ,或者点个关注,大家一起努力学习,共同进步。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【c++】——STL容器之vector的使用和模拟实现 的相关文章

  • 组合框下拉位置

    我有一个最大化的表单 其中包含 500px 的组合框控件 停靠在右上角 Width 尝试打开组合框后 列表的一半超出了屏幕 如何强制列表显示在表单中 棘手的问题 我找不到解决这个问题的好办法 只是一个解决方法 添加一个新类并粘贴如下所示的代
  • 无法加载程序集问题

    我收到以下错误 无法加载程序集 错误详细信息 System BadImageFormatException 无法加载文件或程序集 文件 或其依赖项之一 该程序集是由比当前加载的运行时更新的运行时构建的 无法加载 该程序集是使用 Net Fr
  • 在Python中确定句子中2个单词之间的邻近度

    我需要确定 Python 句子中两个单词之间的接近度 例如 在下面的句子中 the foo and the bar is foo bar 我想确定单词之间的距离foo and bar 确定之间出现的单词数foo and bar 请注意 该词
  • django 中的“管理器”是什么?

    我已经阅读了Django官方中的定义文档 https docs djangoproject com en dev topics db managers 我仍然对什么感到困惑Manager does 文档说它们允许您操作数据库表 模型 但我仍
  • 如何自定义 Google 测试失败消息?

    我编写了一个如下所示的 Google 测试 它将一些计算值与 CSV 文件中预期存储的值进行比较 class SampleTest public testing Test public void setupFile const std st
  • C# 枚举到字符串自动转换?

    是否可以让编译器自动将我的 Enum 值转换为字符串 这样我就可以避免每次都显式调用 ToString 方法 这是我想做的一个例子 enum Rank A B C Rank myRank Rank A string myString Ran
  • 处理“未找到细胞”。 Excel 中的错误

    我正在使用 Excel VSTO 应用程序并使用以下代码在工作表中查找错误单元格 Excel Range rngTemp Excel Range rngErrorRange Excel Worksheet Sheet1 Excel Work
  • 如何让 Python 找到 ffprobe?

    I have ffmpeg and ffprobe安装在我的 mac macOS Sierra 上 并且我已将它们的路径添加到 PATH 中 我可以从终端运行它们 我正在尝试使用ffprobe使用以下代码获取视频文件的宽度和高度 impor
  • 使用 plone.api 创建文件的 Python 脚本在设置文件时出现错误 WrongType

    Dears 我正在创建一个脚本python来在Plone站点中批量上传文件 安装是UnifiedInstaller Plone 4 3 10 该脚本读取了一个txt 并且该txt以分号分隔 在新创建的项目中设置文件时出现错误 下面是脚本 f
  • 与 GNU Make 等 Python 相关的并行任务并发

    我正在寻找一种方法或者可能是一种哲学方法来如何在 python 中执行类似 GNU Make 的操作 目前 我们使用 makefile 来执行处理 因为 makefile 非常擅长通过更改单个选项 j x 进行并行运行 此外 gnu mak
  • 我可以将 UseCSharpNullComparisonBehavior 用于单个查询吗?

    我有一个查询 该查询曾经是存储过程 现已转换为 EF 查询 现在已经超时了 使用 SQL Profiler 我可以看到生成的 SQL 的唯一区别是 EF 转变的新行为entity Property value into entity Pro
  • 如何使用 Ajax 在 Flask 中发布按钮值而不刷新页面?

    我有一个问题 当我单击 Flask 应用程序中的按钮时 我想避免重新加载 我知道有 Ajax 解决方案 但我想知道如何将我的按钮链接到 ajax 函数以发布按钮值并运行链接到其值的 python 函数 这是我的 html 按钮 div di
  • 配置:错误:无法运行C编译的程序

    我正在尝试使用 Debian Wheezy 操作系统在我的 Raspberry Pi 上安装不同的软件 当我运行尝试配置软件时 我尝试安装我得到此输出 checking for C compiler default output file
  • 为什么 tesseract 无法从这个简单的图像中读取文本?

    我在 pytesseract 上阅读了大量的帖子 但我无法让它从一个简单的图像中读取文本 它返回一个空字符串 这是图像 我尝试过缩放它 灰度化它 调整对比度 阈值 模糊 以及其他帖子中所说的一切 但我的问题是我不知道 OCR 想要更好地工作
  • 用户的完整 UNIX 用户名

    想知道您是否知道是否有一种巧妙的方法可以从 shell 获取完整的用户名 示例 如果我的 UNIX 用户名是 froyo 那么我想获取我的全名 在本例中 如系统中注册的那样 froyo Abhishek Pratap Finger 命令可以
  • Type.GetInterfaces() 仅适用于声明的接口

    首先 像这样的问题有很多 也许有些OP甚至在问同样的问题 问题是这些问题的答案 无论是否接受 都没有真正回答这个问题 至少我找不到 如何确定类直接声明的接口 而不是由父级或声明的接口继承的接口 e g interface I interfa
  • 连接到没有元数据的网络服务

    我想连接到此网络服务 https training api temando com schema 2009 06 server wsdl https training api temando com schema 2009 06 serve
  • Matplotlib 渲染日期、图像的问题

    我在使用 conda forge 的 Matplotlib v 3 1 3 和 python 3 7 时遇到问题 我拥有 Matplotlib 所需的所有依赖项 当我输入这段代码时 它应该可以工作 我得到了泼溅艺术 它基于此 YouTube
  • 卸载程序

    我正在尝试使用此代码卸载程序 但它似乎不起作用 我尝试过其他答案 但似乎也不起作用 有人可以帮助我吗 我正在尝试按给定名称 displayName 卸载该程序 例如 我给出 displayName Appname 那么此代码应该从我的计算机
  • 将一个 IEnumerable 拆分为多个 IEnumerable

    我是 linq 新手 我需要根据指示器将 Couple string text bool Indicator 类型的 IEnumerable 拆分为多个 IEnumerable 我尝试使用skipWhile 和 TakeWhile 但没有找

随机推荐

  • Type-C协议简介(CC检测原理)

    1 简介 越来越多的手机开始采用Type C作为充电和通信端口 Type C连接器实物和PIN定义如下图 目录 1 简介 Type C连接器中有两个管脚CC1和CC2 他们用于识别连接器的插入方向 以及不同的插入设备 本文介绍CC的基本识别
  • Bootrom概述

    1 Bootrom 是指on chip bootrom 在CPU芯片内部 内嵌有小的boot程序 bootloader 类似于PC机主板上的BIOS的存储区域 2 Bootloader怎么得到 如果对开发板有些改动 还能使用开发板的boot
  • solidity学习过程---msg

    solidity 5 0 remix测试 个人学习 欢迎指正 msg 研究了好一会 感觉还是有点困惑 msg sender 当前合约的调用者 1 部署合约的地址 2 调用该合约的地址 msg value 随消息发送的 wei 的数量 其实并
  • 【Spark NLP】第 15 章:聊天机器人

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • sonarQube详细安装

    目录 安装前提 将zip包scp到服务器 解压sonar的zip包 修改配置 创建用户sonar 将sonar目录授权给sonar用户 执行命令 查看日志 遇到的问题 今天学习了一下sonar 想看看代码质量检查工具的使用 安装前提 需要j
  • python笔记9--socket初步使用

    python笔记9 socket初步使用 1 介绍 2 源码案例 2 1 tcp c s 案例 2 2 udp c s 案例 3 说明 最近需要写个c s小应用 因此看了下socket编程 把学习的笔记贴在此处以便于后续查阅 1 介绍 本文
  • Mysql服务的安装

    本文适用于新手 小白 而且专业术语不到位 本文内容可能无法解决教程外其他问题 望多包涵 多图警告 此教程适用于windows系统 教程流程 安装时 1 下载安装包 这个是下载链接 MySQLhttps www mysql com 打开界面后
  • ubuntu连接mysql命令_远程服务器 ubuntu 安装 mysql 及连接使用

    远程服务器 ubuntu 安装 mysql 及连接使用 MySQL是最流行的开源关系数据库管理系统 它速度快 容易使用 容易扩展 并且流行的LAMP和LEMP的一部分 这篇指南讲解了如何在 Ubuntu 20 04上安装和保护 MySQL
  • SQL 取数值小数后两位,但不四舍五入。

    例 1 67789 结果要显示为 1 67 select round 1 67789 2 1 1 67 语法 ROUND numeric expression length function 参数 numeric expression 精确
  • k8s滚动更新

    1 编写一个yaml文件 vi deployment nginx yaml apiVersion apps v1 kind Deployment metadata labels app nginx name nginx namespace
  • 22.MongoDB删除操作效率及相关问题验证

    最近遇到一个了一个MongoDB数据删除的问题 需要一次性删除上线即1 5年前 1年前的数据且之后每天清空一年过期的数据 在数据量比较大的情况下何种方式的删除效率最高是一个值得研究的问题 本文通过实际测试找出其中规律 本文采用腾讯云mong
  • PCL实现点云选取并计算选取点法向量及可视化

    1 背景及效果展示 因项目需求 基于PCL1 8 1 VS2015 实现点云特征点选取并计算选取的特点法向量 并对特征点选取过程可视化 法向量计算结果可视化 特此记录该小功能实现 随机选取几个特征点 计算选取特征点法线并可视化 2 实现步骤
  • 使用burp suite软件后开启代理后不能上网

    这篇一定要记录一下 不然忘记了太恶心了 转载网址 https blog csdn net weixin 45571987 article details 110411138
  • Shell万能工具箱脚本

    文章目录 说明 说明 使用步骤 万能工具箱 脚本结构 万能工具箱 执行效果 说明 说明 持续更新 整合业务中常用的脚本并分类触发 所有功能均基于运维企业实战Shell脚本合集 使用步骤 1 shell tools sh存放到 root sc
  • pidstat 命令详解

    pidstat 概述 pidstat是sysstat工具的一个命令 用于监控全部或指定进程的cpu 内存 线程 设备IO等系统资源的占用情况 pidstat首次运行时显示自系统启动开始的各项统计信息 之后运行pidstat将显示自上次运行该
  • python 绘制分组对比柱状图

    首先放效果图 coding utf 8 import numpy as np import tensorflow as tf from matplotlib path import Path from matplotlib patches
  • 算法notes

    算法notes1 一 位运算 本文重点讲解前移位 前三个 位运算规则 十进制 gt 二进制 符号位 正数为0 负数为1 1 无符号右移 符号位不变 低位溢出 高位用符号位 第一位都是0 无论正负 填充 没有无符号左移 2 左移 lt lt
  • MyEclipse中生成Hibernate实体类及映射文件的方法

    下午 想还有一个工程项目要做 是采用三大框架SSH完成的 以下是简单的Hibernate实体类及映射文件的方法 在MyEclipse工作区右上角选择进入MyEclipse Database Explorer透视图 在DB Browser视图
  • Axios三层封装

    Axios三层封装 在实际项目中axios都是要经过封装再使用的 企业级项目一般都是三层封装 1 工具函数层 对axios工具进行增强 如 设置公共的请求服务器 设置请求拦截器 设置响应拦截器 创建一个文件夹utils 用来放axios 创
  • 【c++】——STL容器之vector的使用和模拟实现

    目录 1 vector的概述 2 vector常用接口 2 1 构造函数 2 2 迭代器的使用 2 3 修改的接口 push back pop back insert erase find reverse 2 4 关于容量接口 resize