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

C++ STL:容器 Container

文章目录

    • 1、序列容器
      • 1.1、容器共性
      • 1.2、vector
        • vector 结构
        • * vector 扩容原理
        • * vector 迭代器失效
      • 1.3、deque
        • deque 结构
        • deque 迭代器
        • deque 模拟连续空间
      • 1.4、list
        • list 特殊操作
        • list 结构
        • list 迭代器
    • 2、关联式容器
      • 2.1、容器共性
      • 2.2、容器特性
    • 3、无序关联式容器
      • 3.1、容器共性
      • 3.2、容器特性

模板类的集合,内部封装组织数据的方法,也就是数据结构

作用:存放数据

分类:

  • 序列式容器 :线性
  • 关联式容器:key-value 集合,红黑树实现
  • 无序关联容器:hash 实现

1、序列容器

序列式容器

  • array:固定大小的数组。支持随机访问迭代器。
  • vector:动态数组。支持随机访问迭代器。
  • deque:双端队列。支持随机访问迭代器。
  • list:双向链表。只支持双向访问迭代器。
  • forward_list:单链表。只支持前向访问迭代器

序列式容器使用总结,当下列操作频繁发生时

  • 在容器中间位置添加删除元素,list
  • 在容器头部位置添加删除元素,deque / list
  • 在容器尾部位置添加删除元素,vector / deque / list
  • 访问容器任意位置上的元素,vector

1.1、容器共性

初始化

// 1、默认构造函数,空容器
容器();
// 2、构造拥有 count 个有值 value 的元素的容器。
容器(size_type count,const T& value = T(),const Allocator& alloc = Allocator());
// 3、构造拥有范围 [first, last) 内容的容器。
容器(InputIt first, InputIt last, const Allocator& alloc = Allocator());

赋值操作

// 1、重载等号操作符
operator=
// 2、assign
void assign(InputIt first, InputIt last); 	  // 以范围 [first, last) 中元素的副本替换内容。
void assign(size_type count, const T& value); // 将 count 个 value 的副本替换内容。

元素访问

at		    // 访问指定元素,同时越界检查
operator[]	// 访问指定元素 
front 		// 访问第一个元素
back		// 访问最后一个元素

容量

// 检查容器是否无元素
bool empty() const; 
// 容器中元素数量
size_type size() const;

修改器

// 1. 删除容器中所有元素
void clear();// 2. 插入元素
// 在 pos 前插入 value
iterator insert(const_iterator pos, T&& value);  
// 在 pos 前插入 value 的 count 个副本
iterator insert(const_iterator pos, size_type count, const T& value); 
// 原地构造元素,并将参数args转发给构造函数
iterator emplace(const_iterator pos, Args&&... args);// 3. 容器末尾添加元素
void push_back(const T& value);
// 容器末尾就地构造元素
void emplace_back(Args&&... args);// 4. 移除末尾元素
void pop_back();// 5. 删除元素
// 移除位于 pos 的元素。
iterator erase(iterator pos);
// 移除范围 [first, last) 中的元素。
iterator erase(iterator first, iterator last);   // 6. 改变容器中可存储元素的个数
void resize(size_type count);
void resize(size_type count, T value = T());// 7. 交换容器内容
void swap(deque& other);

1.2、vector

  • 动态数组
  • 支持随机访问迭代器
  • 逻辑机构和物理结构一致,连续线性空间,空间不足时,自动扩容

vector 扩容

  • 申请新空间:两倍扩容
  • 移动数据
  • 释放原空间

vector 结构

vector 使用三个指针维护动态数组 start, finish, end_of_storage

在这里插入图片描述

源码如下:

template <class _Tp, class _Alloc> 
class _Vector_base {
protected:_Tp* _M_start;	      // 指向使用空间的第一个元素	_Tp* _M_finish;	      // 指向使用空间的最后一个元素的下一个位置_Tp* _M_end_of_storage; // 指向可用空间的最后一个位置的下一个位置
};

通过三个指针可以实现一些基本接口

iterator begin() { return _M_start; }
iterator end() { return _M_finish; }size_type size() const { return size_type(end() - begin()); }
size_type capacity() const { return size_type(_M_end_of_storage - begin()); }
bool empty() const { return begin() == end(); }reference operator[](size_type __n) { return *(begin() + __n); }reference front() { return *begin(); }
reference back() { return *(end() - 1); }

* vector 扩容原理

vector 扩容

  • 申请新空间:两倍扩容。
  • 拷贝旧空间的元素到新空间:新空间前半段存放旧数据,后半段存放新插入的数据。
  • 释放原空间。

注意:初始化时,数组空间大小为 0,扩容后,新空间大小为 1。此后,都是两倍扩容操作。

添加元素时,先检测空间是否够用

  • size != capacity,在待插入位置构造新元素
  • size == capacity,则进行 vector 扩容
void push_back() {// 检测是否有可用空间// 空间足够if (_M_finish != _M_end_of_storage) {construct(_M_finish);++_M_finish;}// 空间不够,申请新的空间else_M_insert_aux(end());
}

空间足够,在待插入位置构造新元素

template <class _T1, class _T2>
inline void _Construct(_T1* __p, const _T2& __value) {new ((void*) __p) _T1(__value); // 定位new表达式:在 _p 位置上构造一个对象
}template <class _T1, class _T2>
inline void construct(_T1* __p, const _T2& __value) {_Construct(__p, __value);
}

