【C++笔记】vector使用详解及模拟实现

前言

各位读者朋友们,大家好!上期我们讲了string类的模拟实现,这期我们开启vector的讲解。

一.vector的介绍及使用

1.1 vector的介绍

vector的文档
使用STL的三个境界:能用、明理、能扩展,下面学习vector,我们也按照这个境界去学习。

1.2 vector的使用

我们在学vector的时候,一定要看文档:vector的文档vector在实际中非常重要,在实际中我们熟悉常用的接口即可,下面给出了常用的需要掌握的接口。

1.2.1vector的定义

在这里插入图片描述
vector是可以改变大小的数组序列容器,也就是数据结构的顺序表。

constructor构造函数声明接口说明
vector()重点无参构造
vector (size_type n, const value_type& val = value_type())构造并初始化n个val
vector(const vector& x);重点拷贝构造
vector(InputIterator first,InputIterator last);使用迭代器进行初始化构造
  • 无参构造
    在这里插入图片描述
  • 构造并初始化n个val
    在这里插入图片描述
  • 迭代器区间构造
    在这里插入图片描述

1.2.2 vector iterator的使用

iterator的使用接口说明
begin + end (重点)获取第一个数据位置的iterator/const_iterator,获取最后一个数据的下一个位置的iterator/const_iterator
rbegin + rend获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的reverse_iterator

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

在这里插入图片描述

  • 反向迭代器
    在这里插入图片描述

1.2.3 vector空间增长的问题

容器空间接口说明
size获取数据个数
capacity获取容量大小
empty判断是否为空
resize(重点)改变vector的size
reserve(重点)改变vector的capacity

capacity
在这里插入图片描述

// 测试vector的默认扩容机制
void TestVectorExpand()
{size_t sz;vector<int> v;sz = v.capacity();cout << "making v grow:\n";for (int i = 0; i < 100; ++i) {v.push_back(i);if (sz != v.capacity()) {sz = v.capacity();cout << "capacity changed: " << sz << '\n';}}
}

在这里插入图片描述
可以看出在VS环境下,编译器是1.5倍扩容的,而在g++环境中是2倍扩容的。

resize
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果在resize时,我们没有给初值,会使用默认构造给的值。

  • reserve
    在这里插入图片描述
    在n>capacity时,会扩容,但是在n<capacity时,vector的reserve在任何环境中都不会缩容。但是string在这种情况下,g++环境中会进行缩容。
int main()
{vector<int> v(10, 520);v.reserve(20);cout << v.size() << endl;cout << v.capacity() << endl;v.reserve(15);cout << v.size() << endl;cout << v.capacity() << endl;v.reserve(5);cout << v.size() << endl;cout << v.capacity() << endl;return 0;
}

在这里插入图片描述
g++环境:
在这里插入图片描述

1.2.4 vector的增删查改

vector的增删查改接口说明
push_back尾插
pop_back尾删
find查找(这个是算法模块实现,不是vector的成员接口)
insert在pos位置之前插入的数据
erase删除pos位置的数据
swap交换两个vector的数据空间
operator[]像数组一样访问
  • push_back在这里插入图片描述
int main()
{vector<int> v(1, 520);v.push_back(1314);return 0;
}

在这里插入图片描述

  • pop_back
    在这里插入图片描述
int main()
{vector<int> v(1, 520);v.pop_back();return 0;
}

在这里插入图片描述

  • find
    在这里插入图片描述
    find函数找出第一个和val相等的元素,并返回这个元素的迭代器,如果没有找到就返回last(最后一个元素下一个位置的迭代器)。
int main()
{ vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(520);v.push_back(1314);v.push_back(3);v.push_back(7);vector<int>::iterator it = find(v.begin(), v.end(), 520);cout << *it << endl;it = find(v.begin(), v.end(), 10);if (it == v.end()){cout << "没找到,返回最后一个元素下一个位置的迭代器" << endl;}return 0;
}

在这里插入图片描述

  • insert
    在这里插入图片描述
    这里的插入都是使用的迭代器
    iterator insert (iterator position, const value_type& val)
int main()
{vector<int> v(5, 520);v.insert(v.begin() + 3, 1314);for (auto a : v){cout << a << ' ';}cout<<endl;return 0;
}

