STL线程各种容器对比、数组和vector如何互相转换

STL

  • vector如何扩展内存和释放内存
  • STL中各种容器对比
  • STL中的swap函数
  • STL中哈希表扩容
  • STL迭代器失效的情况和原因
  • vector删除元素后如何避免当前迭代器会失效
  • vector的iterator和const_iterator和const iterator

vector如何扩展内存和释放内存

  • 内存增长

  • 1.5还是2倍扩容

    gcc 二倍扩容,VS2015 1.5倍扩容

  • 内存释放

size_type、size_t、int

size_type

STL容器中的一个成员变量,是一种用以保存不同容器的任意大小的类型,它与size_t一样,目的都是为了使用起来与具体机器无关。标准库类型将size_type定义为unsigned类型,比如string类的string::size_type 就是一个代表string抽象长度的无符号整型。也就是说,string::size_type从本质上来说,是一个整型数。关键是由于机器的环境,它的长度有可能不同。

size_t

size_t是一些C/C++标准在stddef.h中定义的。这个类型足以用来表示对象的大小。size_t的真实类型与操作系统有关。

在32位机器中被普遍定义为:

typedef unsigned int size_t;

而在64位机器中被定义为:

typedef unsigned long size_t;

size_t在32位架构上是4字节,在64位架构上是8字节,在不同架构上进行编译时需要注意这个问题。而int在不同架构下都是4字节,与size_t不同;且int为带符号数,size_t为无符号数。

为什么有时候不用int,而是用size_type或者size_t:

与int固定四个字节不同有所不同,size_t的取值范围是目标平台下最大可能的数组尺寸,一些平台下size_t的范围小于int的正数范围,又或者大于unsigned int. 使用Int既有可能浪费,又有可能范围不够大。

注意:

string str="123";
int a=2;
cout<<a-str.size()<<endl;

这段代码的输出并不是-1,在我64位win10系统中的输出是:4294967295,这是因为str.size()返回值是size_type一个无符号整数,而编译器在int与size_type做减法时,都视为了无符号整数。

  • 我们在使用 string::find的函数的时候,它返回的类型就是 string::size_type类型。而当find找不到所要找的字符的时候,它返回的是 npos的值,这个值是与size_type相关的。假如,你是用 string s; int rc = s.find(…); 然后判断,if ( rc == string::npos ) 这样在不同的机器平台上表现就不一样了。如果,你的平台的string::size_type的长度正好和int相匹配,那么这个判断会侥幸正确。但换成另外的平台,有可能 string::size_type的类型是64位长度的,那么判断就完全不正确了。 所以,正确的应该是: string::size_type rc = s.find(…); 这个时候使用 if ( rc == string::npos )就回正确了。

STL是线程安全的吗

  • 多个线程可以同时读取一个容器中的内容。 即此时多个线程调用 容器的不涉及到写的接口都可以。
  • 对不同容器的多个写入者是安全的。即多个线程对不同容器的同时写入合法。但不能同时又读又写同一容器对象的。

各种容器对比

容器底层数据结构时间复杂度有无序可不可重复其他
array数组随机读改 O(1)无序可重复支持快速随机访问
vector数组随机读改、尾部插入、尾部删除 O(1)、头部插入、头部删除 O(n)无序可重复支持快速随机访问
list双向链表插入、删除 O(1)、随机读改 O(n)无序可重复支持快速增删
deque双端队列头尾插入、头尾删除 O(1)无序可重复一个中央控制器 + 多个缓冲区,支持首尾快速增删,支持随机访问
stackdeque / list顶部插入、顶部删除 O(1)无序可重复deque 或 list 封闭头端开口,不用 vector 的原因应该是容量大小有限制,扩容耗时
queuedeque / list尾部插入、头部删除 O(1)无序可重复deque 或 list 封闭头端开口,不用 vector 的原因应该是容量大小有限制,扩容耗时
priority_queuevector + max - heap插入、删除 O(log2n)有序可重复vector容器 + heap处理规则
set红黑树插入、删除、查找 O(log2n)有序不可重复
multiset红黑树插入、删除、查找 O(log2n)有序可重复
map红黑树插入、删除、查找 O(log2n)有序不可重复
multimap红黑树插入、删除、查找 O(log2n)有序可重复

数组和vector如何互相转换

