STL标准库与泛型编程(侯捷)笔记3

STL标准库与泛型编程(侯捷)

本文是学习笔记,仅供个人学习使用。如有侵权,请联系删除。

参考链接

Youbute: 侯捷-STL标准库与泛型编程

B站: 侯捷 - STL

Github:STL源码剖析中源码 https://github.com/SilverMaple/STLSourceCodeNote/tree/master

Github:课程ppt和源码 https://github.com/ZachL1/Bilibili-plus

文章目录

  • STL标准库与泛型编程(侯捷)
    • 16 vector深度探索
    • 17 array、forward list深度探索
    • 18 deque、queue和 stack深度探索(上)
      • 容器deque
    • 19 deque、queue和 stack深度探索(下)
      • 容器queue
      • 容器stack
      • queue和stack,关于其iterator和底层结构
    • 后记

介绍vector, array, deque, queue, stack的底层实现

16 vector深度探索

Vector将元素复制到内部的dynamic array中。元素之间总是存在一定的顺序,所以vector是一种有序集合(ordered collection)。 Vector支持随机访问,因此只要知道位置,你可以在常量时间内访问任何一个元素。 Vector提供随机访问迭代器,所以适用于任何STL算法。

如果你在末端附加或删除元素,vector的效率相当好。但如果你在前端或中段安插或删除元素,效率就不怎么样了,因为作用点之后的每一个元素都必须移到另一位置,而每一次移动都得调用assignment操作符。

Vector是动态数组,它会进行扩充,但不是原地扩充,而是当数组空间用完时,它会在某个地方重新分配内存空间(原来的两倍大小),再把先前的内容搬过去。

vector底部有三个指针,start, finish, end_of_storage

在C++中,std::vector 是一个动态数组,它的底层通常包含三个指针成员:startfinishend_of_storage

  1. start: 这是指向数组的第一个元素的指针,表示 vector 的起始位置。

  2. finish: 这是指向数组最后一个元素的下一个位置的指针,表示 vector 当前存储的元素范围结束位置。注意,finish 指向的位置是当前存储元素的末尾的下一个位置,而不是最后一个元素的位置。

  3. end_of_storage: 这是指向 vector 内存空间的末尾的下一个位置的指针。当 vector 的元素数量接近其容量时,end_of_storage 可能指向当前分配内存的末尾。如果要添加更多的元素导致超过当前分配的内存空间,vector 可能需要重新分配更大的内存块,然后 end_of_storage 会被更新为新的内存块的末尾。

这些指针的作用是帮助 vector 进行动态内存管理。startfinish 之间的部分是当前 vector 存储的元素,而 finishend_of_storage 之间的部分是 vector 预分配但尚未使用的内存空间。当 vector 的元素数量增加时,它可能需要重新分配内存,然后更新 end_of_storage 指针,以确保有足够的空间来容纳更多的元素。

在这里插入图片描述

现在看看两倍空间增长是怎么做的

下面是push_back的实现,当前分配的空间用完的时候,会调用insert_aux函数

在这里插入图片描述

insert_aux关于空间两倍增长的部分如下图所示

const size_type len = old_size != 0 ? 2 * old_size : 1;

下面的try catch里面就是具体的从旧位置把元素拷贝到新位置的源代码,分别是:把原vector的内容拷贝到新vector,然后为新元素赋值,新的finish指针后移,如果有insert函数,还需要把insert后面的元素复制过来。

后面还会把原来旧的vector空间释放掉

在这里插入图片描述

vector’s iterator

list的迭代器设计为一个class,这里vector的迭代器就是一个指针T *, 然后借助前面介绍的iterator_traits的偏特化(范围的偏特化,从接收T变成接收指针T *),会把associated types里面的 value_type直接指定为T,而不是基于类的迭代器的I::value_type。下图是GNU C++2.9版本的内容

在这里插入图片描述

下面是对GNU C++4.9版本的vector的介绍:多了几个类,但是izeof(vector<T>)还是12B,因为vector继承自_Vector_base, 它里面有一个_Vector_impl的成员,它里面的data是三个指针,在32位电脑里面一个指针是4B,因此在32位电脑上vector的大小是12B。

