深入学习STL标准模板库

C++ STL standard template libaray 标准模板库

目录

    • C++ STL standard template libaray 标准模板库
  • 一、标准容器
    • 顺序容器
      • vector
      • deque
      • list
      • vector deque list对比
    • 容器适配器
      • stack
      • queue
      • priority_queue
    • 关联容器
    • (1)无序关联容器
      • unordered_set
      • unordered_multiset
      • unordered_map
      • unordered_multimap
    • (2)有序关联容器
      • set
      • multiset
      • map
      • mutimap
  • 二、迭代器
      • iterator和const iterator
      • reverse_iterator和const_reverse_iterator
  • 三、函数对象
  • 四、泛型算法

一、标准容器

顺序容器

vector

底层数据结构:动态开辟的数组,每次以原来空间大小的2倍进行扩容(开辟两倍大小的新数组,拷贝构造原数组对象,析构原数组对象,回收原数组内存)

vector<int> vec;
增加:
vec.push_back(20); 末尾添加元素 O(1) 导致容器扩容
vec.insert(it,20); it迭代器指向的位置添加一个元素20 O(n) 导致容器扩容
删除:
vec.pop_back(); 末尾删除元素 O(1)
vec.erase(it); 删除it迭代器指向的元素 O(n)
查询:
operator[] 下标的随机访问 vec[5] O(1)
iterator 迭代器进行遍历
find,for_each
foreach => 底层通过iterator来实现的
常用方法介绍:
size()
empty()
reserve(20):vector预留空间的 只给容器底层开辟指定大小的内存空间,并不会添加新的元素
resize(20):容器扩容用的 不仅给容器底层开辟指定大小的内存空间,还会会添加新的元素
swap:两容器进行元素交换

注意1:resize和reserver的区别
reserve预留空间 只给容器底层开辟指定大小的内存空间,并不会添加新的元素
resize:容器扩容 不仅给容器底层开辟指定大小的内存空间,还会添加新的元素

	vector<int> ve;ve.reserve(20);//预留内存空间 cout<<ve.empty()<<endl;//输出 1 cout<<ve.size()<<endl;//输出 0ve.push_back(1); ve.push_back(2); ve.push_back(3); for(int x:ve) cout<<x<<" ";//输出 1 2 3
	vector<int> ve;ve.resize(10);//开辟空间 添加元素cout<<ve.empty()<<endl;//输出 0 cout<<ve.size()<<endl;//输出 10 ve.push_back(1); ve.push_back(2); ve.push_back(3); for(int x:ve) cout<<x<<" ";//输出 0 0 0 0 0 0 0 0 0 0 1 2 3

注意2:vector调用clear()或者size(0),会清除容器内的所有元素,但是不会释放内存,如果想释放内存需要调用shrink_to_fit()函数

	vector<int> ve{1,2,3,4,5,6,7,8,9,10};cout<<ve.size()<<endl;//输出10 cout<<ve.capacity()<<endl;//输出10ve. clear(); //ve.resize(0);cout<<ve.size()<<endl;//输出0 cout<<ve.capacity()<<endl;//输出10cout<<"ve[2]="<<ve[2]<<endl;//输出3 因为元素清空了 内存没有清空 ve.shrink_to_fit();cout<<ve.size()<<endl;//输出0 cout<<ve.capacity()<<endl;//输出0

注意3:对容器进行连续插入或者删除操作(insert/erase),一定要更新迭代器,否则第一次insert或者erase完成,迭代器就失效了,比如下面代码经典错误

#include <iostream>
#include <vector>
using namespace std;
int main() {vector<int> ve{1,2,3,4,5,6,7,8,9,10};//把容器中所有的偶数删除auto it = ve.begin();for(;it!=ve.end();it++) {if(*it%2==0){ve.erase(it);//错误迭代器已经失效了 }}for(int x:ve){cout<<x<<" ";//输出为空}return 0;
}

正确写法:

#include <iostream>
#include <vector>
using namespace std;
int main() {vector<int> ve{1,2,3,4,5,6,7,8,9,10};//把容器中所有的偶数删除auto it = ve.begin();while(it!=ve.end()){if(*it%2==0){it = ve.erase(it);//删除之后返回迭代器位置 }else//迭代器指向的不是偶数才后移 {++it;}}for(int x:ve){cout<<x<<" ";//输出1 3 5 7 9 }cout<<endl;//给vector容器中所有的奇数前面都添加一个小于奇数1的偶数 for(it=ve.begin();it!=ve.end();++it){if(*it%2!=0){it = ve.insert(it,*it-1);//插入之后返回新的迭代器位置 ++it;//迭代器需要向后多移动一次保证不重复插入 }}for(int x:ve){cout<<x<<" ";//输出0 1 2 3 4 5 6 7 8 9 }return 0;
}

deque

底层数据结构:动态开辟的二维数组(二维双端队列),一维数组从大小2开始,以2倍的方式进行扩容,每次扩容后,原来的二维数组(固定长度),从新的第一维数组的下标oldsize/2开始存放,上下都预留相同的空行,方便支持deque的首尾元素添加

注意:deque底层每一个第二维本身是连续的,但是所有的二维不是连续的,是重新new出来的(分段连续)

底层原理:
一般编译器默认大小
#define MAP_SIZE 2 第一维度大小
#define QUE_SIZE 4096/sizeof(T) 第二维度大小 T为数据类型

1.初始的队头队尾指针在队列中间(双端队列方便两头都可以插入删除)
在这里插入图片描述
2.随着元素的插入队头队尾指针移动
在这里插入图片描述
3.当队列满的时候,开辟新的二维空间
在这里插入图片描述
4.当所有队列满的时候进行2倍扩容(二维会放在一维中间位置)
在这里插入图片描述
在这里插入图片描述
操作:
deque<int> deq;
增加:
deq.push_back(20); 从末尾添加元素 O(1) 可能扩容
deq.push_front(20);从首部添加元素 O(1) 可能扩容
deq.insert(it,20); it指向的位置添加元素 O(n) 可能扩容

删除:
deq.pop_back(); 从末尾删除元素 O(1)
deq.pop_front(); 从首部删除元素 O(1)
deq.erase(it); 从it指向的位置删除元素 O(n)

查询搜索
iterator (连续的insert和erase一定要考虑迭代器失效的问题)

list

底层数据结构:双向的循环列表

list mylist;
增加:
mylist.push_back(20); 从末尾添加元素 O(1) 可能扩容
mylist.push_front(20);从首部添加元素 O(1) 可能扩容
mylist.insert(it,20); it指向的位置添加元素 O(1) 可能扩容 往往需要先query查询操作
对于链表来说,查询操作效率就比较慢

删除:
mylist.pop_back(); 从末尾删除元素 O(1)
mylist.pop_front(); 从首部删除元素 O(1)
mylist.erase(it); 从it指向的位置删除元素 O(1)

查询搜索
iterator (连续的insert和erase一定要考虑迭代器失效的问题)

vector deque list对比

vector特点:动态数组,内存连续,2倍的方式进行扩容
deque特点:动态开辟的二维数组空间,第二维是固定长度的数组空间,扩容的时候(第一维的数组进行2倍扩容)
list特点:双向循环链表

vector和deque之间的区别?

1.底层数据结构:
2.前中后插入删除元素的时间复杂度:中间O(n),末尾都是O(1), 前插deque O(1) vector O(n)
3.对于内存的使用效率:vector需要的内存空间必须连续,deque可以分块进行数据存储,不需要内存必须连续
4.在中间进行insert或者erase,虽然时间复杂度都是O(n),但是vector都是连续空间比较方便,deque的第二维内存空间不是连续的,所以在deque中间进行元素的inset或者erase,指令肯定更多,造成元素移动的时候比vector要慢
deque和list比vector容器多出来的增加删除函数接口:push_front() pop_front()