在第三个位置之前插入1314
在这里插入图片描述
void insert (iterator position, size_type n, const value_type& val)

int main()
{vector<int> v(5, 520);v.insert(v.begin() + 3, 2,1314);for (auto a : v){cout << a << ' ';}cout << endl;return 0;
}

在这里插入图片描述
void insert (iterator position, InputIterator first, InputIterator last)

int main() 
{vector<int> v1(5, 520);vector<int> v2(5, 1314);v1.insert(v1.begin() + 3, v2.begin() + 3, v2.end());// [begin,end)for (auto a : v1){cout << a << " ";}cout << endl;return 0;
}

在第三个位置之前插入迭代器区间,左闭右开
在这里插入图片描述

在这里插入图片描述

  • erase
    在这里插入图片描述
    erase (iterator position)
int main()
{vector<int> v1(5, 520);v1.push_back(1314);for (auto a : v1){cout << a << " ";}cout << endl;v1.erase(v1.end() - 1);for (auto a : v1){cout << a << " ";}cout << endl;return 0;
}

删除最后一个位置的元素
在这里插入图片描述
erase (iterator first, iterator last)
在这里插入图片描述
依旧是左闭右开区间

int main()
{ vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(520);v.push_back(1314);v.push_back(3);v.push_back(7);v.erase(v.begin() + 1, v.end() - 1);for (auto a : v){cout << a << " ";}return 0;
}

在这里插入图片描述

  • swap
    在这里插入图片描述
int main() {vector<int> v1(2, 520);vector<int> v2(4, 1314);cout << "交换前:" << endl;for (auto a : v1) {cout << a << " ";}cout << endl;for (auto a : v2) {cout << a << " ";}cout << endl;v1.swap(v2);cout << "交换前:" << endl;for (auto a : v1) {cout << a << " ";}cout << endl;for (auto a : v2) {cout << a << " ";}cout << endl;return 0;
}

在这里插入图片描述

  • operator[]
    在这里插入图片描述
int main()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(520);v.push_back(1314);v.push_back(3);v.push_back(7);for (int i = 0; i < v.size(); ++i){cout << v[i] << " ";}cout << endl;return 0;
}

在这里插入图片描述

  • 流提取和流插入
    vector是不支持流插入和流提取重载的
vector<int> v;
//流提取单个数据
int x;
cin >> x;
v.push_back(x);
// 多组数据
vector<int>v1(3, 0);
for (int i = 0; i < 3; ++i)
{cin >> v1[i];
}
// 流插入
for (auto a : v1)
{cout << v1[i] << " ";
}

1.3 vector类型存储

在这里插入图片描述
vcector可以看作顺序表,它不仅可以存储内置类型,也可以存储自定义类型。

1.3.1 vector< string >

int main()
{vector<string> v;string s("5201314");v.push_back(s);v.push_back("1314520");for (auto a : v){cout << a << " ";}cout << endl;return 0;
}

但是这样在范围for遍历打印的时候会进行string类的拷贝给a,这样效率会很低,所以我们可以使用引用,不修改数据的情况下加上const。
在这里插入图片描述

1.3.2 vector<vector< int >>

vector<vector< int >>可以看成是二维数组,下面通过vector的结构看一下:
vector可以看成是顺序表:
在这里插入图片描述
在这里插入图片描述
其实编译器这里实例化出了两个模板,一个是vector<vector< int >> ,一个是vector< int >。
在这里插入图片描述
所以我们在遍历二维数组的时候实际上是调用了两次operator[]
在这里插入图片描述
第一次调用返回vector<vector< int >>& ,第二次调用返回int&,也就是第一次调用找到存在整个vector的对应位置的vector,第二次调用返回对应位置的vector的相应位置的元素。
在这里插入图片描述
上面理解了之后我们看一道OJ题杨辉三角
在这里插入图片描述