空间不够,扩容操作

template <class _Tp, class _Alloc>
void vector<_Tp, _Alloc>::_M_insert_aux(iterator __position, const _Tp& __x)
{// 检测是否有可用空间,该函数会被其他函数调用,所以需要再次检查if (_M_finish != _M_end_of_storage) {construct(_M_finish, *(_M_finish - 1));++_M_finish;_Tp __x_copy = __x;copy_backward(__position, _M_finish - 2, _M_finish - 1);*__position = __x_copy;}else {const size_type __old_size = size();// 1、申请新空间:若旧空间大小为 0(初始化),则新空间大小为 1;否则,新空间为旧空间大小的 2 倍const size_type __len = __old_size != 0 ? 2 * __old_size : 1;iterator __new_start = _M_allocate(__len);iterator __new_finish = __new_start;// 2、将旧空间的元素复制到新空间// push_back 操作前半段用来存放旧数据,后半段用来存放新数据__STL_TRY {// 将旧数据拷贝到新空间__new_finish = uninitialized_copy(_M_start, __position, __new_start);// 为新元素设定初值construct(__new_finish, __x);// 调整水位++__new_finish;// 拷贝插入点后的旧数据(insert操作也可能导致扩容)__new_finish = uninitialized_copy(__position, _M_finish, __new_finish);}// 3、释放旧空间__STL_UNWIND((destroy(__new_start,__new_finish), _M_deallocate(__new_start,__len)));destroy(begin(), end());_M_deallocate(_M_start, _M_end_of_storage - _M_start);_M_start = __new_start;_M_finish = __new_finish;_M_end_of_storage = __new_start + __len;}
}

* vector 迭代器失效

vector 支持随机访问迭代器,普通指针天生具备。

typedef _Tp value_type;
typedef value_type* iterator;

插入元素

  • 尾部插入:
    • size < capacity,尾迭代器失效
    • size == capacity,所有迭代器失效(动态数组扩容,重新分配空间)
  • 中间插入:
    • size <= capacity,插入位置后的所有迭代器失效
    • size == capacity,所有迭代器失效(动态数组扩容,重新分配空间)

例:在遍历容器元素的过程中,添加元素的操作很危险。一旦发生扩容操作,申请新的存储空间,而迭代器仍指向原空间,导致越界。

删除元素

  • 尾部删除:尾迭代器失效
  • 中间删除:删除位置后的所有迭代器失效(元素前移)

例:删除 vector 中值为 val 的所有元素。下面是容易导致错误的做法

// 错误写法:删除后,元素前移,当前删除位置后的所有迭代器失效
for (auto it = numbers.begin(); it != numbers.end(); ++it) {if (val == *it) {numbers.erase(it);} 
}

错误的原因在于:

  • 删除连续相同元素,删除后元素前移,跳过第二个要删除的元素
  • 删除最后一个元素,删除后元素前移,迭代器指向 end() 的下一个位置,发生越界

正确的写法

