当前位置: 首页 > news >正文

STL - vector的使用和模拟实现

目录

一:vector的构造函数

二:vector的迭代器

三vector的空间增长问题

四:vector 增删查改接口

五:vector的模拟实现

(一)一些简单接口的实现:

(二)一些复杂接口的实现

迭代器失效问题:

(三)五个构造函数的模拟实现

(1)默认构造

(2)拷贝构造函数

(3)使用n个val去初始化容器的构造

(4)迭代器区间初始化构造:

(5)赋值构造


vector其实就是我们数据结构中的顺序表。

一:vector的构造函数

(1)无参构造:即默认构造。vector构造一个没有元素的空容器。

	// 走默认构造vector<char> vc;

(2)填充构造函数:构造一个包含 n 个元素的容器。每个元素都是 val 的副本。

	// 默认初始化为0vector<int> v1(10);// 初始化为1vector<int> v2(10, 1);

 (3)拷贝构造函数:构造一个容器,其中包含与范围 [first,last] 一样多的元素,每个元素都按相同的顺序从该区域中的相应元素构造。

	// 拷贝构造vector<int> v3(v2);

(4)使用迭代器进行初始化的构造:构造一个容器,其中包含与范围 [first,last] 一样多的元素,每个元素都按相同的顺序从该区域中的相应元素构造。

	vector<int> v1(10);// 使用迭代器进行初始化vector<int> v3(v1.begin(), v1.end()-3);

二:vector的迭代器

同其他的string容器一样,begin和end分别是容器的第一个位置和最后一个位置,反向迭代器则相反。const迭代器和非const迭代器和string的也是一样的C++_STL_string使用和模拟实现-CSDN博客

这里可以看一下。

// 初始化为一个定值
vector<int> v2(10, 1);
// 迭代器使用
//vector<int>::iterator it;
//vector<int>::const_iterator it;
// 反向迭代器
vector<int>::reverse_iterator it;
//it = v2.begin();
it = v2.rbegin();
//while (it != v2.end())
while (it != v2.rend())
{//cout << ++(*it) << " ";cout << *it << " ";it++;
}

三vector的空间增长问题

(1)size():返回元素的实际个数

(2)capacity():容器容量的大小

(3)resize() :修改实际容器元素个数

(4)reserve():改变capacity的大小

(5)empty():判断容器是否为空

注意:在g++和vs中capacity在扩容的时候可能不一样,有的是1.5倍扩容,有的是2倍扩容

具体我们来看下这几个接口的情况:

// 测试vector 空间增长问题接口
void test02()
{vector<int> v2(10, 1);cout << v2.size() << endl;cout << v2.capacity() << endl;cout << v2.empty() << endl;// resize如果n大于size的话会将size的元素进行初始化v2.resize(40);// 这里改变capacity的为13并不会缩容v2.reserve(13);cout << v2.capacity() << endl;for (auto& x : v2){cout << x << " ";}
}

四:vector 增删查改接口

(1)push_back:在容器末尾插入一个值

void push_back (const value_type& val);

(2)pop_back:删除容器末尾的一个值

void pop_back();

(3)find:在范围内查找值

返回范围中比较等于 的第一个元素的迭代器。如果未找到此类元素,则函数返回 。

template <class InputIterator, class T>   InputIterator find (InputIterator first, InputIterator last, const T& val);

(4)insert:通过在指定位置的元素之前插入新元素来扩展向量,从而有效地增加容器大小(增加插入的元素数)。

single element (1)	
iterator insert (iterator position, const value_type& val);
fill (2)	void insert (iterator position, size_type n, const value_type& val);
range (3)	
template <class InputIterator>    void insert (iterator position, InputIterator first, InputIterator last);

(5)erase:从向量中删除单个元素 (位置) 或一系列元素 ([first,last))

iterator erase (iterator position);iterator erase (iterator first, iterator last);

(6)swap:交换向量的数据空间

void swap (vector& x);

(7)operator[]:返回对向量容器中位置 n 处的元素的引用。