class Solution {
public:vector<vector<int>> generate(int numRows) {vector<vector<int>> vv(numRows);// 这里未传实参,// 使用缺省值vector<int>for (int i = 0; i < numRows; ++i){vv[i].resize(i + 1, 1); //将所有值都初始化为1}for (int i = 2; i < numRows; ++i)// 从下标为2的那一行开始{for (int j = 1; j < vv[i].size() - 1; ++j)// 不计算第一个和最后一个数据// vv[i].size 是当前一行的数据个数{vv[i][j] = vv[i - 1][j - 1] + vv[i - 1][j];}}return vv;}
};

二. vector深度剖析及模拟实现

在这里插入图片描述
通过vector的源码,我们看到,vector的底层实际有3个成员变量,它们分别对应

startbegin(顺序表的头)
finishend(顺序表最后一个元素的下一个位置)
end_of_storagecapacity(顺序表的空间)

在这里插入图片描述
下面开始模拟实现vector:
vector的底层

namespace Yuey
{template <class T>class vector{public:typedef T* iterator;private:iterator _start;iterator _finish;iterator _end_of_storage;};
}

2.1 push_back

template <class T>
class vector
{
public:typedef T* iterator;size_t size(){return _finish - _start;// [_statr, _finish) 左闭右开相减得元素个数}size_t capacity(){return _end_of_storage - _start;// [_statr, _end_of_storage) 左闭右开相减得元素个数}void reserve(size_t n){if (n > capacity()){// 开空间拷贝T* tmp = new T[n];memcpy(tmp, _start, size() * sizeof(T));delete[] _start;_start = tmp;_finish = _start + size();_end_of_storage = _start + n;}}T& operator[](size_t n){assert(n < size());return _start[n];}void push_back(const T& x){if (size() == capacity()){reserve(capacity() == 0 ? 4 : 2 * capacity());}*_finish = x;++_finish;}
private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;
};

为了实现push_back这一功能,我们实现了size()、capacity()、reserve()函数,为了方便测试又实现了[]的重载。下面测试一下push_back这一接口:
在这里插入图片描述
发现挂了,调试看一下
在这里插入图片描述

void reserve(size_t n)
{if (n > capacity()){// 开空间拷贝size_t old_size = size(); //记录扩容前的sizeT* tmp = new T[n];memcpy(tmp, _start, size() * sizeof(T));delete[] _start;_start = tmp;_finish = _start + old_size;_end_of_storage = _start + n;}
}

2.2 迭代器

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

在这里插入图片描述

2.3 vector的打印

void print_vector(const vector<int>& v)
{vector<int>::const_iterator  it = v.begin();while (it != v.end()){cout << *it << " ";++it;}
}

这样写只能打印vector< int >类型的,没法打印存储其它类型的vector,但是打印的逻辑是一样的,因此我们还可以再套一层模板给打印函数:

	template <class T>void print_vector(const vector<T>& v){typename vector<T>::const_iterator it = v.begin();// auto it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;}

在这里插入图片描述

2.4 pop_back

bool empty()
{return _start == _finish;
}
void pop_back() 
{assert(!empty());// 尾删但不能为空--_finish;
}

在这里插入图片描述

2.5 迭代器失效

1. 在指定位置插入一个数据

在这里插入图片描述
在这里插入数据的时候没有进行扩容,程序可以正常运行,但是如果我们进行扩容,程序还能正常运行吗?
在这里插入图片描述
程序不能正常运行,这就涉及到了迭代器失效的问题
在这里插入图片描述
调试发现pos是大于end的,while循环不能执行
在这里插入图片描述

void insert(iterator pos, const T& val)
{// 扩容if (size() == capacity()){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;
}

在这里插入图片描述
改进之后就解决了这个问题。

void test_vector6()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);int x;cin >> x;vector<int>::iterator p = find(v.begin(), v.end(), x);if (p != v.end()){v.insert(p, 520);(*p) *= 10;}print_vector(v);
}

2. insert之后的迭代器失效

想要通过find函数找一个数值,并在这个数据的位置插入520,然后让pos位置的值乘10
在这里插入图片描述
在这里插入图片描述

发现并没有实现需求,这是因为pos还是指向原空间的位置,没有指向扩容后的空间,虽然我们上面处理了这种情况,但是是对形参进行的修改,实参是不会改变的。那形参使用引用可不可以解决这个问题呢?答案是可以的,但是在这里插入图片描述
这种情况就是不适用了,返回值存在一个const临时对象中,调用会存在权限放大的问题,那将普通引用改为const引用不就好了?改为const引用之后pos的值就不能更改了。
在这里插入图片描述
库中的insert函数返回了新插入元素的迭代器,我们想修改可以对返回值进行操作后再修改。
改进的insert函数:

	iterator insert(iterator pos, const T& val){assert(pos >= _start && pos <= _finish);// 扩容if (size() == capacity()){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;return pos;}

将我们的insert函数也加上返回值之后再去实现想要的功能:
在这里插入图片描述
实现了。
上面这种情况也是迭代器失效的一种,对于使用完insert之后的迭代器就失效了,不要直接进行访问,如果需要访问就去更新迭代器的值!!!
在这里插入图片描述
vs下进行了强制的检查,使用insert之后的迭代器会报错,不管有没有扩容。

3. erase时迭代器失效

删除指定位置的元素:挪动数据从前往后挪动

void erase(iterator pos)
{assert(pos >= _start && pos < _finish);iterator it = pos + 1;while (it < _finish){*(it - 1) = *it;++it;}--_finish;
}

这里我们写一个程序测试一下,要求删除偶数:

void test_vector8()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);print_Container(v);auto it = v.begin();while (it != v.end()){if (*it % 2 == 0){v.erase(it);}++it;}print_Container(v);
}

在这里插入图片描述
三种情况两种不正确,我们分析一下:

  • 对于第二种
    在这里插入图片描述
  • 第三种情况:
    在这里插入图片描述
    来看一下库中的erase是怎么实现的
    在这里插入图片描述
    和insert一样都带回了一个迭代器,它返回的是被函数调用擦除的最后一个元素之后的元素的新位置的迭代器,也就是pos位置
iterator erase(iterator pos)
{assert(pos >= _start && pos < _finish);iterator it = pos + 1;while (it < _finish){*(it - 1) = *it;++it;}--_finish;return pos;
}

这样修改之后,上面的两种情况都可以解决了

	void test_vector8(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);print_Container(v);auto it = v.begin();while (it != v.end()){if (*it % 2 == 0){it = v.erase(it);}else{++it;}}print_Container(v);}

几乎所有的erase之后的迭代器都失效了,要更新之后再使用

2.6 resize

在这里插入图片描述
这里的val是使用了匿名对象,调用默认构造函数,对于内置类型和自定义类型都适用,看一下内置类型的默认构造:
在这里插入图片描述

void resize(size_t n, T val = T())
{if (n < size()){_finish = _start + n;}else // n >= _finish{reserve(n);// 自动扩容while (_finish < _start + n){*_finish = val;++_finish;}}
}

2.7 构造函数

  • 拷贝构造
vector(const vector<T>& v)
{reserve(v.size());for (auto& e : v){push_back(e);}
}

在这里插入图片描述
调用会报错,之前为什么没有报错呢?我们不写构造函数,编译器会帮我们生成默认构造函数,但是我们写了拷贝构造函数,也就相当于我们写了构造函数,编译器就不会帮我们生成默认构造函数了。

  • 迭代器区间构造
    在这里插入图片描述
    这个构造支持不同容器之间的构造
	template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}

在这里插入图片描述
类模板的成员函数也可以作为函数模板

  • n个值构造
vector(size_t n,T val = T())
{reserve(n);for (size_t i = 0; i < n; ++i){push_back(val);}
}

在这里插入图片描述
下面多测几组:
在这里插入图片描述

我们可以将size_t改为int来解决这个问题。
在这里插入图片描述

2.8 赋值运算符重载

void swap(vector<T>& tmp)
{std::swap(_start, tmp._start);std::swap(_finish, tmp._finish);std::swap(_end_of_storage, tmp._end_of_storage);
}
vector<T>& operator=(vector<T> tmp)
{swap(tmp);return *this;
}

2.9 扩容时的拷贝问题

在这里插入图片描述
上面出现的问题是扩容后出现了乱码,这是怎么导致的呢?
在这里插入图片描述
这里发现tmp和_start的指向的空间是同一个。
在这里插入图片描述
在扩容时,memcpy拷贝是一个字节一个字节的拷贝,将v1中的内容拷贝到tmp中,由于v1中存的是string类,存储的是指向字符串的指针,将指针拷贝给tmp是浅拷贝,拷贝结束后,调用delete函数, string类会调用析构函数,_str指向的空间被释放,因此tmp拷贝过来的_str被释放了就无法访问,就会出现乱码,然后_start指向的空间也被释放。想要解决这个问题就只能走深拷贝。