STL中的swap函数

  • 除了数组,其他容器在交换后本质上是将内存地址进行了交换,而元素本身在内存中的位置是没有变化
  • swap在交换的时候并不是完全将2个容器的元素互换,而是交换了2个容器内的内存地址。

STL中的哈希表扩容

  • 这里需要知道STL中的swap底层,其实扩容也是vector扩容
    • 创建一个新桶,该桶是原来桶两倍大最接近的质数(判断n是不是质数的方法:用n除2到sqrt(n)范围内的数) ;
    • 将原来桶里的数通过指针的转换,插入到新桶中(注意STL这里做的很精细,没有直接将数据从旧桶遍历拷贝数据插入到新桶,而是通过指针转换两个桶的地址)
    • 通过swap函数将新桶和旧桶交换,销毁新桶

影响哈希表性能的因素

  • 散列函数,一个好的散列函数的值应尽可能平均分布。

  • 处理冲突方法。

  • 负载因子的大小。太大不一定就好,而且浪费空间严重,负载因子和散列函数是联动的。

map和unordered_map的区别

  • map是按照operator<比较判断元素是否相同,以及比较元素的大小,然后选择合适的位置插入到树中。所以,如果对map进行遍历(中序遍历)的话,输出的结果是有序的。顺序就是按照operator< 定义的大小排序。
  • map 的key需要定义operator< 。 而unordered_map需要定义hash_value函数并且重载operator ==。
  • unordered_map比map要快一些

map自定义键的方式

1、重载operator<

class Person {
public:int age;
public:Person(int _age = 10) {age = _age;}bool operator<(const Person& p) const {return age < p.age;}
};int main(int argc, char** argv) {map<Person, int> mp;Person p1;Person p2(20);mp[p1]  = 1;mp[p2] = 2;return 0;
}

2、function

利用function对普通的比较函数进行封装

class Person {
public:int age;
public:Person(int _age = 10) {age = _age;}
};
// 普通函数
bool cmp(const Person& p1, const Person& p2) {return p1.age < p2.age;
}int main(int argc, char** argv) {map<Person, int, function<bool(const Person&, const Person&)>> mp(cmp); // function进行封装Person p1;Person p2(20);mp[p1]  = 1;mp[p2] = 2;return 0;
}

3、重载operator()的类

将比较函数打包成可以直接调用的类

#include <bits/stdc++.h>
using namespace std;class Person {
public:int age;
public:Person(int _age = 10) {age = _age;}
};struct Compare
{bool operator()(const Person& p1, const Person& p2) const {return p1.age < p2.age;}
};int main(int argc, char** argv) {map<Person, int, Compare> mp;Person p1;Person p2(20);mp[p1]  = 1;mp[p2] = 2;return 0;
}

4、less函数的模板定制

前面几种方法,无论我们怎么定义,在声明group的时候都需要指定第3个参数,有什么方法是需要指定的呢?当然有啦。

通过map的定义可知,第三个参数的默认值是less。显而易见,less属于模板类。那么,我们可以对它进行模板定制,如下所示。

#include <bits/stdc++.h>
using namespace std;class Person {
public:int age;
public:Person(int _age = 10) {age = _age;}
};template<>
struct std::less<Person>
{
public:bool operator()(const Person& p1, const Person& p2) const {return p1.age < p2.age;}
};int main(int argc, char** argv) {map<Person, int> mp;Person p1;Person p2(20);mp[p1]  = 1;mp[p2] = 2;return 0;
}

STL中的迭代器是什么

  • 迭代器是一种抽象的设计概念,是一种行为类似于指针的对象,指针最常见的行为就是解引用和成员访问。因此迭代器最重要的工作就是重载operator*和operator->。迭代器使得算法独立于使用的容器类型,使我们能够依序访问某个容器所含的各个元素,而又无需暴露该容器的内部表述方式。

  • 迭代器使用类模板来实现。

迭代器相应型别:迭代器所指之物的型别。可以通过函数模板的参数推导机制来实现。

template <class I, class T>
void func_imp1(I iter, T t)
{T tmp;	// 这里T就是所指之物的型别,可用于变量声明之 用// ...
};template <class I>
inline
void func(I iter)
{func_imp1(iter, *iter);	// func的全部工作转移到func_imp1
}int main() {int i;func(&i);return 0;
}

Traits迭代器型别:

用于萃取迭代器的5种型别 value type、difference type、pointer、reference、iterator catagory

  • value type

    • 迭代器所指对象的型别
  • difference type

    • 两个迭代器之间的距离
  • pointer type

    • 一个pointer,指向迭代器所指之物
  • reference type

    • 函数如果想传回一个左值,都是以 by reference 的方式进行。
    • 如果 p 是一个mutable iterator时,如果其 value type 是 T,那么 *p 的型别应该是一个 T&。
    • 如果 p 是一个const iterator时,如果其 value type 是 T,那么 *p 的型别应该是一个 const T&。
    • 这里的 *p指的就是 reference type。
  • iterator catagory

    • 输入迭代器:来自容器的信息被视为输入,对输入迭代器解引用将使程序能够读取容器中的值,但不一定能让程序修改值。
    • 输出迭代器:将信息从程序传输给容器的迭代器,因此程序的输出就是容器的输入,解引用让程序能够修改容器值,而不能读取。
    • 正向迭代器:只使用++运算符来遍历容器。
    • 双向迭代器:可以++也可以–。
    • 随机访问迭代器:具有双向迭代器的所有特性,同时添加了支持随机访问的操作。

std::iterator

STL提供了一个 iterators class 如下,如果每个新设计的迭代器都继承自它,就可保证符合STL所需之规范。iterator class 不含任何成员,纯粹只是型别定义,所以继承它不会招致任何额外负担。

template <class Category,class T,class Distance = ptrdiff_t,class Pointer = T*,class Reference = T&>
struct iterator {typedef Category  iterator_category;typedef T		  value_type;typedef Distance  difference_type;typedef Pointer   pointer;typedef Reference reference;
};

怎么设计一个迭代器

iterator设计:

  • 首先定义5个迭代器类型,这些 classes 只作为标记用,所以不需要任何成员。用于针对不同的迭代器类型对某些函数进行重载。

    struct input_iterator_tag {};
    struct output_iterator_tag {};
    struct forward_iterator_tag : public input_iterator_tag {};
    struct bidirectional_iterator_tag : public forward_iterator_tag {};
    struct random_access_iterator_tag : public bidirectional_iterator_tag {};
    
  • 定义一个迭代器基类

    template <class Category,class T,class Distance = ptrdiff_t,class Pointer = T*,class Reference = T&>
    struct iterator {typedef Category iterator_category;typedef T		 value_type;typedef Distance difference_type;typedef Pointer pointer;typedef Reference reference;
    };
    
  • 定义 iterator_traits 类

    template <class Iterator>
    struct iterator_traits {typedef typename Iterator::iterator_category iterator_category;typedef typename Iterator::value_type 		 value_type;typedef typename Iterator::difference_type 	 difference_type;typedef typename Iterator::pointer			 pointer;typedef typename Iterator::reference 		 reference;
    }
    
  • 针对原生指针 pointer 和 const-pointer 设计偏特化版的 iterator_traits 类

    // pointer指针
    template <class Iterator>
    struct iterator_traits<T*> {typedef typename random_access_iterator_tag  iterator_category;typedef typename T					 		 value_type;typedef typename ptrdiff_t 	 				 difference_type;typedef typename T*							 pointer;typedef typename T&							 reference;
    };
    // const-pointer指针
    template <class Iterator>
    struct iterator_traits<const T*> {typedef typename random_access_iterator_tag  iterator_category;typedef typename T					 		 value_type;typedef typename ptrdiff_t 	 				 difference_type;typedef typename T*							 pointer;typedef typename T&							 reference;
    };
    
  • 这个模板函数可以很方便地决定某个迭代器的类型(category)

    template <class Iterator>
    inline typename iterator_traits<Iterator>::iterator_category
    iterator_category(const Iterator&){typedef typename iterator_traits<Iterator>::iterator_category category;return category();
    };
    
  • 这个模板函数可以很方便地决定某个迭代器的distance type

    template <class Iterator>
    inline typename iterator_traits<Iterator>::difference_type*
    distance_type(const Iterator&){return static_cast<typename iterator_traits<Iterator>::difference_type*>(0);
    };
    
  • 这个模板函数可以很方便地决定某个迭代器的 value type

    template <class Iterator>
    inline typename iterator_traits<Iterator>::value_type*
    value_type(const Iterator&){return static_cast<typename iterator_traits<Iterator>::value_type*>(0);
    };
    