reference operator[] (size_type n);const_reference operator[] (size_type n) const;

1~7接口代码:

void test03()
{//find
//push_back 
///vector<int> v2;for (int i = 0; i < 100; i++){v2.push_back(i);}v2.pop_back();//for (auto& e : v2)//{//	cout << e << " ";//}cout << endl;// 在一个范围内查找数据val,并且返回第一个等于val的迭代器,如果没有找到就返回区间的末尾迭代器vector<int>::iterator it = find(v2.begin(),v2.end(), 31);//while (it != v2.end())//{//	//cout << ++(*it) << " ";//	cout << *it << " ";//	it++;//}
/
//insert
//在pos迭代器位置插入val,不是下标v2.insert(v2.begin() + 10, 10025);it = v2.begin();//while (it != v2.end())//{//	//cout << ++(*it) << " ";//	cout << *it << " ";//	it++;//}//erase
//删除迭代区间的数据或者迭代pos位置的数据// iterator erase (iterator first, iterator last);v2.erase(v2.begin() + 3, v2.end() - 10);it = v2.begin();while (it != v2.end()){//cout << ++(*it) << " ";cout << *it << " ";it++;}// iterator erase (iterator position);v2.erase(v2.begin() + 20);it = v2.begin();while (it != v2.end()){//cout << ++(*it) << " ";cout << *it << " ";it++;}	
}// 测试swap
void test04()
{// template <class T, class Alloc>// void swap(vector<T, Alloc>&x, vector<T, Alloc>&y);vector<int> v2(10, 1);vector<int> v3(10, 3);// 交换两个向量的空间v2.swap(v3);vector<int>::iterator it;it = v2.begin();//while (it != v2.end())//{//	//cout << ++(*it) << " ";//	cout << *it << " ";//	it++;//}
//
//reference operator[] (size_type n);const_reference operator[] (size_type n) const;for (int i = 0; i < v2.size(); i++){cout << ++v2[i]<< ' ';}}

五:vector的模拟实现

在实现vector的时候我们采用模板来实现,方便vector存取任意的类型,可以是自定义类型,也可以是内置类型,例如:vector<vector<int>>(二维数组)。

因为vector的数据结构本质是顺序表,所以我们可以设置一个顺序表来模拟实现它。

然后设置三个标志位:

private:iterator _start = nullptr;iterator _finsh = nullptr;iterator _end_of_storage = nullptr;

_start表示容器的起始位置,_finsh表示有效数据个数的最后一个位置,_end_of_storage表示容器容量的大小。

iterator使我们使用typedef将模板类型重命名的。

namespace cp
{template<class T>class vector {public:typedef T* iterator;typedef const T* const_iterator;private:iterator _start = nullptr;iterator _finsh = nullptr;iterator _end_of_storage = nullptr;};    
}

我们将我们的vector使用一个单独的命名空间CP包起来,避免跟库里面的vector冲突。

关于模板请看:C++模板初阶-CSDN博客

(一)一些简单接口的实现:

一些比较简单的接口我们就将他们放到类里面

关于容量相关的接口:

//清除数据
void clear()
{_finsh = _start;
}
//判断容器是否为空
bool empty()const 
{return _finsh == _start;
}
//获取容器容量的大小
size_t size() const 
{//指针相减得到元素个数return _finsh - _start;
}
//获取容器容量的大小
size_t capacity() const 
{return _end_of_storage - _start;
}

迭代器的实现:const迭代器和非const迭代器,反向迭代器就不实现了

几种迭代器
iterator begin()
{return _start;
}
iterator end()
{return _finsh;
}
const_iterator cbegin() const
{return _start;
}
const_iterator begin() const
{return _start;
}
const_iterator end() const
{return _finsh;
}
const_iterator cend() const
{return _finsh;
}

函数后边加const表示成员变量不可以修改。

方括号下标[ ]的重载实现:

//返回普通引用,可以修改
T& operator[](size_t pos)
{return _start[pos];
}
//返回const引用,不可以修改
const T& operator[](size_t pos)const
{return _start[pos];
}

尾删除函数

void pop_back()
{assert(!empty());--_finsh;
}

(二)一些复杂接口的实现

这些复杂的接口我们将他们放到类外面。

(1)reserve:开辟空间并检查。

template<class T>
void vector<T>::reserve(size_t n)
{if (n > capacity()){size_t old_size = size();T* tmp = new T[n];for (int i = 0; i < old_size; i++){tmp[i] = _start[i];}if (_start){delete[] _start;}_start = tmp;_finsh = _start + old_size;_end_of_storage = _start + n;}
}

注意:在更新成员变量的时候要先预存一份没交换之前的size,因为在_starttmp交换的时候也会影响到size的改变。另外,记得释放旧空间,当然如果原来的容器是空的就不用释放了。

(2)push_back:在容器的末尾位置尾插一个数据

template<class T>
void vector<T>::push_back(const T& x)
{if (_finsh == _end_of_storage){reserve(capacity() == 0 ? 4 : 2 * capacity());}*_finsh = x;++_finsh;
}

只要是往容器里面插入数据都要检查容器是否满了,如果满了就需要先扩容再插入数据,这和数据结构的顺序表是一样的。

迭代器失效问题:

通常我们在插入和删除的时候使用的是迭代器,所以在一些情况下会导致迭代器失效,string的迭代器版本也会有这样的情况。

(1)insert:在pos迭代器位置插入数据,并且返回当前插入数据位置的迭代器。

	template<class T>typename vector<T>::iterator vector<T>::insert(iterator pos, T val){assert(pos >= _start);assert(pos < _finsh);if (_finsh == _end_of_storage){//防止pos位置因为扩容而失效size_t len = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());pos = _start + len;}iterator end = _finsh;while (end >= pos){*end = *(end - 1);end--;}*pos = val;_finsh++;pos++;return pos;}

知识点补充:在这里我们使用typename的原因,因为在实例化的时候编译器不知道迭代器(iterator)到底是类型还是成员变量,所以我们使用typename。(规定使用typename指定的是类型)。

在实现insert的时候我们要先扩容,但是扩容的时候原来_start指向的空间和tmp交换了

但是我们的pos位置迭代器还是原来空间的pos,原来空间交换给tmp之后随着函数结束tmp变量指向的空间销毁,pos所指向的也就是一个随机空间。当我们在挪动数据的时候,因为pos不是当前对象指向的空间位置,所以会发生一些错误,插入数据也就会导致一些问题。

解决方案:

如上述代码,我们先记录pos的相对位置,在更新_start指向的空间的之后我们也更新pos的迭代器,这样就不会发生问题了。

这是第一种迭代器失效的情况:迭代器指向的空间被释放,类似于野指针。

(2)erase:挪动覆盖删除迭代器位置的数据,返回pos位置的迭代器。

我们先实现一下这个成员函数,同样,我们将他们放到类外面。

template<class T>
typename vector<T>::iterator vector<T>::erase(iterator pos)
{assert(pos >= _start);assert(pos < _finsh);iterator start = pos;while (start < _finsh){*start = *(start + 1);start++;}_finsh--;return pos;
}

当我们删除数据之后,pos还是指向原来的位置,但是如果我们以下标的形式看待它。

例如:我们来测试一下,我们写一个vector,往里面放一些数据,删除之后使用它的迭代器来操作。

因为方便测试我们实现一个打印容器的函数模板:

	template<class Container>void print_container(const Container& con){/*auto it = con.cbegin();while (it != con.cend()){cout << *it << " ";++it;}cout << endl;*/for (auto& e : con){cout << e << " ";}cout << endl;}
//测试迭代器失效问题
void test_vaid_iterator()
{cp::vector<int> v;v.push_back(0);v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);//删除5位置的内容cp::vector<int>::iterator it = v.erase(v.begin()+3);cp::print_container(v);*it *= 10;cp::print_container(v);
}

可以看到原来位置的意义已经改变了,我们原本的位置在删除数据之后已经改变了。

(3)库里面的迭代器失效问题:Windows平台下。

我们来测试一下库里面的insert和erase。

测试函数:

(1)测试insert:

//测试迭代器失效问题
void test_vaid_iterator()
{std::vector<int> v;v.push_back(0);v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);//删除5位置的内容std::vector<int>::iterator pos = v.begin() + 3;v.insert(pos, 3);//删除pos位置的内容cp::print_container(v);//访问pos位置*pos*=10;cp::print_container(v);
}

(2)的是erase:

//测试迭代器失效问题
void test_vaid_iterator()
{std::vector<int> v;v.push_back(0);v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);//删除5位置的内容std::vector<int>::iterator pos = v.begin() + 3;cp::print_container(v);v.erase(pos);//删除pos位置的内容*pos *= 10;cp::print_container(v);
}