vector和list之间的区别?
数组和链表的区别
数组:增加删除O(n) 查询O(n) 随机访问O(1)
链表:增加删除O(1) 查询(n)

容器适配器

怎么理解适配器?
1.适配器底层没有自己的数据结构,它是另一个容器的封装,它的方法,全部由底层依赖的容器进行实现
2.没有实现自己的迭代器

底层实现
template<typename T,typename Container=deque<T>>
class Stack
{
public:void push(const T &val){con.push_back(val);}void pop(){con.pop_back();}T top()const{return con.back();}
private:Container con;
};

stack

先进后出
push():入栈
pop():出栈
top():查看栈顶元素
empty():判断栈空
size():返回元素个数

queue

先进先出
push():入队
pop():出队
front():查看队头元素
back():查看队尾元素
empty():判断队空
size():返回队列元素个数

priority_queue

底层数据结构:大根堆
push():入队
pop():出队
top():查看队顶元素
empty():判断队空
size():返回元素个数

面试问题:

stack和queue底层依赖deque,为什么不依赖vector?
1.vector的初始内存使用效率太低了!没有deque好(vector需要二倍扩容,deque初始二维就开辟了1024个数组空间)
2.对于queue来说,需要支持尾部插入,头部删除O(1),如果queue依赖vector,其出队效率很低
3.vector需要大片连续内存,而deque只需要分段的内存,当存储大量的数据时,显得deque对于内存的利用率更好一些

priority_queue底层依赖vector,为什么不依赖deque?
底层默认把数据组成一个大根堆结构,在一个内存连续的数组上构建一个大根堆和小根堆(父子节点需要通过下标计算)

关联容器

(1)无序关联容器

底层数据结构:链式哈希表 增删查O(1)

unordered_set

#include<unordered_set>
增加:insert(val)
遍历:iterator自己搜索,调用find成员方法
删除:erase(key) erase(it)
存在:count()

unordered_multiset

#include<unordered_set>
#include<unordered_set>
增加:insert(val)
遍历:iterator自己搜索,调用find成员方法
删除:erase(key) erase(it)
个数:count()

unordered_map

#include<unordered_map>

unordered_multimap

#include<unordered_map>

#include<iostream>
#include<unordered_map>
#include<string> 
using namespace std;
/*map存储的是pair对象 
class pair
{first;second;
}
*/
int main()
{unordered_map<int,string> map;//插入 map.insert(make_pair(1000,"张三"));map.insert({1010,"李四"});map[1020] = "王五";cout<<map.size()<<endl;map.erase(1020);//删除 //查询 方式1 cout<<map[1020]<<endl;//查询 方式2 auto it = map.find(1000);if(it!=map.end()){cout<<" key:"<<it->first<<" value:"<<it->second;}//遍历方式一 for(const pair<int,string> &p:map){cout<<" key:"<<p.first<<" value:"<<p.second;} //遍历方式二 it = map.begin();for(;it!=map.end();it++){cout<<" key:"<<it->first<<" value:"<<it->second;} return 0;
} 

注意:
1.map的operator[]不仅有查询功能,如果key不存在,它会插入一对数据[key,type()]

2.map存储的是pair对象

(2)有序关联容器

底层数据结构:红黑树 增删查 O(log2n) n是底数(树的层数 树的高度)

set

multiset

#include
增加:insert(val)
遍历:iterator自己搜索,调用find成员方法
删除:erase(key) erase(it)

注意自定义类型需要重载运算符

#include<iostream>
#include<set>
#include<map>
#include<string> 
using namespace std;
class Student
{
public:Student(int id,string name):_id(id),_name(name){}//重载小于运算符 bool operator<(const Student &stu)const{return _id<stu._id;}
private:int _id;string _name; friend ostream& operator<<(ostream &out,const Student &stu);
}; 
ostream& operator<<(ostream &out,const Student &stu)
{out<<"id:"<<stu._id<<" name:"<<stu._name<<endl;return out;
}
int main()
{set<Student> set;set.insert(Student(1020,"李四"));set.insert(Student(1000,"张文"));for(auto it=set.begin();it!=set.end();it++){cout<<*it<<endl;}return 0;
} 