vector删除元素如何避免当前迭代器会失效

**迭代器失效就是指:迭代器指向的位置在该操作的前后不再相同。**删除时,将当前的迭代器存起来。

STL迭代器失效的情况和原因

迭代器失效分三种情况考虑,也是分三种数据结构考虑,分别为数组型,链表型,树型数据结构。

  • 数组型数据结构
    • 该数据结构的元素是分配在连续的内存中
    • insert和erase操作,都会使得删除点和插入点之后的元素挪位置,所以,插入点和删除掉之后的迭代器全部失效,也就是说insert(*iter)(或erase(*iter)),然后在iter++,是没有意义的。
    • 解决方法:erase(*iter)的返回值是下一个有效迭代器的值。 iter = cont.erase(iter);
//不要直接在循环条件中写++iter
for (iter = cont.begin(); iter != cont.end();)
{(*it)->doSomething();if (shouldDelete(*iter))iter = cont.erase(iter);  //erase删除元素,返回下一个迭代器else++iter;
}
  • 链表型数据结构

    • 对于list型的数据结构,使用了不连续分配的内存
    • 插入不会使得任何迭代器失效
    • 删除运算使指向删除位置的迭代器失效,但是不会失效其他迭代器.
    • 解决办法两种,erase(*iter)会返回下一个有效迭代器的值,或者erase(iter++).
  • 树形数据结构

    • 使用红黑树来存储数据
    • 插入不会使得任何迭代器失效
    • 删除运算使指向删除位置的迭代器失效,但是不会失效其他迭代器.
    • erase迭代器只是被删元素的迭代器失效,但是返回值为void,所以要采用erase(iter++)的方式删除迭代器。

注意 :经过erase(iter)之后的迭代器完全失效,该迭代器iter不能参与任何运算,包括iter++,*ite

针对不同容器,具体情况如下:

向容器添加元素

  • 如果容器是vector或者string,且存储空间被重新分配,那么迭代器、指针和引用会失效。如果存储空间未重新分配,那么插入点之前的迭代器、指针和引用未失效,插入点之后的迭代器、指针和引用失效。
  • 如果是deque,插入到首尾位置以外的任何位置都会导致迭代器、指针和引用失效。如果插入到首尾,迭代器会失效,但指向存在元素的引用或指针不会失效。
  • 对于list和forward_list,指向容器的迭代器、指针和引用仍有效。

从容器删除元素

  • 对于list和forward_list,指向容器其他位置的迭代器、引用和指针仍有效
  • 对于deque,如果在首尾之外的任何位置删除元素,那么指向被删除元素外其他元素的迭代器、引用和指针也会失效。如果是删除deque的尾元素,那么尾迭代器失效,其他迭代器、引用和指针不受影响。如果删除deque的首元素,那么首迭代器失效,其他迭代器、引用和指针不受影响。
  • 对于vector和string,与插入操作迭代器失效与否是一样的

vector的iterator和const_iterator和const iterator

  • 三种的区别
    • iterator,可遍历,可改变所指元素
    • const_iterator,可遍历,不可改变所指元素
    • const iterator,不可遍历,可改变所指元素
  • const_iterator转iterator,iterator不能转const_iterator
    • const_iterator 主要是 在容器被定义成常量、或者非常量容器但不想改变元素值的情况 下使用的,而且容器被定义成常量之后,它返回的迭代器只能是const_iterator
    • 有些容器成员函数只接受iterator作为参数,而不是const_iterator。那么,如果你只有一const_iterator,而你要在它所指向的容器位置上插入新元素呢?
      • const_iterator转iterator
      • 强制转换的函数会报错,只能通过 advance(a, distance(a, b)); 其中,distance用于取得两个迭代器之间的距离,advance用于将一个迭代器移动指定的距离
      • 如果a是iterator,b是const_iterator,distance会报错,可以显式的指明distance调用的模板参数类型,从而避免编译器自己得出它们的类型
typedef deque<int> IntDeque;
typedef IntDeque::iterator iter;
typedef IntDeque::const_iterator ConstIter;
IntDeque d;
ConstIter ci;
Iter i(d.begin());
advance(i,distance<ConstIter>(i,ci)); 

STL的 sort 函数

sort 算法在数据量大的时候采用 快排,分段递归排序,一旦分段后的数据量小于某个门槛 16,改用 插入排序,,如果递归层次过深,还会改用 堆排