在vs2020中编译器会强制检查报错。在insert和erase之后是不允许访问pos位置的迭代器的。

总结:不管是自己实现的还是标准库内部实现的,在容器中(string,vector..)为了安全考虑,在insert和erase之后就不要访问pos位置的迭代器了。如果要访问就要更新迭代器。

(三)五个构造函数的模拟实现

接下来我们来实现他们的成员函数。

(1)默认构造

因为构造函数默认走初始化列表,所以我们在实现默认构造函数的时候可以这样写。

vector() = default;

因为我们在成员变量哪里给了缺省值,所以使用default关键字可以强制编译器生成默认构造。

当然,如果们没在成员变量给缺省参数的话可以自己走初始化列表:

		vector():_start(nullptr),_finsh(nullptr),_end_of_storage(nullptr){// 啥也不干,因为会自动走舒适化列表用缺省值完成初始化}

我们来测试一下:

可以看到v对象的三个成员已经被初始化完成了,都是空指针。

(2)拷贝构造函数

用一个已经存在的对象去初始化另一个刚创建的对象

template<class T>
vector<T>::vector(const vector<T>& v)
{//防止自己给自己赋值if (this != &v){reserve(v.capacity());for (auto& e : v){push_back(e);}//_finsh和_endd_of_storage是指针,不是整型,不能直接赋值,而且在reserve和push_back的时候已经更新过了,不用更新//_finsh = v._finsh;//_end_of_storage = v._end_of_storage;}
}

(3)使用n个val去初始化容器的构造

	template<class T>vector<T>::vector(size_t n, vector<T>& val){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}

(4)迭代器区间初始化构造:

template<class input_iterator>
vector(input_iterator first, input_iterator last)
{while (first != last){push_back(*first);first++;}
}

测试:

void Test03()
{cp::vector<int> v;v.push_back(0);v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);cp::print_container(v);cp::vector<int> v4(v.begin()+2, v.begin() + 5);cp::print_container(v4);}