map

#include

mutimap

#include

注意使用operator[]需要提供默认参数构造函数

#include<iostream>
#include<set>
#include<map>
#include<string> 
using namespace std;
class Student
{
public:Student(int id=0,string name=""):_id(id),_name(name){}
private:int _id;string _name; friend ostream& operator<<(ostream &out,const Student &stu);
}; 
ostream& operator<<(ostream &out,const Student &stu)
{out<<"id:"<<stu._id<<" name:"<<stu._name<<endl;return out;
}
int main()
{map<int,Student> mp;mp.insert({1000,Student(1000,"张文")});mp.insert({1020,Student(1000,"李广")});mp.insert({1030,Student(1000,"高阳")});cout<<mp[1020]<<endl;//使用[]需要提供默认参数构造函数 (因为可能查询的key不存在,则会构造一个新的对象)auto it = mp.begin();for(;it!=mp.end();it++){cout<<"key:"<<it->first<<" value:"<<it->second;} return 0;
} 

二、迭代器

iterator和const iterator

const_iterator:常量的正向迭代器 只能读不能写
iterator:普通的正向迭代器

两种迭代器其实是继承关系class const_iterator{public:const T& operator*(){//返回常引用 所以不能赋值 return *_ptr;}};class iterator : public const_iterator{public:T& operator*(){//返回普通引用 可以赋值 return *_ptr;}}vector<int> const_iterator it = vec.begin();//子类的值赋值给父类 没毛病

reverse_iterator和const_reverse_iterator

reverse_iterator:普通的反向迭代器
const_reverse_iterator:常量的反向迭代器 只能读不能写

#include<iostream>
#include<vector>
using namespace std;
int main()
{vector<int> vec;for(int i=0;i<20;i++){vec.push_back(i);}//rbegin():返回的是最后一个元素的反向迭代器表示//rend():返回的是首元素前驱位置的迭代器的表示 auto rit = vec.rbegin();for(;rit!=vec.rend();++rit){cout<<*rit<<" ";}return 0;
} 

三、函数对象

(1)什么是函数对象
把有operator()小括号运算符重载函数的对象,称作为函数对象或者称为仿函数
(小括号运算符重载函数一个参数叫一元函数对象,二个参数叫二元函数对象)

C语言实现两数之和

int sum(int a,int b)
{return a+b;
}
int ret = sum(10,20);

C++实现两数之和(函数对象)

class Sum
{
public:operator()(int a,int b){return a+b;}
};
Sum sum;
int ret = sum(10,20);

(2)为什么使用函数对象
假如我们要实现比较两个数的大小,使用C语言实现

template<typename T>
bool greater(T a,T b)
{return a>b;
}
template<typename T>
bool less(T a,T b)
{return a<b;
}
cout<<greater(10,20)<<endl;
cout<<less(10,20)<<endl;

使用函数指针实现

template<typename T>
inline bool mygreater(T a,T b)
{return a>b;
}template<typename T>
inline bool myless(T a,T b)
{return a<b;
}template<typename T,typename Compare>
bool compare(T a,T b,Compare comp)//第三个参数接收函数指针 
{//通过函数指针调用函数,是没有办法内联的,效率很低,因为有函数调用开销 return comp(a,b);
}
int main()
{cout<<compare(10,20,mygreater<int>)<<endl;cout<<compare(10,20,myless<int>)<<endl;return 0;
} 

使用C++函数对象的版本实现

template<typename T>
class mygreater
{
public:bool operator()(T a,T b){return a>b;}
};
template<typename T>
class myless
{
public:bool operator()(T a,T b){return a<b;}
};
template<typename T,typename Func>
bool compare(T a,T b,Func fun)//第三个参数为函数对象 
{return fun(a,b);
}
int main()
{cout<<compare(10,20,mygreater<int>())<<endl;//第三个参数为函数对象 cout<<compare(10,20,myless<int>())<<endl;return 0;
} 

1.通过函数对象调用operator(),可以省略函数的调用开销,比通过函数指针调用函数(不能够inline内联调用)效率高
2.因为函数对象是用类生成的,所以可以添加相关的成员变量,用来记录函数对象使用时的更多信息

(3)STL函数对象的使用
greater:函数对象 从大到小
less:函数对象 从小到大

举例1:priority_queue 模板类原型,第一个参数为类型,第二个参数为容器,第三个参数为函数对象(默认less)
在这里插入图片描述

//默认大根堆 从小到大排序 priority_queue<int> queMax;for(int i=0;i<10;i++){queMax.push(rand()%100+1);}while(!queMax.empty()){cout<<queMax.top()<<" ";queMax.pop(); }//小根堆 从大到小排序 using MinHeap =  priority_queue<int,vector<int>,greater<int>>;MinHeap queMin; for(int i=0;i<10;i++){queMin.push(rand()%100+1);}while(!queMin.empty()){cout<<queMin.top()<<" ";queMin.pop(); }

举例2:set模板类原型,第一个参数是类型,第二个参数是函数对象(默认less),第三个参数是容器空间配置器
在这里插入图片描述

	set<int,greater<int>> set;//小根堆 从大到小排列 for(int i=0;i<10;i++){set.insert(rand()%100);}for(int v:set){cout<<v<<endl;}

四、泛型算法

泛型算法 = template + 迭代器 + 函数对象
特点一:泛型算法的参数接收的都是迭代器
特点二:泛型算法的参数还可以接收函数对象(C函数指针)

绑定器
bindlst:把二元函数对象的operator()(a,b)的第一个形参绑定起来
bind2nd:把二元函数对象的operator()(a,b)的第二个参数绑定起来

sort

sort(vec.begin(),vec.end());//从小到大排序 
sort(vec.begin(),vec.end(),greater<int>());//从大到小排序 

find
遍历查找 O(n)

	auto it1 = find(vec.begin(),vec.end(),43);if(it1!=vec.end()){cout<<"43存在"<<endl;}

binary_search
有序容器二分查找 O(log2n)

	if(binary_search(vec.begin(),vec.end(),21)){cout<<"52存在"<<endl;}

for_each
可以遍历容器的所有元素,可以自行添加合适的函数对象对容器的元素进行过滤

//输出所有偶数 for_each(vec.begin(),vec.end(),[](int val)->void{if(val%2==0){cout<<val<<" ";}});

测试代码:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;int main()
{int arr[] = {12,4,78,9,21,43,56,52,42,31};vector<int> vec(arr,arr+sizeof(arr)/sizeof(arr[0]));for(int v:vec){cout<<v<<" ";} sort(vec.begin(),vec.end());//从小到大排序 for(int v:vec){cout<<v<<" ";} //有序容器二分查找 O(log2n)if(binary_search(vec.begin(),vec.end(),21)){cout<<"52存在"<<endl;}//遍历查找 O(n)auto it1 = find(vec.begin(),vec.end(),43);if(it1!=vec.end()){cout<<"43存在"<<endl;}sort(vec.begin(),vec.end(),greater<int>());//从大到小排序 for(int v:vec){cout<<v<<" ";} //输出所有偶数 for_each(vec.begin(),vec.end(),[](int val)->void{if(val%2==0){cout<<val<<" ";}});} 

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

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

相关文章

Cxx Primer-chap7

类的基本思想是数据抽象和封装&#xff0c;前者强调interface和implement分离&#xff0c;后者在此基础上&#xff0c;强调访问控制符&#xff08;存疑&#xff09;。同时类的实现者和使用者考虑的角度不同&#xff0c;前者考虑实现效率&#xff0c;后者仅需关注功能即可&#…

C++相关概念和易错语法(23)(set、仿函数的应用、pair、multiset)

1.set和map存在的意义 &#xff08;1&#xff09;set和map的底层都是二叉搜索树&#xff0c;可以达到快速排序&#xff08;当我们按照迭代器的顺序来遍历set和map&#xff0c;其实是按照中序来遍历的&#xff0c;是排过序的&#xff09;、去重、搜索的目的。 &#xff08;2&a…

与众不同的社交体验:Facebook的新功能与新变化

在快速变化的社交媒体领域&#xff0c;Facebook不断引入创新功能和变化&#xff0c;以满足用户日益增长的需求&#xff0c;并提供与众不同的社交体验。从增强现实到数据隐私&#xff0c;Facebook的新功能和更新正在塑造一个全新的社交平台。本文将深入探讨这些新功能和变化&…

arm环境下构建Flink的Docker镜像

准备工作 资源准备 按需下载 flink&#xff0c;我的是1.17.2版本。官方说1.13版本之后的安装包兼容了arm架构&#xff0c;所以直接下载就行。 如需要cdc组件&#xff0c;提前下载好。 服务器准备 可在某云上购买arm服务器&#xff0c;2c/4g即可&#xff0c;按量付费。 带宽…

谷粒商城实战笔记-43-前端基础-Vue-使用Vue脚手架进行模块化开发

文章目录 一&#xff0c;Vue的模块化开发1&#xff0c;目录结构2&#xff0c;单文件组件 (SFC)3&#xff0c;模块化路由4&#xff0c;Vuex 模块5&#xff0c;动态组件和异步组件6&#xff0c;抽象和复用7&#xff0c;构建和打包8&#xff0c;测试9&#xff0c;文档和注释10&…

Nginx反向代理概述

正向代理与反向代理概述 正向代理&#xff1a; 定义&#xff1a;正向代理位于客户端和目标服务器之间&#xff0c;客户端的请求首先发送到代理服务器&#xff0c;然后由代理服务器转发到目标服务器&#xff0c;最后将目标服务器的响应返回给客户端。 作用&#xff1a;正向代理…

Linux - 进程的概念、状态、僵尸进程、孤儿进程及进程优先级

目录 进程基本概念 描述进程-PCB task_struct-PCB的一种 task_struct内容分类 查看进程 通过系统目录查看 通过ps命令查看 通过系统调用获取进程的PID和PPID 通过系统调用创建进程- fork初始 fork函数创建子进程 使用if进行分流 Linux进程状态 运行状态-R 浅度睡眠状态-S…

uni-app:踩坑路---关于使用了transform导致fixed定位不生效的问题

前言&#xff1a; 继续记录&#xff0c;在上篇文章中&#xff0c;弹出框遮罩层在ios上没有正确的铺盖全屏&#xff0c;是因为机型的原因&#xff0c;也和我们的代码结构有相关的问题。今天再来展示另外一个奇葩的问题。 这次我使用了在本篇博客中的弹出框组件CustomDialog.vue…

《昇思25天学习打卡营第19天|基于MobileNetv2的垃圾分类》

基于MobileNetv2的垃圾分类 本文档主要介绍垃圾分类代码开发的方法。通过读取本地图像数据作为输入&#xff0c;对图像中的垃圾物体进行检测&#xff0c;并且将检测结果图片保存到文件中。 1、实验目的 了解熟悉垃圾分类应用代码的编写&#xff08;Python语言&#xff09;&a…

【C++】:AVL树的深度解析及其实现

目录 前言一&#xff0c;AVL树的概念二&#xff0c;AVL树节点的定义三&#xff0c;AVL树的插入3.1 第一步3.2 第二步 四&#xff0c;AVL树的旋转4.1 右单旋4.2 左单旋4.3 右左双旋4.4 左右双旋4.5 插入代码的完整实现4.6 旋转总结 五&#xff0c;AVL树的验证六&#xff0c;实现…

插入和选择排序

1.1直接插入排序 void InsertSort(int* a, int n) {for (int i 1; i < n - 1; i) {//i的范围要注意的&#xff0c;防止指针越界int end i;int tmp a[end 1];while (end>0) {if (tmp< a[end]) {a[end 1] a[end];//小于就挪动&#xff0c;虽然会覆盖后面空间的值…

【Linux】通过分配虚拟内存的方式来解决因内存不够而导致部署的项目自动挂掉

多个 jar 包项目部署在同一台服务器上&#xff0c;当服务器配置低&#xff0c;内存不足时&#xff0c;有可能出现 nohup java -jar 启动的进程就莫名其妙挂掉的问题。 解决方式&#xff1a; 第一种方法&#xff1a;进行JVM调优可以改善这种情况&#xff0c;但是项目太多&…

【Android】安卓四大组件之广播知识总结

文章目录 动态注册使用BroadcastReceiver监听Intent广播注册Broadcast Receiver 静态注册自定义广播标准广播发送广播定义广播接收器注册广播接收器 有序广播修改发送方法定义第二个广播接收器注册广播接收器广播截断 使用本地广播实践-强制下线使用ActivityCollector管理所有活…

sql注入 mysql 执行命令 sql注入以及解决的办法

我们以前很可能听过一个词语叫做SQL注入攻击&#xff0c;其是威胁我们系统安全的最危险的因素之一&#xff0c;那么到底什么是SQL注入攻击呢&#xff1f;这里我会用一个最经典最简单的例子来跟大家解释一下&#xff1a; 众所周知&#xff0c;我们的sql语句都是有逻辑的&#xf…

STM32之九:ADC模数转换器

目录 1. 简介 2. ADC 2.1 逐次逼近型寄存器SAR 2.2 ADC转换时间 3 ADC框图 3.1 8 bit ADC0809芯片内部框图 3.2 ADC框图 3.2.1 注入通道和规则通道 3.2.2 单次/连续转换模式 3.2.3 扫描模式 3.2.4 外部触发转换 3.2.5 数据对齐 3.2.6 模拟看门狗 4. 总结和ADC驱…

MYSQL ODBC驱动安装时的注意事项

今天想使用MYSQL的ODBC驱动连接数据库。 安装的时候遇到一个大坑&#xff0c;在这里记录一下。 window 64位的操作&#xff0c;要安装64位驱动&#xff0c;这个大家都知道了。 有以下的问题要注意区别的。 1 、windows是64位的&#xff0c;但是开发软件是32位的。 这个时候…

OpenStack Yoga版安装笔记(七)glance练习补充

1、练习场景说明 在OpenStack Yoga版安装笔记&#xff08;五&#xff09;中&#xff0c;glance已经在controller node虚拟机上安装完成&#xff0c;并且已经成功拍摄了快照。 此时&#xff0c;controller node虚机已经安装了keystone、keystone DB、glance、glance DB、OpenSta…

PCL-基于FPFH的SAC-IA结合ICP的点云配准方法

目录 一、相关方法原理1.凸包方法2.FPFH特征描述3.SAC-IA概述4.ICP概述 二、实验代码三、实验结果 一、相关方法原理 点云是在同一空间参考系下表达目标空间分布和目标表面特性的海量点集合&#xff0c;在获取物体表面每个采样点的空间坐标后&#xff0c;得到的是点的集合&…

构建智能运维系统:创新架构与效率优化

随着信息技术的迅猛发展&#xff0c;企业对于运维效率和服务质量的要求越来越高。智能运维系统的设计和实施&#xff0c;不仅能够提升系统可靠性和响应速度&#xff0c;还能有效降低成本和人力投入。本文将深入探讨智能运维系统的架构设计原则和关键技术&#xff0c;为企业在运…

数据结构重置版(概念篇)

本篇文章是对数据结构的重置&#xff0c;且只涉及概念 顺序表与链表的区别 不同点 顺序表 链表 存储空间上 物理上一定连续 逻辑上连续&#xff0c;但物理上不一定连续…