具体实现是这样的

sort(first, last);

首先计算 last - first 的长度,通过 log(last - first) (2^k <= n 的最大 k ) 计算最大递归深度 depth_limit,如果元素个数小于 16 ,执行插入排序;否则 判断是否到达最大递归深度,如果到达最大递归深度,执行堆排,否则进行快排

在最后结束后,[first, last) 内会有很多“元素个数少于16”的子序列,每个子系列都有相当程度的排序,但尚未完全排序,此时再进行一次插入排序即可。

其中,快排采用三点中值方案来确定枢轴。

插入排序在数据量小时,不像其他复杂算法那样有着诸如递归调用等操作带来的额外负担,所以排序效果不错,且当序列接近有序时,插入排序效率也很不错。

List的sort原理

  • 在该排序算法的实现过程中,定义了一个类似于搬运作用的链表carry和具有中转站作用的链表counter,这里首先对counter[i]里面存储数据的规则进行分析;counter[i]里面最多存储数据个数为2^(i+1),若存储数据超过该数字,则向相邻高位进位,即把counter[i]链表里的内容都合并到counter[i+1]链表。carry负责取出原始链表的头一个数据节点和交换数据中转站作用

  • 思想是:从链表中取1个节点,放入counter[0],再取1个节点,放入counter[0],此时counter[0]装满了,会转移到counter[1],然后counter[0]再存2个节点,转移到counter[1],此时counter[1]满了。就转移到counter[2],…,依此类推,合并几个counter,因为每一个counter里都是有序的,所以思想是归并排序

STL的allocator

  1. 通常 C++ 的内存配置操作和释放操作是这样的

    class Foo {...};
    Foo *pf = new Foo;	// 配置内存,然后构造对象
    delete pf;		    // 将对象析构,然后释放内存
    

    这其中的 new 包含两阶段操作:

    ​ (1) 调用new配置内存,(2) 调用Foo:Foo() 构造对象内容;

    delete 也包含两阶段操作:

    ​ (1) 调用Foo:~Foo()将对象析构,(2) 调用 delete 释放内存

  2. 为精密分工,STL allocator 将这两阶段操作区分开:

    • __内存配置__操作由 alloc:allocate() 负责;
    • __内存释放__操作由 alloc:deallocate() 负责;
    • __对象构造__操作由 construct() 负责;
    • __对象析构__操作由 destroy() 负责
  3. construct() 接受一个指针p和一个初值value,将初值设定到指针所指的空间上

  4. destroy() 有两个版本,第一个版本接受一个指针,然后将该指针所指之物析构

第二个版本接受 first 和 last 两个迭代器,将 [ first, last ) 区间内的对象析构掉

destroy_construct
  1. SGI 设计了双层级内存配置器,第一级配置器直接使用malloc()和free(),第二级配置器则视情况采用不同的策略:

    1. 当配置区块超过128 bytes 时,视之为“足够大”,便调用第一级配置器;

      1. 第一级配置器的 allocate() 和 realloc() 都是在调用 malloc() 和 realloc() 不成功后,改调用 oom_malloc() 和 oom_realloc() 。后两者都有内循环,不断调用“内存不足处理例程”,期望在某次调用后,获得足够的内存而圆满完成任务。但如果 “内存不足处理例程” 并未被客端设定, oom_malloc() 和 oom_realloc() 便老实不客气地调用 __THROW_BAD_ALLOC,丢出 bad_alloc异常信息,或利用 exit(1)硬生生地中止程序。
    2. 当配置区块小于 128 bytes时,视之为“过小”,为了避免太多小额区块造成内存的碎片以及降低额外负担(比如分配一个很小的块,但系统需要内存去记录这个块的大小,那么这个块越小,因为记录的内存大小固定,所以额外负担所占比例愈大),便采用复杂的memory pool 整理方式,而不再求助于第一级配置器。

      alloc
      1. 内存池管理,又叫次层配置:每次配置一大块内存,并维护对应之自由链表 free-list 。下次若再有相同大小的内存需求,就直接从 free-list 中拨出。如果客端释还小额区块,就由配置器回收到 free-list 中(配置器除了负责配置,还负责回收)。为了方便管理,SGI第二级配置器会主动将任何小额区块内存需求量上调至 8 的倍数(例如客端要求30bytes,就自动调整为 32 bytes),并维护 16 个 free-list,各自管理大小分别为8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128 bytes的小额区块。

      2. 首先判断区块大小,大于128 bytes 就调用第一级配置器,小于 128 bytes 就检查对应的 free-list,如果free-list有可用的区块,就直接拿来用,如果没有,就调用refill() 准备从内存池为free-list重新填充空间。

        freelist1
      3. 释放操作,首先判断区块大小,大于 128 bytes 就调用第一级配置器的 deallocate() 函数释放,小于 128 bytes 就找到对应的 free-list,将区块回收。

        freelist2
      4. 重新填充:当发现free-list中没有可用区块了时,就调用 refill() ,准备为 free-list 重新填充空间。新的空间将取自内存池。缺省取得20个新节点,但万一内存池空间不足,获得的节点数可能小于20。如果内存池空间不足,就调用配置heap空间,用来补充内存池,具体配置方式如下:

        memory

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

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