(5)赋值构造

因为都是自定义类型,且需要开辟空间,所以和拷贝构造一样都是深拷贝。

		//this = vvector<T>& operator=(const vector<T>& v){if (this != &v){clear();reserve(v.size());/*size_t size = v.size();T* tmp = new T[v.capacity()];for (size_t i = 0; i < size; i++){tmp[i] = v._start[i];}if (_start)delete[] _start;_start = tmp;_finsh = _start + size;_end_of_storage = _start + v.capacity();*/for (auto& e : v){push_back(e);}}return *this;}

赋值构造的现代写法:

void swap(vector<T>& v)
{std::swap(_start, v._start);std::swap(_finsh, v._finsh);std::swap(_end_of_storage, v._end_of_storage);
}
//现代写法
vector<T>& operator=(vector<T> v)
{swap(v);return *this;
}

(6)析构函数

~vector()
{if (_start)//如果_start是空(为假),则说明已经析构了,不需要析构{delete[] _start;_start = _finsh = _end_of_storage = nullptr;}
}

相关文章:

STL - vector的使用和模拟实现

目录 一&#xff1a;vector的构造函数 二&#xff1a;vector的迭代器 三vector的空间增长问题 四&#xff1a;vector 增删查改接口 五&#xff1a;vector的模拟实现 &#xff08;一&#xff09;一些简单接口的实现&#xff1a; &#xff08;二&#xff09;一些复杂接口的…...