void reserve(size_t n)
{if (n > capacity()){// 开空间拷贝size_t old_size = size(); //记录扩容前的sizeT* tmp = new T[n];//memcpy(tmp, _start, old_size * sizeof(T));int i = 0;while (i < old_size){tmp[i] = _start[i];++i;}delete[] _start;_start = tmp;_finish = _start + old_size;_end_of_storage = _start + n;}// 出作用域tmp销毁
}

这里用了赋值运算符重载,完成了深拷贝,调用的是string类的赋值运算符重载
在这里插入图片描述
原空间被释放了也不影响现在的空间。

结语

以上就讲完了vector的使用及模拟实现,希望对大家有所帮助,感谢大家的阅读,欢迎大家批评指正!

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

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

相关文章

GOLANG+VUE后台管理系统

1.截图 2.后端工程截图 3.前端工程截图

推荐一款流程图和图表绘制工具:WizFlow Flowcharter Pro

WizFlow Flowcharter是一款易于使用、功能丰富的Windows流程图和图表绘制工具。它允许用户使用超过一百种预定义的形状和箭头定义形状“样式”。您可以将自己的样式保存在图表模板中&#xff0c;以建立自己的绘图方法。WizFlow附带了完整的流程图模板&#xff0c;以帮助您入门。…

fpga spi回环

SPI设备间的数据传输之所以又被称为数据交换,是因为 SPI协议规定一个 SPI设备 不能在数据通信过程中仅仅只充当一个"发送者(Transmitter)“或者"接收者 (Receiver)”.在每个 Clock 周期内,SPI 设备都会发送并接收一个 bit 大小的数据(不管主 设备好还是从设备),相当于…

软间隔支持向量机支持向量的情况以及点的各种情况

软间隔支持向量 ​ 这一节我们要回答的问题是&#xff1f;如何判断一个点是软间隔支持向量机中的支持向量&#xff0c;在硬间隔支持向量机中&#xff0c;支持向量只需要满足一个等式&#xff1a; y i ( w T x i b ) − 1 0 y_i(w^Tx_i b) -1 0 yi​(wTxi​b)−10 ​ 在软间…

界面控件DevExpress Blazor UI v24.1新版亮点 - 全新PDF Viewer等组件

DevExpress Blazor UI组件使用了C#为Blazor Server和Blazor WebAssembly创建高影响力的用户体验&#xff0c;这个UI自建库提供了一套全面的原生Blazor UI组件&#xff08;包括Pivot Grid、调度程序、图表、数据编辑器和报表等&#xff09;。 DevExpress Blazor控件目前已经升级…

defaultdict()语法

一、defaultdict产生的原因&#xff1a; 当我使用普通的字典时&#xff0c;用法一般是dict{},添加元素的只需要dict[element] value即&#xff0c;调用的时候也是如此&#xff0c;dict[element] xxx,但前提是element字典里&#xff0c;如果不在字典里就会报错。 defaultdict的…

[HE phy]

前导码 5G OFDM分为两部分&#xff0c;前导码Legacy preamble和数据data 前导码类型&#xff1a; 其中前导码Legacy preamble分为&#xff1a;Legacy Short Traing (L-STF), L_LTF, L-SIG。 如果数据是HT/VHT/HE&#xff0c;则还有其对应格式的前导码。 各类型作用&#xff…

【matlab】数据类型01-数值型变量(整数、浮点数、复数、二进制和十六进制)

文章目录 一、 整数1.1 整数的最值1.2 大整数1.3 当整数值超过了uint64最大值1.4 和其它类型数值运算 二、 浮点数2.1 双精度和单精度2.2 浮点数的存储2.3 浮点数的最值2.4 浮点数的“四舍五入”2.5 浮点数的算术运算2.6 意外&#xff1a;舍入误差、抵消、淹没和中间转换 三、复…

Tessy学习笔记—requirement(需求)的管理

1&#xff1a;什么是需求 Tessy中的requirement&#xff08;需求&#xff09;是&#xff0c;我们还是跟着Tessy官方的文档&#xff0c;继续学习&#xff0c;打开官方自带的工程Is Value In Range Requirement.project。 按照官方自带的操作手册&#xff0c;导入txt类型的需求…

关于10款PDF编辑工具我的使用体验!!!!!

如今&#xff0c;pdf的使用已经见怪不怪。在我们的工作、学习和生活中都已经离不开PDF文档了。那我么&#xff0c;随之而来的问题也就是我们经常需要对PDF文件进行编辑。市面上已经出现了许多PDF编辑软件。下面&#xff0c;我将与大家分享一下这几款PDF编辑器的个人使用经历。 …

unity小:shaderGraph不规则涟漪、波纹效果

实现概述 在本项目中&#xff0c;我们通过结合 Sine、Polar Coordinates 和 Time 节点&#xff0c;实现了动态波纹效果。以下是实现细节&#xff1a; 核心实现 Sine 波形生成&#xff1a; 使用 Sine 节点生成基本的波形。该节点能够创建周期性变化&#xff0c;为波纹效果提供…

针对gitgitee的使用

1.下载git 链接 打开终端&#xff0c;桌面鼠标右键 2.配置密钥 登录gitee。 设置密钥 查看官方文档 跟着教程 复制最后的输出进行密钥添加 验证是否添加成功 3.创建&连接远程仓库 创建仓库 git终端进行配置 远程仓库克隆到本地 桌面终端clone,克隆他人|自己的仓库到本地…

基于yolov8、yolov5的玉米病害检测识别系统(含UI界面、训练好的模型、Python代码、数据集)

项目介绍 项目中所用到的算法模型和数据集等信息如下&#xff1a; 算法模型&#xff1a;     yolov8、yolov8 SE注意力机制 或 yolov5、yolov5 SE注意力机制 &#xff0c; 直接提供最少两个训练好的模型。模型十分重要&#xff0c;因为有些同学的电脑没有 GPU&#xff0…

省级生活垃圾无害化处理率面板数据(2004-2022年)

生活垃圾无害化处理率是指经过处理的生活垃圾中&#xff0c;达到无害化标准的垃圾所占的比例。这一指标的提高&#xff0c;意味着城市在垃圾处理方面的能力增强&#xff0c;能够有效减少环境污染&#xff0c;提升居民生活质量&#xff0c;同时也是城市可持续发展的重要保障。 …

NTIRE2024 | 修复一切图像RAIM: Restore All Image Model Challenge报告分析

论文/报告地址&#xff1a;NTIRE 2024 Restore Any Image Model (RAIM) in the Wild Challenge 0、写在前面 马上CVPR2024就要开幕&#xff0c;各大挑战赛的排名和详细报告也都出炉。近期留意到这个名字很屌的赛道&#xff0c;修复一切图像的模型&#xff0c;小米的团队的拿了…

【Visual Studio】设置文件目录

打开属性 输出目录&#xff1a;$(SolutionDir)bin\$(Platform)\$(Cinfiguration)\ 中间目录&#xff1a;$(SolutionDir)bin\intermediates\$(Platform)\$(Cinfiguration)\

基于Java的校园菜鸟驿站管理系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…

Photoshop(PS)——人像磨皮

1.新建一个文件&#xff0c;背景为白色&#xff0c;将图片素材放入文件中 2.利用CtrlJ 复制两个图层出来&#xff0c;选择第一个拷贝图层&#xff0c;选择滤镜---杂色---蒙尘与划痕 3.调整一下数值&#xff0c;大概能够模糊痘印痘坑&#xff0c;点击确定。 4.然后选择拷贝2图层…

Yocto - 使用Yocto开发嵌入式Linux系统_13 创建定制层

Creating Custom Layers 除了使用社区或供应商提供的现有图层外&#xff0c;我们还将在本章中学习如何为我们的产品创建图层。此外&#xff0c;我们还将了解如何创建机器定义和分布&#xff0c;并从中获益&#xff0c;从而更好地组织我们的源代码。 In addition to using exist…

第5章-总体设计 5.2 需求转化为规格

5.2 需求转化为规格 1.框式产品&#xff08;1&#xff09;业务规格&#xff0c;这需要满足客户期望、有市场竞争力、颗粒度最合理。&#xff08;2&#xff09;整框规格&#xff0c;包括电源、功耗、散热、可靠性的规格&#xff0c;要保证整款满足环境应用要求。&#xff08;3&a…