相关文章

微信小程序ibeacon搜索功能制作

以下是一个完整的微信小程序代码示例&#xff0c;演示如何实现iBeacon搜索功能&#xff1a; // 在小程序页面中的js文件中编写代码Page({data: {beacons: [] // 存储搜索到的iBeacon设备信息},onReady() {// 初始化iBeaconwx.startBeaconDiscovery({uuids: [你的UUID], // 替换…

数据结构和算法(1):开始

算法概述 所谓算法&#xff0c;即特定计算模型下&#xff0c;旨在解决特定问题的指令序列 输入 待处理的信息&#xff08;问题&#xff09; 输出 经处理的信息&#xff08;答案&#xff09; 正确性 的确可以解决指定的问题 确定性 任一算法都可以描述为一个由基本操作组成的序…

用户促活留存新方式——在APP中嵌入小游戏

随着APP同类产品的不断出现&#xff0c;APP开发者们面临着激烈的竞争&#xff0c;很多APP下载后被新的APP取代&#xff0c;获客成本越来越高。同时开发者还会面临用户粘性差、忠诚度低、用完即走、留存困难&#xff0c;商业化价值被大大缩减。 在APP中植入小游戏来提高用户活跃…

Vue——vue3+element plus实现多选表格使用ajax发送id数组

代码来源: Vue 3结合element plus&#xff08;问题总结二&#xff09;之 table组件实现多选和清除选中&#xff08;在vue3中获取ref 的Dom&#xff09;_multipletableref.value.togglerowselection()打印出来的是u_子时不睡的博客-CSDN博客 前言 为了实现批量删除功能的功能…

【Python爬虫实战】爬虫封你ip就不会了?ip代理池安排上

前言 在进行网络爬取时&#xff0c;使用代理是经常遇到的问题。由于某些网站的限制&#xff0c;我们可能会被封禁或者频繁访问时会遇到访问速度变慢等问题。因此&#xff0c;我们需要使用代理池来避免这些问题。本文将为大家介绍如何使用IP代理池进行爬虫&#xff0c;并带有代…

C语言练习:输入日期输出该日期为当年第几天

用scanf()输入某年某月某日&#xff0c;判断这一天是这一年的第几天。以3月5日为例&#xff0c;应该先把前两个月的加起来&#xff0c;然后再加上5天即本年的第几天&#xff0c;特殊情况&#xff0c;闰年且输入月份≥3时需考虑多加一天。注&#xff1a;判断年份是否为闰年的方法…

【C刷题】day1