for (auto it = vec.begin(); it != vec.end();) {  if (val == *it) { // 删除元素后,不能执行 ++操作it = vec.erase(it); } else {//未删除元素,执行++操作++it; } 
}

1.3、deque

  • 双端队列
  • 支持随机访问迭代器
  • 逻辑结构,连续空间,双端开口,首尾插入移除元素 O(1)
  • 物理离散,物理结构由多个片段构成,片段内部连续,片段间不连续,片段的控制由中控器完成。

修改器接口

// 容器头部插入元素
void push_front( const T& value );
// 容器头部就地构造元素
void emplace_front( Args&&... args );
// 移除容器头部元素
void pop_front();

deque 结构

物理结构由多个片段构成,片段内部连续,片段之间不连续,片段的控制由中控器完成。

deque 组成

  • 中控器:map 数组,其中的每个元素(node 节点)是一个指针,指向一块较大的连续空间(缓冲区)。
  • 缓冲区:buffer 缓冲区,实际存放数据的区域

在这里插入图片描述

源码如下:

template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class deque : protected _Deque_base<_Tp, _Alloc> {protected: typedef pointer* _Map_pointer; // 二级指针static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); }protected:using _Base::_M_map;		// 连续空间,每个元素是一个指针,指向一个 bufferusing _Base::_M_map_size;	// 容纳的指针数量using _Base::_M_start;	// 哨兵,指向 buffer 起始位置using _Base::_M_finish;	// 哨兵,指向 buffer 结束位置

缓冲区 buffer 大小默认 512

// 返回每个缓冲区可容纳元素数量
inline size_t __deque_buf_size(size_t __size) {return __size < 512 ? size_t(512 / __size) : size_t(1);
}

deque 迭代器

deque 逻辑连续,体现在 operator++ 和 operator–运算。deque 迭代器需要判断缓冲区位置,其次当迭代器处于缓冲区边缘,为了能够正确跳跃至上一个或下一个缓冲区,需要中控器的支持。

dueque 迭代器组成

  • cur:指向 buffer 的当前元素
  • fast:哨兵,指向 buffer 起始位置
  • last:哨兵,指向 buffer 结束位置
  • node:指向中控器

在这里插入图片描述

源码如下

template <class _Tp, class _Ref, class _Ptr>
struct _Deque_iterator {// 支持迭代器typedef random_access_iterator_tag iterator_category;typedef _Tp value_type;typedef _Ptr pointer;typedef _Ref reference;typedef size_t size_type;typedef ptrdiff_t difference_type;typedef _Tp** _Map_pointer;typedef _Deque_iterator _Self;typedef _Tp** _Map_pointer; // 二级指针,指向 buffer_Tp* _M_cur;   // 指向 buffer 的当前元素_Tp* _M_first; // 哨兵,指向 buffer 起始位置_Tp* _M_last;  // 哨兵,指向 buffer 结束位置_Map_pointer _M_node; // 中控器,二级指针...
};

deque 插入元素,首先判断插入元素在 deque 的位置

  iterator insert(iterator position, const value_type& __x) {// 1、若插入位置是头部if (position._M_cur == _M_start._M_cur) {push_front(__x);return _M_start;}// 2、若插入位置是尾部else if (position._M_cur == _M_finish._M_cur) {push_back(__x);iterator __tmp = _M_finish;--__tmp;return __tmp;}// 3、若插入位置在中间else {return _M_insert_aux(position, __x);}}

在 deque 中间位置插入,需要移动元素,为了减少移动元素次数,这里有一个巧妙的设计,判断插入点前和插入点后的元素数量,移动元素数量少的一端。

template <class _Tp, class _Alloc>
typename deque<_Tp, _Alloc>::iterator
deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos, const value_type& __x)
{// 插入点前元素个数difference_type __index = __pos - _M_start;value_type __x_copy = __x;// 比较插入点前的元素数量与插入点后的元素数量// 选择元素较少的一端移动元素// 1、若插入点前元素个数较少if (size_type(__index) < this->size() / 2) {// 头端插入与第一个元素值相同的元素push_front(front());iterator __front1 = _M_start;++__front1;iterator __front2 = __front1;++__front2;__pos = _M_start + __index;iterator __pos1 = __pos;++__pos1;// 元素前移copy(__front2, __pos1, __front1);}// 2、若插入点后元素个数较少else {// 尾端插入与最后一个元素值相同的元素push_back(back());iterator __back1 = _M_finish;--__back1;iterator __back2 = __back1;--__back2;__pos = _M_start + __index;copy_backward(__pos, __back2, __back1);}// 插入元素*__pos = __x_copy;return __pos;
}

deque 模拟连续空间

deque 迭代器模拟连续空间

reference operator[](size_type __n) { return _M_start[difference_type(__n)]; }reference front() { return *_M_start; }reference back() {iterator __tmp = _M_finish;--__tmp;return *__tmp;
}size_type size() const { return _M_finish - _M_start; }bool empty() const { return _M_finish == _M_start; }

**operator ***

reference operator*() const { return *_M_cur; }

set_node

实现 node 节点 (buffer) 跳转

void _M_set_node(_Map_pointer __new_node) {_M_node = __new_node;_M_first = *__new_node;_M_last = _M_first + difference_type(_S_buffer_size());
}

difference_type operator-

两个迭代器的距离 = 两个迭代器间的 buffers 总长度 + 起始 buffer 长度 + 末尾(当前)buffer 长度

  • 两个迭代器间的 buffers 长度:bufferSize * 首尾 buffer 间的 buffers 数量,-1 是排除起始边界 buffer
  • 起始 buffer 的元素数量:__x._M_last - __x._M_cur
  • 末尾 buffer 的元素数量:_M_cur - _M_first
difference_type operator-(const _Self& __x) const {// 两个迭代器间的 buffers 总长度 + 起始 buffer 长度 + 末尾(当前)buffer 长度return difference_type(_S_buffer_size()) * (_M_node - __x._M_node - 1) +(_M_cur - _M_first) + (__x._M_last - __x._M_cur);
}

operator++

// 前置++
_Self& operator++() {++_M_cur;// 判断是否到了 buffer 边界(终点)if (_M_cur == _M_last) {// 跳转至下一个node节点(buffer)的起点_M_set_node(_M_node + 1);_M_cur = _M_first;}return *this; 
}// 后置++
_Self operator++(int)  {_Self __tmp = *this;// 前置++实现后置++++*this;return __tmp;
}

operator–

// 前置--
_Self& operator--() {// 判断是否到了 buffer 边界(起点)if (_M_cur == _M_first) {// 跳转至前一个node节点(buffer)的终点_M_set_node(_M_node - 1);_M_cur = _M_last;}--_M_cur;return *this;
}// 后置--
_Self operator--(int) {_Self __tmp = *this;// 前置--实现后置----*this;return __tmp;
}

operator+=

_Self& operator+=(difference_type __n) {difference_type __offset = __n + (_M_cur - _M_first);// 目标位置在同一 buffer 内if (__offset >= 0 && __offset < difference_type(_S_buffer_size()))_M_cur += __n;// 目标位置不在同一 buffer 内else {difference_type __node_offset =__offset > 0 ? __offset / difference_type(_S_buffer_size()): -difference_type((-__offset - 1) / _S_buffer_size()) - 1;// 切换到目标 node 节点(buffer)_M_set_node(_M_node + __node_offset);// 切换至正确元素_M_cur = _M_first + (__offset - __node_offset * difference_type(_S_buffer_size()));}return *this;}

operator+

_Self operator+(difference_type __n) const {_Self __tmp = *this;// 内部调用 += 实现return __tmp += __n;
}

operator-=

内部调用 +=,偏移量 -n

// 内部调用 += -n
_Self& operator-=(difference_type __n) { return *this += -__n; }

operator-

内部调用 -=

_Self operator-(difference_type __n) const {_Self __tmp = *this;return __tmp -= __n;
}

1.4、list

  • list 双向链表
  • 支持双向访问迭代器
  • 物理结构:循环双向链表
  • 逻辑结构:双向链表

list 特殊操作

// 1、从一个链表转移元素到另一个链表
// 移动一个链表到另一个链表的某个指定位置
void splice(const_iterator pos, list& other);
void splice(const_iterator pos, list&& other)
// 移动一个链表中的某个元素到另一个链表的某个指定位置
void splice(const_iterator pos, list& other, const_iterator it)
void splice(const_iterator pos, list&& other, const_iterator it);
// 移动一对迭代器范围元素到另一个链表的某个指定位置
void splice(const_iterator pos, list& other, const_iterator first, const_iterator last)
void splice(const_iterator pos, list&& other,const_iterator first, const_iterator last)// 2、对元素进行排序
void sort();
template< class Compare > void sort(Compare comp);
template <typename T>
struct Compare {bool operator()(const T &a, const T &b) const {return a < b;}
}; // 3、合并两个已排序的链表
void merge(list& other);// 4、将该链表的所有元素的顺序反转
void reverse();// 5、移除满足特定标准的元素
void remove(const T& value);
void remove_if(UnaryPredicate p)// 6、删除连续的重复元素
void unique();

list 结构

list 通过 node 指针可以实现遍历循环链表,尾端留有空白节点,符合左闭右开,成为 last 迭代器。

在这里插入图片描述

list node

  • prev:指向前一个节点
  • next:指向下一个节点
  • data:存储数据

在这里插入图片描述

struct _List_node_base {_List_node_base* _M_next;_List_node_base* _M_prev;
};template <class _Tp>
struct _List_node : public _List_node_base {_Tp _M_data;
};

list 迭代器

template<class _Tp, class _Ref, class _Ptr>
struct _List_iterator : public _List_iterator_base {// 1、typedeftypedef _List_iterator<_Tp,_Tp&,_Tp*>             iterator;typedef _List_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;typedef _List_iterator<_Tp,_Ref,_Ptr>             _Self;typedef _Tp value_type;typedef _Ptr pointer;typedef _Ref reference;typedef _List_node<_Tp> _Node;// 2、运算符重载...
};  

运算符重载

reference operator*() const { return ((_Node*) _M_node)->_M_data; }pointer operator->() const { return &(operator*()); }void _M_incr() { _M_node = _M_node->_M_next; }
void _M_decr() { _M_node = _M_node->_M_prev; }_Self& operator++() { this->_M_incr();return *this;
}
_Self operator++(int) { _Self __tmp = *this;	// 先调用重载=,在调用重载*,因此这里调用的是拷贝构造this->_M_incr();return __tmp;
}
_Self& operator--() { this->_M_decr();return *this;
}
_Self operator--(int) { _Self __tmp = *this;this->_M_decr();return __tmp;
}

2、关联式容器

2.1、容器共性

容器共性

  • 底层实现:红黑树,查找元素时间复杂度O(logN)
  • 默认情况下,按照关键字 key 升序排列
  • 不能修改关键字 key 的值
  • 支持双向访问迭代器

面试:红黑树的特征

  • 节点是红色或黑色
  • 根节点必须是黑色
  • 叶子节点都是黑色
  • 红色节点的孩子节点必须是黑色的。黑色节点的孩子节点可以是黑色的。
  • 从根节点到叶子节点的所有路径的黑色节点的个数相同

扩展:从根节点到叶子节点的路径上不存在连续的红色节点

  • 最短路径,节点都是黑色的;
  • 最长路径,红黑相间,2 * 黑色节点数 - 1,红色节点数 = 黑色节点数 - 1

2.2、容器特性

容器分类:set / map,key 唯一;multiset / multimap,key 不唯一。

set

  • 存放 key 的有序集合
  • 插入操作:insert,返回std::pair<iterator, bool>
  • 查找操作,count / find
  • 删除操作:erase

map

  • 存放键值对,pair<const key, value>。可以使用std::pairstd::make_pair存放元素。
  • 支持下标访问运算符,注意:查询时对应的 key 若不存在,会直接创建该 key 的记录

3、无序关联式容器

3.1、容器共性

  • 底层实现:哈希表(桶 + 单链表)
  • 存放的元素是无序的
  • 针对自定义类型:必须自定义 std::hashstd::equal_to

面试:hash table

在这里插入图片描述

  • 哈希冲突:不同的 key,散列到相同的地址,即 H(key1) == H(key2)
  • 哈希冲突解决方法:链地址法(STL)、开放定址法、再散列法
  • 装载因子 = 实际装载数据的长度 n / 哈希表长 m,当负载因子过大时,rehash

3.2、容器特性

  • unordered_set

  • unordered_map

  • unordered_multiset

  • unordered_multimap

例:自定义 point 类型,无法使用无序关联式容器。

定义std::hash

  • 自定义函数对象
  • 扩展std::hash的模板特化版本
  • 函数调用运算符设计成 const 版本
// 1、自定义哈希函数
// 1.1、扩展 std::hash 的模板特化版本
namespace std {
template <>
// 1.2、自定义函数对象
struct hash<Point> {// 1.3、函数调用运算符设计成 const 版本size_t operator()(const Point & rhs) const {// 自定义哈希函数return (rhs.getX() << 1) ^ (rhs.getY() << 1);}
};

定义 std::equal_to:重载函数调用运算符,或重载等号运算符,或使用模板特化

bool operator() (const T &lhs, const T &rhs) const {return lhs == rhs;
}bool operator== (const T &lhs, const T &rhs) {return lhs == rhs;
}namespace std {
template <>
struct equal_to<Point> {bool operator()(const Point &lhs, const Point &rhs) const {return (lhs.getX() == rhs.getX()) && (lhs.getY() == rhs.}
};
}//end of namespace std

相关文章:

C++ STL:容器 Container

文章目录1、序列容器1.1、容器共性1.2、vectorvector 结构* vector 扩容原理* vector 迭代器失效1.3、dequedeque 结构deque 迭代器deque 模拟连续空间1.4、listlist 特殊操作list 结构list 迭代器2、关联式容器2.1、容器共性2.2、容器特性3、无序关联式容器3.1、容器共性3.2、…...

urllib之urlopen和urlretrieve的headers传入以及parse、urlparse、urlsplit的使用

urllib库是什么?urllib库python的一个最基本的网络请求库&#xff0c;不需要安装任何依赖库就可以导入使用。它可以模拟浏览器想目标服务器发起请求&#xff0c;并可以保存服务器返回的数据。urllib库的使用&#xff1a;1、request.urlopen(1)只能传入url的方式from http.clie…...

【C++】二叉搜索树的模拟实现

一、概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值它的左右子树也分别…...

HNU工训中心:元器件及测量基础实验报告

工训中心的牛马实验 1.实验目的 1.熟悉测量验证常用元器件参数、 并采用替代法(测量回路电流)测量其伏安特性的方法。 2.熟悉测量误差及减小测量误差注意事项 2.实验仪器和器材 1.实验仪器. 直流稳压电源型号:IT6302 台式多用表型号:UT805A 2.实验( 箱)器材 电路实验箱…...

博客系统--自动化测试

项目体验地址&#xff08;账号&#xff1a;123&#xff0c;密码&#xff1a;123&#xff09;http://120.53.20.213:8080/blog_system/login.html项目后端说明&#xff1a;http://t.csdn.cn/32Nnv项目码云Gitee地址&#xff1a;https://gitee.com/GoodManSS/project/tree/master…...

Day903.自增主键不能保证连续递增 -MySQL实战

自增主键不能保证连续递增 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于自增主键不能保证连续递增的内容。 MySql保证了主键是自增&#xff0c;但不相对连续&#xff1b;帮助开发人员快速识别每个行的唯一性&#xff0c;并提高查询效率。 自增主键可以让主键索引…...

02-MyBatis查询-

文章目录Mybatis CRUD练习1&#xff0c;配置文件实现CRUD1.1 环境准备Debug01: 别名mybatisx报错1.2 查询所有数据1.2.1 编写接口方法1.2.2 编写SQL语句1.2.3 编写测试方法1.2.4 起别名解决上述问题1.2.5 使用resultMap解决上述问题1.2.6 小结1.3 查询详情1.3.1 编写接口方法1.…...

外盘国际期货招商:2023年3月关注日历,把握重要投资机会

2023年3月大事件日历 关注大事日历&#xff0c;把握重要投资机会 3月1日&#xff1a;马斯克推出特斯拉宏图第三篇章 3月1-2日&#xff1a;G20外长会议 3月4-5日&#xff1a;全国两会召开 3月9日&#xff1a;中国2月CPI、PPI数据 待定&#xff08;前次进行日期&#xff1a…...

Linux学习(9.1)文件系统的简单操作

以下内容转载自鸟哥的Linux私房菜 原文&#xff1a;鸟哥的 Linux 私房菜 -- Linux 磁盘与文件系统管理 (vbird.org) 磁盘与目录的容量 df&#xff1a;列出文件系统的整体磁盘使用量&#xff1b;du&#xff1a;评估文件系统的磁盘使用量(常用在推估目录所占容量) df du 实体…...

Hadoop综合案例 - 聊天软件数据

目录1、聊天软件数据分析案例需求2、基于Hive数仓实现需求开发2.1 建库2.2 建表2.3 加载数据2.4 ETL数据清洗2.5 需求指标统计---都很简单3、FineBI实现可视化报表3.1 FineBI介绍3.2 FineBI配置数据3.3 构建可视化报表1、聊天软件数据分析案例需求 MR速度慢—引入hive 背景&a…...

Python进阶-----面向对象1.0(对象和类的介绍、定义)

目录 前言&#xff1a; 面向过程和面向对象 类和对象 Python中类的定义 &#xff08;1&#xff09;类的定义形式 &#xff08;2&#xff09;深层剖析类对象 前言&#xff1a; 感谢各位的一路陪伴&#xff0c;我学习Python也有一个月了&#xff0c;在这一个月里我收获满满…...

天猫淘宝企业服务为中小微企业打造供应链智能协同网络,让采购不再将就!丨爱分析报告

编者按&#xff1a;近日天猫淘宝企业服务&爱分析联合发布《2023中小微企业电商采购白皮书》&#xff0c;为中小微企业采购数字化带来红利。 某水泵企业&#xff1a;线上客户主要是中小微企业&#xff0c;线上业绩遇到瓶颈&#xff0c;如何突破呢&#xff1f;某焊割设备企业…...

基于四信网络摄像机的工业自动化应用

方案背景 随着数控机床被广泛的应用在工业生产中&#xff0c;数控技术发展成为制造业的核心。 鉴于数控机床的复杂性&#xff0c;以及企业人力储备有限&#xff0c;设备的监控和维护必须借助外部力量&#xff0c;而如何实现车间实时监测成了目前迫切解决的问题。 方案需求 ①兼…...

软件测试2

一 web掐断三大核心技术 HTML&#xff1a;负责网页的结构 CSS&#xff1a;负责网页的美化 JS&#xff1a;负责网页的行为 二 工具的使用 改变HBuilder文字的大小&#xff1a; 工具-视觉主题设置-大小22-确定 三 html简介 中文定义&#xff1a;超文本标记语言 新建一个html…...

(二分查找)leetcode162. 寻找峰值

文章目录一、题目1、题目描述2、基础框架3、原题链接二、解题报告1、思路分析2、时间复杂度3、代码详解三、本题小知识一、题目 1、题目描述 峰值元素是指其值严格大于左右相邻值的元素。 给你一个整数数组 nums&#xff0c;找到峰值元素并返回其索引。数组可能包含多个峰值…...

spring boot 配合element ui vue实现表格的批量删除(前后端详细教学,简单易懂,有手就行)

目录 一.前言&#xff1a; 二. 前端代码&#xff1a; 2.1.element ui组件代码 2.2删除按钮 2.3.data 2.4.methods 三.后端代码&#xff1a; 一.前言&#xff1a; 研究了其他人的博客&#xff0c;找到了一篇有含金量的&#xff0c;进行了部分改写实现前后端分离&#xff0…...

hiveSQL开窗函数详解

hive开窗函数 文章目录hive开窗函数1. 开窗函数概述1.1 窗口函数分类1.2 窗口函数和普通聚合函数的区别2. 窗口函数的基本用法2.1 基本用法2.2 设置窗口的方法2.2.1 window_name2.2.2 partition by2.2.3 order by 子句2.2.4 rows指定窗口大小窗口框架2.3 开窗函数中加 order by…...

深度学习基础实例与总结

一、神经网络 1 深度学习 1 什么是深度学习&#xff1f; 简单来说&#xff0c;深度学习就是一种包括多个隐含层 (越多即为越深)的多层感知机。它通过组合低层特征&#xff0c;形成更为抽象的高层表示&#xff0c;用以描述被识别对象的高级属性类别或特征。 能自生成数据的中…...

在 WIndows 下安装 Apache Tinkerpop (Gremlin)

一、安装 JDK 首先安装 Java JDK&#xff0c;这个去官网下载即可&#xff0c;我下载安装的 JDK19&#xff08;jdk-19_windows-x64_bin.msi&#xff09;&#xff0c;细节不赘述。 二、去 Tinkerpop 网站下载 Gremlin 网址&#xff1a;https://tinkerpop.apache.org/ 点击下面…...

从软件的角度看待PCI和PCIE(一)

1.最容易访问的设备是什么&#xff1f; 是内存&#xff01; 要读写内存&#xff0c;知道它的地址就可以了&#xff0c;不需要什么驱动程序&#xff1b; volatile unsigned int *p 0xffff8811; unsigned int val; *p val; val *p;只有内存能这样简单、方便的使用吗&#xf…...

DSP_TMS320F28377D_ADC学习笔记

前言 DSP各种模块的使用&#xff0c;基本上就是 GPIO复用配置、相关控制寄存器的配置、中断的配置。本文主要记录本人对ADC模块的学习笔记。TMS320F28377D上面有24路ADC专用IO&#xff0c;这意味着不需要进行GPIO复用配置。 只需要考虑相关控制寄存器和中断的配置。看代码请直…...

springcloud3 Nacos中namespace和group,dataId的联系

一 Namespance和group和dataId的联系 1.1 3者之间的联系 话不多说&#xff0c;上答案&#xff0c;如下图&#xff1a; namespance用于区分部署环境&#xff0c;group和dataId用于逻辑上区分两个目标对象。 二 案例&#xff1a;实现读取注册中心的不同环境下的配置文件 …...

[YOLO] yolo理解博客笔记

YOLO v2和V3 关于设置生成anchorbox&#xff0c;Boundingbox边框回归的过程详细解读 YOLO v2和V3 关于设置生成anchorbox&#xff0c;Boundingbox边框回归的个人理解https://blog.csdn.net/shenkunchang1877/article/details/105648111YOLO v1网络结构计算 Yolov1-pytorch版 …...

清华源pip安装Python第三方包

一、更换PIP源PIP源在国外&#xff0c;速度慢&#xff0c;可以更换为国内源&#xff0c;以下是国内一些常用的PIP源。豆瓣(douban) http://pypi.douban.com/simple/ (推荐)清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/阿里云 http://mirrors.aliyun.com/pypi/simple/中…...

python线程池【ThreadPoolExecutor()】批量获取博客园标题数据

转载&#xff1a;蚂蚁学python 网址&#xff1a;【【2021最新版】Python 并发编程实战&#xff0c;用多线程、多进程、多协程加速程序运行】 https://www.bilibili.com/video/BV1bK411A7tV/?p8&share_sourcecopy_web&vd_sourced0ef3d08fdeef1740bab49cdb3e96467实战案…...

LearnOpenGL-入门-8.坐标系统

本人刚学OpenGL不久且自学&#xff0c;文中定有代码、术语等错误&#xff0c;欢迎指正 我写的项目地址&#xff1a;https://github.com/liujianjie/LearnOpenGLProject LearnOpenGL中文官网&#xff1a;https://learnopengl-cn.github.io/ 文章目录坐标系统概述局部空间世界空…...

windows10使用wsl2安装docker

配环境很麻烦&#xff0c;想利用docker的镜像环境跑一下代码整个安装过程的原理是&#xff1a;windows使用docker&#xff0c;必须先安装一个linux虚拟机&#xff0c;才可运行docker&#xff0c;而采用wsl2安装虚拟机是目前最好的方法第一步 windows安装wsl2控制面板->程序-…...

Javascript的API基本内容(六)

一、正则表达式 1.定义规则 const reg /表达式/ 其中/ /是正则表达式字面量正则表达式也是对象 2.使用正则 test()方法 用来查看正则表达式与指定的字符串是否匹配如果正则表达式与指定的字符串匹配 &#xff0c;返回true&#xff0c;否则false 3.元字符 比如&#xff0…...

电压放大器和电流放大器的区别是什么意思

在日常电子实验测试中&#xff0c;很多电子工程师都会使用到电压放大器和电流放大器&#xff0c;但是很多新手工程师却无法区分两者的区别&#xff0c;下面就让安泰电子来为我们讲解电压放大器和电流放大器的区别是什么意思。 一、电压放大器介绍&#xff1a; 电压放大器是一种…...

cast提前!最简单有效的神经网络优化方法,没有之一!

做优化有时候真的很头疼&#xff0c;绞尽脑汁的想怎么做算法等价&#xff0c;怎么把神经网络各层指令流水起来&#xff0c;在确保整网精度的同时&#xff0c;又有高性能。 但有时做了半天&#xff0c;却发现流水根本就流不起来&#xff0c;总是莫名其妙地被卡住。 真的是一顿…...

LeetCode刷题——动态规划(C/C++)

文章目录[简单]买股票的最佳时机[简单]爬楼梯[中等]最长递增子序列[中等]最大连续子数组和[简单]买股票的最佳时机 原题链接 题解 min&#xff1a;今天之前买股的最低价 res&#xff1a;最大利润 每一天比较今天和往前的最低价差值能否比最大利润还大 class Solution { publ…...

车载智能终端TBOX

YD886 终端设备是基于GSM/WCDMA全网通讯方式的GPS定位移动终端,车载设备具有强大的车辆监控管理、CAN总线数据采集等功能&#xff0c;可以满足不同用户的需求&#xff0c;同时具备汽车行驶记录功能扩展应用。具体功能请以终端实际情况为准&#xff01; 一、移动管家 车载智能终…...

技术分担产品之忧(上):挑选有业务专家潜力的人

你好&#xff0c;我是王植萌&#xff0c;去哪儿网的高级技术总监、TC主席。从2014年起&#xff0c;担任一个部门的技术负责人&#xff0c;有8年技术总监经验、5年TC主席的经验。这节课我会从去哪儿网产研融合的经验出发&#xff0c;和你聊一聊怎么让技术分担产品之忧。 技术分…...

UVa 12569 Planning mobile robot on Tree (EASY Version) 树上机器人规划(简单版) BFS 二进制

题目链接&#xff1a;Planning mobile robot on Tree (EASY Version) 题目描述&#xff1a; 给定一棵树&#xff0c;树上有一个位置存在一个机器人&#xff0c;其他mmm个位置存在石头&#xff0c;保证初始状态一个结点最多一个物体&#xff08;一个石头或者一个机器人或者为空…...

intel的集成显卡(intel(r) uhd graphics) 配置stable diffusion

由于很多商务本没有独立显卡&#xff0c;只有Intel的集成显卡&#xff0c;在配置安装stable diffusion 时候需要特殊对待&#xff0c;参考不少帖子&#xff0c;各取部分现稍加整合。整体思路分两个部分&#xff1a;第一步是先配置环境&#xff0c;主要是安装Anaconda Pytorch&…...

【数据库的基础知识(2)】

&#x1f339;作者:云小逸 &#x1f4dd;个人主页:云小逸的主页 &#x1f4dd;Github:云小逸的Github &#x1f91f;motto:要敢于一个人默默的面对自己&#xff0c;强大自己才是核心。不要等到什么都没有了&#xff0c;才下定决心去做。种一颗树&#xff0c;最好的时间是十年前…...

Docker部署实战

文章目录Docker部署应用准备制作容器镜像启动容器上传镜像docker exec数据卷&#xff08;Volume&#xff09;声明原理实践Docker部署 应用准备 这一次&#xff0c;我们来用 Docker 部署一个用 Python 编写的 Web 应用。这个应用的代码部分&#xff08;app.py&#xff09;非常…...

RestTemplate 相关使用

RestTemplate介绍简单接口调用&#xff08;getForObject&#xff09;添加 Header 和 Cookie&#xff08;exchange&#xff09;介绍 在项目中&#xff0c;当我们需要远程调用一个 HTTP 接口时&#xff0c;我们经常会用到 RestTemplate 这个类。这个类是 Spring 框架提供的一个工…...

新手小白亚马逊注册最全教程在此

自从龙哥出了Walmart注册教程后&#xff0c;立刻看到私信有兄弟问这个亚马逊的注册。亚马逊是跨境电商的鼻祖&#xff0c;资源和流量是无容置疑的。作为一个重产品&#xff0c;轻店铺的平台&#xff0c;是比较看中客户体验的&#xff0c;要求卖家要有好的资源。而且亚马逊有强大…...

二分查找重复情况 找最左边或最右边的位置下标

目录二分找最左边二分找最右边综合应用(剑指offer)二分找最左边 核心思想: 先mid (lr)/2每次向左取整; 然后命中target的时候&#xff0c;右边界逼近到mid; 因为每次mid向左取整&#xff0c;mid命中target时l代替mid位置&#xff0c;则循环迭代最后会卡出重复数字最左侧的位置…...

智慧扫码点餐系统源码

智慧餐厅扫码点餐小程序系统源码 1. 开发语言&#xff1a;JAVA 2. 数据库&#xff1a;MySQL 3. 原生小程序 4. Saas 模式 5. 带调试部署视频 6、总后台管理端商家端门店端小程序用户端 智慧扫码点餐系统支持多店铺运营&#xff0c;单店铺运营以及连锁店铺运营。系统功能支…...

分布式环境并发场景下,如何操作抢红包(或者减少库存)

文章目录简介思考lua 对 redis 的原子操作其他解决方式一些问题简介 在分布式场景高并发环境中&#xff0c;无论是抢红包还是减库存&#xff0c;其实本质上都是如何处理高并发中共享资源的问题&#xff0c;保证高并发资源分配的安全性 相互学习&#xff0c;如有错误还请指正&…...

明星的孩子也在做的感统训练,真的有用吗?

林志颖曾经在社交网站晒过带他儿子“模拟过山车”的视频。孩子大脑前庭受到适当的刺激&#xff0c;可以有效地锻炼前庭平衡感。 除此之外&#xff0c;还能看见地上的感统教具&#xff1a;过河石、平衡桥&#xff0c;看来明星老爸在陪孩子做感统游戏的日常一点也不含糊。 其实在…...

守护进程与TCP通讯

目录 一.守护进程 1.1进程组与会画 1.2守护进程 二.创建守护进程 setsid函数&#xff1a; 三. TCP通讯流程 3.1三次握手&#xff1a; 3.2 数据传输的过程 3.3四次挥手 一.守护进程 1.1进程组与会画 进程组&#xff1a;进程组由一个进程或者多个进程组成&#xff0c;每…...

在线文本翻译能力新增14个直译模型,打造以中文为轴心语言的翻译系统

经济全球化的今天&#xff0c;人们在工作和生活中经常会与外语打交道。相较传播性较广的英语而言&#xff0c;其他语种的识别和阅读对大多数人来说是一件难事&#xff0c;此时就需要借助语言翻译软件来帮助理解。 华为 HMS Core 机器学习服务&#xff08;ML Kit&#xff09;翻…...

CVE-2022-42889 Apache Commons Text 漏洞

0x00 前言 所幸遇到&#xff0c;就简单看看&#xff0c;其中没有啥比较难的地方&#xff0c;仅做记录。10月13日的漏洞。 cve链接可以看下面这个&#xff1a; https://cve.mitre.org/cgi-bin/cvename.cgi?nameCVE-2022-42889 git地址&#xff1a; https://github.com/apache…...

20- widedeep及函数式构建模型 (TensorFlow系列) (深度学习)

知识要点 wide&deep: 模型构建中, 卷积后数据和原始数据结合进行输出.fetch_california_housing&#xff1a;加利福尼亚的房价数据&#xff0c;总计20640个样本&#xff0c;每个样本8个属性表示&#xff0c;以及房价作为target&#xff0c;所有属性值均为number&#xff0…...

大家一起做测试的,凭什么你现在拿20k,我却还只有10k?...

最近我发现一个神奇的事情&#xff0c;我一个97年的朋友居然已经当上了测试项目组长&#xff0c;据我所知他去年还是在深圳的一家创业公司做苦逼的测试狗&#xff0c;短短8个月&#xff0c;到底发生了什么&#xff1f; 于是我立刻私聊他八卦一番。 原来他所在的公司最近正在裁…...

>>数据管理:DAMA简介「考试和续期」

关于DAMA,这里就不再多做描述,可以参考以前写的一些简介或官方介绍。下面就考试再做一些详细介绍。 1 区别 CDGA:数据治理工程师(Certified Data Governance Associate),“DAMA中国”组织的数据治理方面的职业认证考试。 CDGP:数据治理专家(Certified Data Governa…...

React的生命周期详细讲解

什么是生命周期&#xff1f; 所谓的React生命周期&#xff0c;就是指组件从被创建出来&#xff0c;到被使用&#xff0c;最后被销毁的这么一个过程。而在这个过程中&#xff0c;React提供了我们会自动执行的不同的钩子函数&#xff0c;我们称之为生命周期函数。**组件的生命周期…...