《鸿蒙生态:开发者的机遇与挑战》

一、引言 在当今科技飞速发展的时代&#xff0c;操作系统作为连接硬件与软件的核心枢纽&#xff0c;其重要性不言而喻。鸿蒙系统的出现&#xff0c;为开发者带来了新的机遇与挑战。本文将从开发者的角度出发&#xff0c;阐述对鸿蒙生态的认知和了解&#xff0c;分析鸿蒙生态的…...

【C++融会贯通】二叉树进阶

目录 一、内容说明 二、二叉搜索树 2.1 二叉搜索树概念 2.2 二叉搜索树操作 2.2.1 二叉搜索树的查找 2.2.2 二叉搜索树的插入 2.2.3 二叉搜索树的删除 2.3 二叉搜索树的实现 2.3.1 二叉搜索树的节点设置 2.3.2 二叉搜索树的查找函数 2.3.2.1 非递归实现 2.3.2.2 递…...

使用python-Spark使用的场景案例具体代码分析

使用场景 1. 数据批处理 • 日志分析&#xff1a;互联网公司每天会产生海量的服务器日志&#xff0c;如访问日志、应用程序日志等。Spark可以高效地读取这些日志文件&#xff0c;对数据进行清洗&#xff08;例如去除无效记录、解析日志格式&#xff09;、转换&#xff08;例如…...

如何查看本地的个人SSH密钥

1.确保你的电脑上安装了 Git。 你可以通过终端或命令提示符输入以下命令来检查&#xff1a; git --version 如果没有安装&#xff0c;请前往 Git 官网 下载并安装适合你操作系统的版本。 2.查找SSH密钥 默认情况下&#xff0c;SSH密钥存储在你的用户目录下的.ssh文件夹中。…...

本人认为 写程序的三大基本原则

1. 合法性 ‌定义‌&#xff1a;合法性指的是程序必须遵守法律法规和道德规范&#xff0c;不得用于非法活动。 ‌建议‌&#xff1a; ‌了解法律法规‌&#xff1a;在编写程序之前&#xff0c;了解并遵守所在国家或地区的法律法规&#xff0c;特别是与数据隐私、版权、网络安…...

A030-基于Spring boot的公司资产网站设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…...

React Hooks 深度解析与实战

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 React Hooks 深度解析与实战 React Hooks 深度解析与实战 React Hooks 深度解析与实战 引言 什么是 Hooks? 定义 为什么需要 Ho…...

#渗透测试#SRC漏洞挖掘#蓝队基础之网络七层杀伤链04 终章

网络杀伤链模型&#xff08;Kill Chain Model&#xff09;是一种用于描述和分析网络攻击各个阶段的框架。这个模型最初由洛克希德马丁公司提出&#xff0c;用于帮助企业和组织识别和防御网络攻击。网络杀伤链模型将网络攻击过程分解为多个阶段&#xff0c;每个阶段都有特定的活…...

计算机毕业设计Python+大模型农产品推荐系统 农产品爬虫 农产品商城 农产品大数据 农产品数据分析可视化 PySpark Hadoop

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

爬虫补环境案例---问财网(rpc,jsdom,代理,selenium)

目录 一.环境检测 1. 什么是环境检测 2.案例讲解 二 .吐环境脚本 1. 简介 2. 基础使用方法 3.数据返回 4. 完整代理使用 5. 代理封装 6. 封装所有使用方法 jsdom补环境 1. 环境安装 2. 基本使用 3. 添加参数形式 Selenium补环境 1. 简介 2.实战案例 1. 逆向目…...

SpringBoot有几种获取Request对象的方法

HttpServletRequest 简称 Request&#xff0c;它是一个 Servlet API 提供的对象&#xff0c;用于获取客户端发起的 HTTP 请求信息。例如&#xff1a;获取请求参数、获取请求头、获取 Session 会话信息、获取请求的 IP 地址等信息。 那么问题来了&#xff0c;在 Spring Boot 中…...