一、选择题 1.正确的输出结果是 int x5,y7; void swap() { int z; zx; xy; yz; } int main() { int x3,y8; swap(); printf("%d,%d\n"&#xff0c;x, y); return 0; } 【答案】&#xff1a; 3&#xff0c;8 【解析】&#xff1a; 考点&#xff1a; &#xff…

Matlab如何导入Excel数据并进行FFT变换

如果你发现某段信号里面有干扰&#xff0c;想要分析这段信号里面的频率成分&#xff0c;就可以使用matlab导入Excel数据后进行快速傅里叶变换&#xff08;fft&#xff09;。 先直接上使用方法&#xff0c;后面再补充理论知识。 可以通过串口将需要分析的数据发送到串口助手&a…

postgresql-窗口函数

postgresql-窗口函数 窗口函数简介窗口函数的定义分区排序选项窗口选项 窗口函数简介 包括 AVG、COUNT、MAX、MIN、SUM 以及 STRING_AGG。聚合函数的作用是针对一组数据行进行运算&#xff0c;并且返回一条汇总结果 分析的窗口函数&#xff08;Window Function&#xff09;。 …

投稿指南【NO.12_8】【极易投中】核心期刊投稿(组合机床与自动化加工技术)

近期有不少同学咨询投稿期刊的问题&#xff0c;大部分院校的研究生都有发学术论文的要求&#xff0c;少部分要求高的甚至需要SCI或者多篇核心期刊论文才可以毕业&#xff0c;但是核心期刊要求论文质量高且审稿周期长&#xff0c;所以本博客梳理一些计算机特别是人工智能相关的期…

单相并联下垂控原理

Part1 上述有个核心的piont是等效阻抗上的电压一般时很小的&#xff0c;这就导致逆变器输出电压矢量E和负载电压矢量UL之间的夹角很小 》基于上述的结论有助于我们去简化下垂控制的公式&#xff01;&#xff01;&#xff01; Part2 上述得到负载电流&#xff0c;接着乘以负载…

mac 查看端口占用

sudo lsof -i tcp:port # 示例 sudo lsof -i tcp:8080 杀死进程 sudo kill -9 PID # 示例 sudo kill -9 8080

基于奇偶模的跨线桥(crossover)分析

文章目录 1、ADS建模2、奇偶模分析2.1 Port1→Port2传输特性2.1.1奇模分析2.1.2偶模分析 2.2 Port1→Port4传输特性 附&#xff1a;正交混合网络的奇偶模分析1、 Port1→Port21.1奇模分析1.2Port1→Port2偶模分析1.3 奇模传输与偶模传输相位关系![在这里插入图片描述](https://…

蚂蚁开源编程大模型,提高开发效率

据悉&#xff0c;日前蚂蚁集团首次开源了代码大模型 CodeFuse&#xff0c;而这是蚂蚁自研的代码生成专属大模型&#xff0c;可以根据开发者的输入提供智能建议和实时支持&#xff0c;帮助开发者自动生成代码、自动增加注释、自动生成测试用例、修复和优化代码等kslouitusrtdf。…

rrweb入门

rrweb 背景 rrweb 是 record and replay the web&#xff0c;是当下很流行的一个录制屏幕的开源库。与我们传统认知的录屏方式&#xff08;如 WebRTC&#xff09;不同的是&#xff0c;rrweb 录制的不是真正的视频流&#xff0c;而是一个记录页面 DOM 变化的 JSON 数组&#x…

zookeeper没有.log日志,只有.out日志

zookeeper没有.log日志&#xff0c;只有.out日志 背景&#xff1a;发现zookeeper没有.log日志&#xff0c;只有.out日志 发现在logs目录下&#xff0c;只有.out文件&#xff0c;且每次重启zk&#xff0c;.out日志都会被覆盖写 为了有完整的log日志&#xff0c;需要如下参数 1…

精品基于SpringCloud实现的高校招生信息管理系统-微服务-分布式

《[含文档PPT源码等]精品基于SpringCloud实现的高校招生信息管理系统-微服务-分布式》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程等 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;Java 框架&#xff1a;springcloud JDK版本&#x…

C++:vector

目录 一、关于vector 二、vector的相关函数 三、相关函数的使用 ①构造函数 ②size ③[] ​编辑 ④push_back ⑤迭代器iterator ⑥reserve ⑦resize ⑧find ⑨insert ⑩erase ⑪sort 一、关于vector vector比较像数组 观察可知&#xff0c;vector有两个模板参数…

计算机图形学环境配置java3D

计算机图形学环境配置java3D JDK18&#xff08;或者一些版本都无法支持Applet类&#xff09;idea配置导入java3D的jar包测试代码&#xff1a;运行效果&#xff1a; java3Dwindows64位下载 这个是默认到下图路径中&#xff1a;&#xff08;记住这个路径&#xff0c;待会要导入ja…

选择 Guava EventBus 还是 Spring Framework ApplicationEvent

文章首发地址 Spring Framework ApplicationEvent Spring Framework 的 ApplicationEvent 是 Spring 框架提供的一种事件机制&#xff0c;用于实现发布和订阅事件的功能。它基于观察者模式&#xff0c;允许应用程序内的组件之间进行松耦合的通信。 下面是关于 Spring Frame…