在这里插入图片描述

GNU C++4.9版本的vector的iterator呢?

下图所示的设计很复杂,经过层层推导,可以看到_Iterator _M_current变量的类型也是_Tp*即上面GNU C++2.9版本的T*类型。

在这里插入图片描述

而且,GNU C++4.9版本的vector的iterator不再是G++2.9版本的指针T*,而是vector<T>::iterator,如下图箭头所指。

在这里插入图片描述

17 array、forward list深度探索

容器array

TR1:C++ TR1(Technical Report 1,技术报告 1)是一个介于 C++03 标准和 C++11 标准之间的阶段性技术报告,旨在为 C++ 标准库引入新功能和库组件提供一种机制。TR1 提供了一些 C++ 标准库的扩展,以及一些新的库组件,作为对 C++03 标准库的增强。

TR1 中的一些建议和组件后来被纳入 C++11 标准,成为了正式的 C++ 标准库的一部分。C++11 标准以及之后的版本中包括了 TR1 中的一些组件,例如 <memory>, <functional>, <random>, <tuple> 等。

这里介绍TR1版本的array实现

在这里插入图片描述

array的用法,需要指定array的大小

array<int, 10> myArray;
auto ite = myArray.begin();
ite += 3;
cout << *ite;

array的实现中没有构造函数和析构函数,GNU C++(g++) 2.9版本中直接拿原生指针当作迭代器, g++2.9版本的vector也是这种实现。

GNU C++ 4.9版本的array

在这里插入图片描述

容器forward_list

单向链表,下面的slide配合list学习。

std::forward_list 是 C++ 标准模板库(STL)中的一种单向链表容器。与 std::list 不同,std::forward_list 是一个单向链表,每个元素只保存指向下一个元素的指针,而不保存指向前一个元素的指针。

以下是一些 std::forward_list 的主要特点和操作:

特点:

  1. 单向链表: std::forward_list 是一个单向链表,每个元素只有指向下一个元素的指针。
  2. 没有 size() 函数: 由于是单向链表,std::forward_list 没有提供直接获取元素个数的 size() 函数。获取元素个数需要遍历整个链表。
  3. 高效插入和删除: 在链表中间插入或删除元素的操作比在其他序列容器中更加高效。
  4. 不支持随机访问: 由于是单向链表,std::forward_list 不支持通过索引直接访问元素。

在这里插入图片描述

18 deque、queue和 stack深度探索(上)

容器deque

std::deque(双端队列,deque 意为 double-ended queue)是 C++ 标准模板库(STL)中的一个容器,它提供了动态数组的功能,允许在两端进行高效的插入和删除操作。以下是关于 std::deque 的一些主要特点和概念:

  1. 双端操作: std::deque 允许在队列的两端(前端和后端)进行高效的插入和删除操作,而不仅仅是在尾部。

  2. 动态数组: std::deque 的内部结构通常是由多个固定大小的块组成的,每个块中存储一定数量的元素。这种结构允许在两端执行常数时间的插入和删除操作,而不需要像动态数组那样移动大量元素。

  3. 迭代器: std::deque 提供随机访问迭代器,可以在常数时间内对其元素进行随机访问。这使得 std::deque 在许多算法和操作中能够高效地使用。

  4. 不要求连续存储:std::vector 不同,std::deque 不要求元素在内存中是连续存储的。这使得在 std::deque 头部和尾部执行插入和删除操作更加高效。

  5. 大小可变: std::deque 的大小可以动态调整,因此它可以根据需要动态分配和释放内存。

总体而言,std::deque 是一个强大的容器,适用于需要在两端进行高效插入和删除操作的情况。它提供了动态数组的灵活性,同时避免了由于频繁在中间插入或删除元素而引起的性能问题。

在这里插入图片描述

deque的内部:

首先有一个map(暂且称为控制中心),里面存储指针,指针指向各个缓冲区buffer(或者叫做node),缓冲区是数组,具体存储数据。缓冲区是连续的,但是不同的缓冲区之间不是连续的,所以称为分段连续。如下图所示,下图中有5个 buffer。

对于下图中的迭代器中的cur,first,last,node四个元素,first和last分别是一个buffer的起始和结束,node是控制中心中哪个buffer的指针,cur指向的是具体的元素值。

所有的容器都维护了两个begin() 和 end(), 就是下图中的迭代器start和finish,它里面也有上述四个元素。

在这里插入图片描述

下面看一下class deque的内容,它里面的数据有:

iterator start; // 16B, 
iterator finish; // 16B
map_pointer map;  // 4B,上面所说的控制中心
size_type map_size;  // 4B, 控制中心这个vector的大小

上面的16 + 16 + 4 + 4 = 40B,这就是一个class deque创建出来的对象本身大小有40B(32位机器上),至于deque里面存储的数据占用的空间大小,是动态分配获得的,和对象本身大小无关。

再看下图的右上角,其中一个模板参数位 BufSiz, 这是GNU C++2.9版本,可以用来指定缓冲区的大小。

在这里插入图片描述

下图是iterator的成员(方框框起来的部分),可以看到map_pointer是 T**,它本身是一个指针,所以cur, first, last, node共计4 * 4B = 16B(在32位电脑上指针是4B大小),这个就是上面iterator的大小。

下图中有

typedef  random_access_iterator_tag iterator_category;

指定迭代器的类型是随机存取的类型,这就是deque对外表现:提供随机访问迭代器,可以在常数时间内对其元素进行随机访问。其实通过上面的学习,我们知道deque底层不是连续的,它是分段连续的。

在这里插入图片描述

下面看deque的insert函数

insert可以在指定位置插入元素,这一页ppt展示的是插入的位置在deque的头或尾,直接调用push_front和push_back,对于中间的插入放到下一页ppt中的insert_aux函数讲。

在这里插入图片描述

下面是insert_aux函数的具体讲解

由于deque是连续的,并且是可以双向扩充的,当插入一个元素(对应安插点)时,就要看一下,哪端元素少,要决定元素的移动是向前还是向后,然后再插入新值,这样速度更快。

在这里插入图片描述

19 deque、queue和 stack深度探索(下)

先看一下deque的函数:

reference front()
{return *start;
}reference back()
{iterator tmp = finish; // 迭代器tmp赋值为finish,finish指向最后一个元素的下一个位置--tmp;// 迭代器--,往前移动一格return *tmp; // 此时返回的是最后一个元素
}size_type size() const
{return finish - start; // -操作符重载// 
}

这里是从源代码中的operator-的重载,摘录如下:

// _Deque_iterator里面的四个值
_Tp* _M_cur;
_Tp* _M_first;
_Tp* _M_last;
_Map_pointer _M_node;difference_type operator-(const _Self& __x) const {return difference_type(_S_buffer_size()) * (_M_node - __x._M_node - 1) +(_M_cur - _M_first) + (__x._M_last - __x._M_cur);
}
// 每个buffer容纳的元素个数,buffer_size
inline size_t __deque_buf_size(size_t __size) {return __size < 512 ? size_t(512 / __size) : size_t(1);
}static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); }

在这里插入图片描述

下面看deque如何模拟连续空间,主要是deque iterators的功劳

下面的_M_node - __x._M_node - 1中的_M_node指的是上图中的迭代器中的node节点,_M_node - __x._M_node - 1指的是控制中心两个node相减,得到是首尾buffer之间buffer的个数。(__x._M_last - __x._M_cur)指的是起始buffer的元素个数,就是下图中的97,98,99所在buffer的计算,这个buffer中右侧是元素,左侧是空白(目前还没有存数据)。(_M_cur - _M_first)指的是末尾buffer的元素个数,这个buffer左侧是数据,右侧是空白。