在 Windows 11 中使用 MuMu 模拟器 12 国际版配置代理

**以下是优化后的教学内容,使用 Markdown 格式,便于粘贴到 CSDN 或其他支持 Markdown 格式的编辑器中: 在 Windows 11 中使用 MuMu 模拟器 12 国际版配置代理 MuMu 模拟器内有网络设置功能,可以直接在模拟器中配置代理。但如果你不确定如何操作,可以通过在 Windows 端设…...

ASP.NET Core Webapi 返回数据的三种方式

ASP.NET Core为Web API控制器方法返回类型提供了如下几个选择&#xff1a; Specific type IActionResult ActionResult<T> 1. 返回指定类型&#xff08;Specific type&#xff09; 最简单的API会返回原生的或者复杂的数据类型&#xff08;比如&#xff0c;string 或者…...

SQL面试题——蚂蚁SQL面试题 连续3天减少碳排放量不低于100的用户

连续3天减少碳排放量不低于100的用户 这是一道来自蚂蚁的面试题目,要求我们找出连续3天减少碳排放量低于100的用户,之前我们分析过两道关于连续的问题了 SQL面试题——最大连续登陆问题 SQL面试题——球员连续四次得分 这两个问题都是跟连续有关的,但是球员连续得分的难…...

Python酷库之旅-第三方库Pandas(216)

目录 一、用法精讲 1011、pandas.DatetimeIndex.tz属性 1011-1、语法 1011-2、参数 1011-3、功能 1011-4、返回值 1011-5、说明 1011-6、用法 1011-6-1、数据准备 1011-6-2、代码示例 1011-6-3、结果输出 1012、pandas.DatetimeIndex.freq属性 1012-1、语法 1012…...

论文解析:计算能力资源的可信共享:利益驱动的异构网络服务提供机制

目录 论文解析:计算能力资源的可信共享:利益驱动的异构网络服务提供机制 KM-SMA算法 KM-SMA算法通过不断更新节点的可行顶点标记值(也称为顶标),利用匈牙利方法(Hungarian method)来获取匹配结果。在获取匹配结果后,该算法还会判断该结果是否满足Pareto最优性,即在没…...

Spring AOP技术

1.AOP基本介绍 AOP 的全称 (aspect oriented programming) &#xff0c;面向切面编程。 1.和传统的面向对象不同。 面向切面编程是根据自我的需求&#xff0c;将切面类的方法切入到其他的类的方法中。&#xff08;这么说抽象吧&#xff01;来张图来解释。&#xff09; 如图 传…...

数字IC实践项目(10)—基于System Verilog的DDR4 Model/Tb 及基础Verification IP的设计与验证(付费项目)

数字IC实践项目&#xff08;10&#xff09;—基于System Verilog的DDR4 Model/Tb 及基础Verification IP的设计与验证&#xff08;付费项目&#xff09; 前言项目框图1&#xff09;DDR4 Verification IP2&#xff09;DDR4 JEDEC Model & Tb 项目文件1&#xff09;DDR4 Veri…...

MATLAB保存多帧图形为视频格式

基本思路 在Matlab中&#xff0c;要将drawnow绘制的多帧数据保存为视频格式&#xff0c;首先需要创建一个视频写入对象。这个对象用于将每一帧图像数据按照视频格式的要求进行组合和编码。然后&#xff0c;在每次drawnow更新绘图后&#xff0c;将当前的图形窗口内容捕获为一帧图…...

redis7.x源码分析:(3) dict字典

dict字典采用经典hash表数据结构实现&#xff0c;由键值对组成&#xff0c;类似于C中的unordered_map。两者在代码实现层面存在一些差异&#xff0c;比如gnustl的unordered_map分配的桶数组个数是&#xff08;质数n&#xff09;&#xff0c;而dict分配的桶数组个数是&#xff0…...