// 两个迭代器之间的距离:指的是多少个元素在两个迭代器之间
difference_type operator-(const _Self& __x) const {return difference_type(_S_buffer_size()) * (_M_node - __x._M_node - 1) +(_M_cur - _M_first) + (__x._M_last - __x._M_cur);
}

在这里插入图片描述

下面看++和–操作符重载:移动一个位置

_Self& operator++() {++_M_cur;if (_M_cur == _M_last) { // 到达一个buffer的边界// _M_node是控制中心的节点_M_set_node(_M_node + 1); // 跳转到下一个buffer_M_cur = _M_first;}return *this; 
}
_Self operator++(int)  {_Self __tmp = *this;++*this;return __tmp;
}_Self& operator--() {if (_M_cur == _M_first) {_M_set_node(_M_node - 1);_M_cur = _M_last;}--_M_cur;return *this;
}
_Self operator--(int) {_Self __tmp = *this;--*this;return __tmp;
}// 从一个buffer跳转到另一个buffer
void _M_set_node(_Map_pointer __new_node) {_M_node = __new_node;_M_first = *__new_node; // 指向新buffer的start_M_last = _M_first + difference_type(_S_buffer_size()); //指向新buffer的last
}

在这里插入图片描述

deque号称是连续空间,迭代器可以跳过多个位置,所以迭代器提供+=的重载

当跳过多个位置跨越了当前buffer的边界,就会到另一个buffer,

_Self& operator+=(difference_type __n)
{difference_type __offset = __n + (_M_cur - _M_first);// 目标位置在同一个缓冲区bufferif (__offset >= 0 && __offset < difference_type(_S_buffer_size()))_M_cur += __n;else { // 目标位置不在同一个缓冲区bufferdifference_type __node_offset =__offset > 0 ? __offset / difference_type(_S_buffer_size()): -difference_type((-__offset - 1) / _S_buffer_size()) - 1;// 切换到正确的buffer_M_set_node(_M_node + __node_offset);// 切换至正确的元素_M_cur = _M_first + (__offset - __node_offset * difference_type(_S_buffer_size()));}return *this;
}_Self operator+(difference_type __n) const
{_Self __tmp = *this;return __tmp += __n;
}

在这里插入图片描述

-=的重载调用上文的+=

  _Self& operator-=(difference_type __n) { return *this += -__n; }_Self operator-(difference_type __n) const {_Self __tmp = *this;return __tmp -= __n;}
// 连续空间需要提供下标操作符[]reference operator[](difference_type __n) const { return *(*this + __n); }

另外这里补充一下this 和 *this的区别:

bool operator==(const _Self& __x) const { return _M_cur == __x._M_cur; }  
bool operator!=(const _Self& __x) const { return !(*this == __x); }

问题:这里的this是什么类型,*this是什么类型?

回答:

在C++中,this 是一个指向当前对象的指针。在成员函数中,this 指针被隐式地传递给成员函数,指向调用该成员函数的对象。因此,this 的类型是指向当前类类型的指针。

在上述代码中,*this 表示当前对象的解引用。由于 this 是指针,*this 就是该指针所指向的对象。因此,*this 的类型是当前类的对象类型。

具体来说,上述代码是一个用于比较不等于的运算符重载函数。*this 是当前对象,__x 是另一个对象。通过 *this == __x 这一比较操作,判断当前对象是否等于另一个对象。!(*this == __x) 表示当前对象不等于另一个对象,因此返回 true。这个重载函数的目的是实现 != 运算符,如果你已经在类中实现了 == 运算符,这个函数就是通过对 == 的结果取反来实现 !=

g++4.9版本的deque

deque的类图如下图所示,也是deque继承自一个deque base,deque base有一个deque impl实现,这个deque impl有一个迭代器deque iterator。

新版本不允许用户指定缓冲区的大小,使用默认值512.

在这里插入图片描述

deque里面有四个成员变量

_M_map // 指向控制中心(这是一个vector)map,控制中心控制一块一块的缓冲区
_M_map_size // 控制中心的大小
// 两个迭代器
_M_start // 指向deque所有元素的头
_M_finish // 指向deque所有元素的尾

这里补充控制中心这个vector扩充的规则:

当vector空间满的时候,会自动两倍扩充空间,并且把旧的元素拷贝进新的两倍空间中,这里实现的时候,拷贝到新vector的中间部分,从而实现vector中间部分不仅可以向后扩张(记录新的缓冲区),而且还可以向前扩张(记录新的缓冲区),如下图右侧,中间控制中心(灰色)。

在这里插入图片描述

容器queue

std::queue 是 C++ 标准模板库(STL)中的一个容器适配器,用于实现先进先出(FIFO)的队列数据结构。它是建立在其他 STL 容器之上的一个封装,通常使用 std::deque 作为默认底层容器。

以下是 std::queue 的一些主要特点和操作:

  1. 先进先出(FIFO): std::queue 实现了队列的基本特性,确保最先进入队列的元素最先被移出。

  2. 容器适配器: std::queue 是一个容器适配器,意味着它不直接提供存储元素的能力,而是通过封装底层容器(默认是 std::deque)来实现队列的行为。

  3. 底层容器: 默认情况下,std::queue 使用 std::deque 作为底层容器,但你也可以通过模板参数来指定其他底层容器,比如 std::liststd::vector

  4. 入队和出队操作: std::queue 提供了 push 方法用于将元素入队,pop 方法用于将队首元素出队。

    std::queue<int> myQueue;
    myQueue.push(1);
    myQueue.push(2);
    myQueue.pop();
    
  5. 队首和队尾访问: front 方法返回队首元素的引用,back 方法返回队尾元素的引用。

    std::queue<int> myQueue;
    int frontElement = myQueue.front();  // 访问队首元素
    int backElement = myQueue.back();    // 访问队尾元素
    
  6. 大小和空判断: size 方法返回队列中的元素数量,empty 方法检查队列是否为空。

    std::queue<int> myQueue;
    bool isEmpty = myQueue.empty();  // 检查队列是否为空
    

std::queue 提供了一种方便的方式来操作队列,尤其是在需要实现先进先出的场景下。它隐藏了底层容器的实现细节,使得队列的使用更加简单。

queue的源代码如下图,它调用deque中的各种方法实现自己的功能

在这里插入图片描述

容器stack

std::stack 是 C++ 标准模板库(STL)中的一个容器适配器,用于实现后进先出(LIFO)的栈数据结构。它是建立在其他 STL 容器之上的一个封装,通常使用 std::deque 作为默认底层容器。

以下是 std::stack 的一些主要特点和操作:

  1. 后进先出(LIFO): std::stack 实现了栈的基本特性,确保最后入栈的元素最先被弹出。

  2. 容器适配器: std::stack 是一个容器适配器,意味着它不直接提供存储元素的能力,而是通过封装底层容器(默认是 std::deque)来实现栈的行为。

  3. 底层容器: 默认情况下,std::stack 使用 std::deque 作为底层容器,但你也可以通过模板参数来指定其他底层容器,比如 std::liststd::vector

  4. 入栈和出栈操作: push 方法用于将元素入栈,pop 方法用于将栈顶元素出栈。

    std::stack<int> myStack;
    myStack.push(1);
    myStack.push(2);
    myStack.pop();
    
  5. 栈顶访问: top 方法返回栈顶元素的引用。

    std::stack<int> myStack;
    int topElement = myStack.top();  // 访问栈顶元素
    
  6. 大小和空判断: size 方法返回栈中的元素数量,empty 方法检查栈是否为空。

    std::stack<int> myStack;
    bool isEmpty = myStack.empty();  // 检查栈是否为空
    

std::stack 提供了一种方便的方式来操作栈,尤其是在需要实现后进先出的场景下。它隐藏了底层容器的实现细节,使得栈的使用更加简单。

下面是stack的源代码,它也是调用deque的各个函数实现自己的功能

在这里插入图片描述

queue和stack,关于其iterator和底层结构

stack和queue都不允许遍历,不提供iterator

stack和queue都可以选择list或者deque作为底层结构,如下图所示,便是使用list作为底层结构

stack<string, list<string>> c;
queue<string, list<string>> c1;

在这里插入图片描述

stack可以选择vector作为底层结构

queue不能选择vector作为底层结构

在这里插入图片描述

stack和queue都不能选择set或map做底层结构

在这里插入图片描述

后记

截至2024年1月7日,学习完list, vector, deque, queue, stack的底层实现,接下来要学习基于红黑树的容器。

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

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

相关文章

中国式浪漫:古人对万物的雅称

古人对万物的称呼都是美而浪漫&#xff0c;在诗词中&#xff0c;女子被称为红妆、佳人、婵娟、碧玉、红颜。雪也叫作琼芳、玉絮、六花、玉鸾&#xff1b;在诗词中&#xff0c;每一缕风&#xff0c;每一片雪&#xff0c;都有一个雅致的名字。所谓的诗情画意&#xff0c;便是用普…

基于深度学习的停车位关键点检测系统(代码+原理)

摘要&#xff1a; DMPR-PS是一种基于深度学习的停车位检测系统&#xff0c;旨在实时监测和识别停车场中的停车位。该系统利用图像处理和分析技术&#xff0c;通过摄像头获取停车场的实时图像&#xff0c;并自动检测停车位的位置和状态。本文详细介绍了DMPR-PS系统的算法原理、…

最短路径问题相关算法、原理及适用场景

这里写目录标题 一、最短路径算法、原理及适用场景深度优先搜索算法/广度优先搜索算法Floyd算法&#xff08;Floyd-Warshell算法&#xff09;Dijkstra算法A*算法贝尔曼福特算法&#xff08;Bellman-Ford Algorithm&#xff09;SPFA算法&#xff08;Shortest Path Faster Algori…

FPGA高端项目:纯verilog的 25G-UDP 高速协议栈,提供工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐我这里已有的以太网方案本协议栈的 1G-UDP版本本协议栈的 10G-UDP版本1G 千兆网 TCP-->服务器 方案1G 千兆网 TCP-->客户端 方案10G 万兆网 TCP-->服务器客户端 方案 3、该UDP协议栈性能4、详细设计方案设计架构框图网络调试助手…

传感数据分析——小波滤波

传感数据分析——小波滤波 文章目录 传感数据分析——小波滤波前言一、运行环境二、Python实现总结 前言 小波滤波算法是一种基于小波变换的滤波方法&#xff0c;其核心思想是将信号分解成不同的频率成分&#xff0c;然后对每个频率成分进行独立的处理。小波滤波器的设计和应用…

第12课 实现桌面与摄像头叠加

在上一节&#xff0c;我们实现了桌面捕获功能&#xff0c;并成功把桌面图像和麦克风声音发送给对方。在实际应用中&#xff0c;有时候会需要把桌面与摄像头图像叠加在一起发送&#xff0c;这节课我们就来看下如何实现这一功能。 1.备份与修改 备份demo11并修改demo11为demo12…

安达发|基于APS排程系统的PDM功能

APS系统&#xff08;Advanced Planning and Scheduling&#xff0c;先进计划与排程&#xff09;是一种基于APS系统&#xff08;Advanced Planning and Scheduling&#xff0c;先进计划与排程&#xff09;是一种基于供应链管理和生产管理的综合性软件系统。它通过整合企业内外部…

在anaconda中安装pytorch的GPU版本

本文前提&#xff1a; 1.你已经下载好了anaconda,最好是新建一个虚拟环境来安装pytorch的GPU版本&#xff0c;并且设置了国内镜像源&#xff1b; 2.了解自己电脑对应的cuda版本&#xff0c;可通过nvidia-smi&#xff0c;并下载好了cuda。 安装pytorch的GPU版本 到官网中https…

微信公众号-订阅通知

第一步&#xff1a; 公众号需要实名认证&#xff0c;完成以后&#xff01; 设置-开发里找到基本配置&#xff1a; 开发者ID(AppID):xxxxxxxxxxxxxxxxxxxxxxxxx 开发者密码(AppSecret):xxxxxxxxxxxxxxxxxxxxxxxxx 白名单IP也要填写上你的服务器IP哦&#xff01; 第二步&am…

聊天Demo

文章目录 参考链接使用前端界面消息窗口平滑滚动至底部vue使用watch监听vuex中的变量变化 参考链接 vue.js实现带表情评论功能前后端实现&#xff08;仿B站评论&#xff09; vue.js实现带表情评论仿bilibili&#xff08;滚动加载效果&#xff09; vue.js支持表情输入 vue.js表…

使用Scrapy框架和代理IP进行大规模数据爬取

目录 一、前言 二、Scrapy框架简介 三、代理IP介绍 四、使用Scrapy框架进行数据爬取 1. 创建Scrapy项目 2. 创建爬虫 3. 编写爬虫代码 4. 运行爬虫 五、使用代理IP进行数据爬取 1. 安装依赖库 2. 配置代理IP和User-Agent 3. 修改爬虫代码 4. 运行爬虫 六、总结 一…

【AI视野·今日Sound 声学论文速览 第四十二期】Fri, 5 Jan 2024

AI视野今日CS.Sound 声学论文速览 Fri, 5 Jan 2024 Totally 10 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Sound Papers PosCUDA: Position based Convolution for Unlearnable Audio Datasets Authors Vignesh Gokul, Shlomo Dubnov深度学习模型需要大量干净的…

【算法Hot100系列】合并两个有序链表

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

前端nginx配置指南

前端项目发布后&#xff0c;有些接口需要在服务器配置反向代理&#xff0c;资源配置gzip压缩&#xff0c;配置跨域允许访问等 配置文件模块概览 配置示例 反向代理 反向代理是Nginx的核心功能之一&#xff0c;是指客户端发送请求到代理服务器&#xff0c;代理服务器再将请求…

数据结构-怀化学院期末题(321)

图的广度优先搜索 题目描述&#xff1a; 图的广度优先搜索类似于树的按层次遍历&#xff0c;即从某个结点开始&#xff0c;先访问该结点&#xff0c;然后访问该结点的所有邻接点&#xff0c;再依次访问各邻接点的邻接点。如此进行下去&#xff0c;直到所有的结点都访问为止。在…

OpenHarmony沙箱文件

一.前言 1.前景提要 DevEcoStudio版本&#xff1a;DevEco Studio 3.1 Release SDK版本&#xff1a;3.2.2.5 API版本&#xff1a;9 2.概念 在openharmony文件管理模块中&#xff0c;按文件所有者分类分为应用文件和用户文件和系统文件。 1&#xff09;沙箱文件。也叫做应…

Jmeter扩展函数?年薪50W+的测试大佬教你怎么玩

很多同学&#xff0c;都问我&#xff1a;“老师&#xff0c;我的 jmeter 里面&#xff0c;怎么没有 MD5 函数&#xff0c;base64 函数也没有&#xff0c;我是不是用了假的 jmeter&#xff1f;” 哈哈哈&#xff0c;不是的。jmeter 的函数&#xff0c;有自带函数和扩展函数两大…

等价类划分法

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;软件测试面试题分享&#xff1a; 1000道软件测试面试题及答案&#x1f4e2;软件测试实战项目分享&#xff1a; 纯接口项目-完…

<HarmonyOS第一课>1~10课后习题汇总

HarmonyOS第一课 &#xff1c;HarmonyOS主题课&#xff1e;1~3课后习题汇总 1运行Hello World 判断题 main_pages.json存放页面page路径配置信息。&#xff08;正确&#xff09;DevEco Studio是开发HarmonyOS应用的一站式集成开发环境。&#xff08;正确&#xff09; 单选题…

二叉树-遍历-单独精讲

遍历:遍历每个元素。 寻常遍历root只会指一次。 而二叉树遍历每个元素则会指三次。 中序遍历-节点的中序 void traveres(TreeNode* root){if(!root)return;traveres(root->left);cout << root->val << endl;traveres(root->right);}中序遍历亦叫节点的中…