连续九届EI稳定|江苏科技大学主办

【九届EI检索稳定|江苏科技大学主办 | IEEE出版 】 &#x1f388;【截稿倒计时】&#xff01;&#xff01;&#xff01; ✨徐秘书&#xff1a;gsra_huang ✨往届均已检索&#xff0c;已上线IEEE官网 &#x1f38a;第九届清洁能源与发电技术国际学术会议&#xff08;CEPGT 2…...

HarmonyOS NEXT应用开发实战 ( 应用的签名、打包上架,各种证书详解)

前言 没经历过的童鞋&#xff0c;首次对HarmonyOS的应用签名打包上架可能感觉繁琐。需要各种秘钥证书生成和申请&#xff0c;混在一起也分不清。其实搞清楚后也就那会事&#xff0c;各个文件都有它存在的作用。 HarmonyOS通过数字证书与Profile文件等签名信息来保证鸿蒙应用/…...

【CICD】CICD 持续集成与持续交付在测试中的应用

一、什么是CICD&#xff1f; CI/CD 是指持续集成&#xff08;Continuous Integration&#xff09;和持续部署&#xff08;Continuous Deployment&#xff09;或持续交付&#xff08;Continuous Delivery&#xff09; 1.1 持续集成&#xff08;Continuous Integration&#xf…...

Dolby TrueHD和Dolby Digital Plus (E-AC-3)编码介绍

文章目录 1. Dolby TrueHD特点总结 2. Dolby Digital Plus (E-AC-3)特点总结 Dolby TrueHD 与 Dolby Digital Plus (E-AC-3) 的对比 Dolby TrueHD和Dolby Digital Plus (E-AC-3) 是两种高级的杜比音频编码格式&#xff0c;常用于蓝光影碟、流媒体、影院等高品质音频传输场景。它…...

数字频率计的设计-- 基于 HDL 方法

目录 数字频率计的设计 1.计数、锁存与显示译码电路设计 2.主控电路设计 3.分频电路设计 4.顶层电路设计 伪随机序列发生器 的设计 数字频率计的设计 基于HDL设计数字系统时&#xff0c;可以根据需要应用Verilog HDL描述所需要的功能电路&#xff0c;既有利于节约资源&am…...

[程序员] 没有产生core文件的原因

最近和同事一块看一个core文件没有产生的问题,总结了一些在CSDN的专栏里。分析的过程,参考使用了ftrace的功能,感觉非常实用。 如果有需要可以参考。大体上就这么几种情况:信号的特殊处理,coredump相关的配置没有设置正确,文件系统访问权限问题,setuid相关的不匹配问题。…...

【数字图像处理+MATLAB】基于 Sobel 算子计算图像梯度并进行边缘增强:使用 imgradientxy 函数

引言 在图像处理中&#xff0c;边缘通常是图像中像素强度变化最大的地方&#xff0c;这种变化可以通过计算图像的梯度来量化。梯度是一个向量&#xff0c;它的方向指向像素强度增加最快的方向&#xff0c;它的大小&#xff08;或者说幅度&#xff09;表示像素强度增加的速度。…...

P10901 [蓝桥杯 2024 省 C] 封闭图形个数

铁子们好呀&#xff0c;今天博主给大家更新一道编程题&#xff01;&#xff01;&#xff01; 题目链接如下&#xff1a; P10901 [蓝桥杯 2024 省 C] 封闭图形个数 好&#xff0c;接下来&#xff0c;我将从三个方面讲解这道例题。分别是 题目解析算法原理代码实现 文章目录 1.题…...

ubuntu-desktop-24.04上手指南(更新阿里源、安装ssh、安装chrome、设置固定IP、安装搜狗输入法)

ubuntu-desktop-24.04上手指南(更新阿里源、安装ssh、安装chrome、设置固定IP、安装搜狗输入法) 一、更新并安装基础软件 #切换root用户 sudo su -#更新 apt update #升级 apt upgrade#install vim apt install vim#install net-tools apt install net-tools二、安装ssh并设置…...