C++笔记——第十三篇 种一颗 AVL树,长大变成 红黑树,开出了 map和set

news2025/1/25 9:10:10

 


目录

一、引入

1. 关联式容器

二、键值对

三、树形结构的关联式容器

3.1 set

3.1.1 set的介绍

3.1.2 set的使用 

3.2 map3.2.1 map的介绍 

3.2.2 map的使用

3.3 multiset

        3.3.1 multiset的介绍

3.4 multimap

        3.4.1 multimap的介绍 

 四、底层结构

4.1 AVL 树

4.1.1 AVL树的概念

4.1.2 AVL树节点的定义

4.1.3 AVL树的插入

4.1.4 AVL树的旋转

        1. 新节点插入较高左子树的左侧---左左:右单旋

        2. 新节点插入较高右子树的右侧---右右:左单旋 

        3. 新节点插入较高左子树的右侧---左右:先左单旋再右单旋 

         4. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋

4.1.5 AVL树的验证

4.1.6 AVL树的性能

4.2 红黑树

4.2.1 红黑树的概念

4.2.2 红黑树的性质

4.2.3 红黑树结构

4.2.5 红黑树的插入操作



一、引入



1. 关联式容器



在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、forward_list(C++11)等

这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身


关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。



二、键值对




用来表示具有一 一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息
 



三、树形结构的关联式容器



STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结构的关联式
容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。下面一依次介绍每一个容器


3.1 set

3.1.1 set的介绍


1.set是按照一定次序存储元素的容器


2. 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。


3. 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。


4. set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。


5. set在底层是用二叉搜索树(红黑树)实现的。


注意:
1. 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,

set中只放value,但在底层实际存放的是由<value, value>构成的键值对。


2. set中插入元素时,只需要插入value即可,不需要构造键值对。


3. set中的元素不可以重复(因此可以使用set进行去重)


4. 使用set的迭代器遍历set中的元素,可以得到有序序列


5. set中的元素默认按照小于来比较


6. set中查找某个元素,时间复杂度为:O(logN)也就是 树的高度


7. set中的元素不允许修改


8. set中的底层使用二叉搜索树(红黑树)来实现。


3.1.2 set的使用 


1. set的模板参数列表

template < class T,                        // set::key_type/value_type           
class Compare = less<T>,        // set::key_compare/value_compare          
class Alloc = allocator<T>      // set::allocator_type           
         > class set;

T: set中存放元素的类型,实际在底层存储<value, value>的键值对。
Compare:set中元素默认按照小于来比较
Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理

2. set的构造

函数声明 ——功能介绍


set (const Compare& comp = Compare(), const Allocator& =Allocator() );
构造空的set


set (InputIterator first, InputIterator last, const Compare&comp = Compare(),

const Allocator& = Allocator() );


用[first, last)区间中的元素构造set


set ( const set<Key,Compare,Allocator>& x); 

set的拷贝构造

3. set的迭代器 

函数声明 功能介绍
iterator begin() ——返回set中起始位置元素的迭代器
iterator end() ——返回set中最后一个元素后面的迭代器


const_iterator cbegin() const ——返回set中起始位置元素的const迭代器
const_iterator cend() const ——返回set中最后一个元素后面的const迭代器


reverse_iterator rbegin() ——返回set第一个元素的反向迭代器,即end
reverse_iterator rend()——返回set最后一个元素下一个位置的反向迭代器,即begin


const_reverse_iterator  crbegin() const ——返回set第一个元素的反向const迭代器,即cend
const_reverse_iterator crend() const ——返回set最后一个元素下一个位置的反向const迭代器,即crbegin

 4. set的容量

函数声明 ——功能介绍
bool empty ( ) const ——检测set是否为空,空返回true,否则返回true
size_type size() const ——返回set中有效元素的个数

5. set修改操作 

函数声明 功能介绍
pair<iterator,bool> insert (const value_type& x )
在set中插入元素x,实际插入的是<x, x>构成的键值对,如果插入成功,返回<该元素在set中的位置,true>,如果插入失败,说明x在set中已经存在,返回<x在set中的位置,false>


void erase ( iterator position ) ——删除set中position位置上的元素


size_type erase ( const key_type& x )——删除set中值为x的元素,返回删除的元素的个数


void erase ( iterator first,iterator last )——删除set中[first, last)区间中的元素,左闭右开


void swap (set<Key,Compare,Allocator>&st );——交换set中的元素


void clear ( ) ——将set中的元素清空


iterator find ( const key_type& x ) const——返回set中值为x的元素的位置


size_type count ( const key_type& x ) const——返回set中值为x的元素的个数

 


3.2 map
3.2.1 map的介绍 


1. map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。


2. 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为 pair:     typedef pair value_type;


3. 在内部,map中的元素总是按照键值key进行比较排序的。


4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。


5. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value


6. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。



3.2.2 map的使用



1. map的模板参数说明

key: 键值对中key的类型
T: 键值对中value的类型
Compare: 比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器
注意:在使用map时,需要包含头文件。 

2. map的构造

函数声明 ——功能介绍
map() ——构造一个空的map

3. map的迭代器

函数声明—— 功能介绍
begin()和end() ——begin:首元素的位置,end最后一个元素的下一个位置


cbegin()和cend() ——与begin和end意义相同,但cbegin和cend所指向的元素不能修改

rbegin()和rend()——反向迭代器,rbegin在end位置,rend在begin位置,其++和--操作与begin和end操作移动相反


crbegin()和crend()——与rbegin和rend位置相同,操作相同,但crbegin和crend所指向的元
素不能修改

4. map的容量与元素访问 

函数声明 ——功能简介
bool empty ( ) const——检测map中的元素是否为空,是返回true,否则返回false


size_type size() const ——返回map中有效元素的个数


mapped_type& operator[] (const key_type& k)——返回去key对应的value

 注意:在元素访问时,有一个与operator[]类似的操作at()(该函数不常用)函数,都是通过key找到与key对应的value然后返回其引用,不同的是:当key不存在时,operator[]用默认value与key构造键值对然后插入,返回该默认valueat()函数直接抛异常

 5. map中元素的修改

函数声明 功能简介
pair<iterator,bool> insert (const value_type& x )
在map中插入键值对x,注意x是一个键值对,返回值也是键值对:iterator代表新插入元素的位置,bool代表释放插入成功


void erase ( iterator position ) ——删除position位置上的元素

size_type erase ( const key_type& x )——删除键值为x的元素


void erase ( iterator first, iterator last )——删除[first, last)区间中的元素


void swap (map<Key,T,Compare,Allocator>&mp )——交换两个map中的元素


void clear ( )—— 将map中的元素清空

iterator find ( const key_type& x)——在map中插入key为x的元素,找到返回该元素的位置
的迭代器,否则返回end


const_iterator find ( const key_type& x ) const
——在map中插入key为x的元素,找到返回该元素的位置的const迭代器,否则返回cend


size_type count ( const key_type& x ) const——返回key为x的键值在map中的个数,注意map中key是唯一的,因此该函数的返回值要么为0,要么为1,因此也可以用该函数来检测一个key是否在map中

 1. map中的的元素是键值对
2. map中的key是唯一的,并且不能修改
3. 默认按照小于的方式对key进行比较
4. map中的元素如果用迭代器去遍历,可以得到一个有序的序列
5. map的底层为平衡搜索树(红黑树),查找效率比较高
6. 支持[]操作符,operator[]中实际进行插入查找。


3.3 multiset
3.3.1 multiset的介绍

1. multiset是按照特定顺序存储元素的容器,其中元素是可以重复的。


2. 在multiset中,元素的value也会识别它(因为multiset中本身存储的就是<value, value>组成的键值对,因此value本身就是key,key就是value,类型为T). multiset元素的值不能在容器中进行修改(因为元素总是const的),但可以从容器中插入或删除。


3. 在内部,multiset中的元素总是按照其内部比较规则(类型比较)所指示的特定严格弱排序准则进行排序。

4. multiset容器通过key访问单个元素的速度通常比unordered_multiset容器慢,但当使用迭代器遍历时会得到一个有序序列。


5. multiset底层结构为二叉搜索树(红黑树)。


注意:
1. multiset中,底层中存储的是<value, value>的键值对
2. mtltiset的插入接口中只需要插入即可
3. 与set的区别是,multiset中的元素可以重复,set是中value是唯一的
4. 使用迭代器对multiset中的元素进行遍历,可以得到有序的序列
5. multiset中的元素不能修改
6. 在multiset中找某个元素,时间复杂度为O(logN)
7. multiset的作用:可以对元素进行排序

 


3.4 multimap
3.4.1 multimap的介绍 


1. Multimaps是关联式容器,它按照特定的顺序,存储由key和value映射成的键值对<key, value>,其中多个键值对之间的key是可以重复的。


2. 在multimap中,通常按照key排序和惟一地标识元素,而映射的value存储与key关联的内容。key和value的类型可能不同,通过multimap内部的成员类型value_type组合在一起,value_type是组合key和value的键值对:
typedef pair<const Key, T> value_type;


3. 在内部,multimap中的元素总是通过其内部比较对象,按照指定的特定严格弱排序标准对key进行排序的。


4. multimap通过key访问单个元素的速度通常比unordered_multimap容器慢,但是使用迭代器直接遍历multimap中的元素可以得到关于key有序的序列。


5. multimap在底层用二叉搜索树(红黑树)来实现。

注意:multimap和map的唯一不同就是:map中的key是唯一的,而multimap中key是可以重复的

 1. multimap中的key是可以重复的。
2. multimap中的元素默认将key按照小于来比较
3. multimap中没有重载operator[]操作



 四、底层结构



map、set等关联式容器的底层结构是对二叉树进行了平衡处理,即采用平衡树来实现。


4.1 AVL 树



4.1.1 AVL树的概念


当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。

它的左右子树都是AVL树
左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)

 图上的蓝色数字即为该节点的左右子树高度之差。

如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在 ,搜索时
间复杂度O( logN)。


4.1.2 AVL树节点的定义


template<class T>
struct AVLTreeNode
{
    AVLTreeNode(const T& data)
        : _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr)
        , _data(data), _bf(0)
    {}
    AVLTreeNode<T>* _pLeft; // 该节点的左孩子
    AVLTreeNode<T>* _pRight; // 该节点的右孩子
    AVLTreeNode<T>* _pParent; // 该节点的双亲
    T _data;
    int _bf; // 该节点的平衡因子
};


4.1.3 AVL树的插入



AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。

那AVL树的插入过程可以分为两步:
1. 按照二叉搜索树的方式插入新节点
2. 调整节点的平衡因子 

pCur插入后,pParent的平衡因子一定需要调整,在插入之前,pParent
的平衡因子分为三种情况:-1,0, 1, 分以下两种情况:
1. 如果pCur插入到pParent的左侧,只需给pParent的平衡因子-1即可


2. 如果pCur插入到pParent的右侧,只需给pParent的平衡因子+1即可
此时:pParent的平衡因子可能有三种情况:0,正负1, 正负2


1. 如果pParent的平衡因子为0,说明插入之前pParent的平衡因子为正负1,插入后被调整成0,此
时满足AVL树的性质,插入成功
2. 如果pParent的平衡因子为正负1,说明插入前pParent的平衡因子一定为0,插入后被更新成正负1,此时以pParent为根的树的高度增加,需要继续向上更新
3. 如果pParent的平衡因子为正负2,则pParent的平衡因子违反平衡树的性质,需要对其进行旋转
处理 


4.1.4 AVL树的旋转


        1. 新节点插入较高左子树的左侧---左左:右单旋

 左图为F节点即为根节点,右图为F节点上面还有节点。(红黑树也会用到旋转哦!)

void RotateR(Node* parent)
{
    Node* subL = parent->_left;
    Node* subLR = subL->_right;

    parent->_left = subLR;
     if (subLR)
        subLR->_parent = parent;

    Node* parentParent = parent->_parent;

    subL->_right = parent;
    parent->_parent = subL;

     if (parent == _root)
      {
        _root = subL;
        _root->_parent = nullptr;
        }
        else
        {
       if (parentParent->_left == parent)
        parentParent->_left = subL;
       else
        parentParent->_right = subL;

      subL->_parent = parentParent;
     }
}

        2. 新节点插入较高右子树的右侧---右右:左单旋 

以60节点作为cur节点,30节点是parent节点。60节点左侧连接30节点,把60节点的左子树给30节点,当30节点的右子树。返回60节点作为parent节点

        3. 新节点插入较高左子树的右侧---左右:先左单旋再右单旋 

 以60节点作为cur节点,30节点是parent节点。找到60节点左子树的最左侧,连接30节点,把60节点的左子树给30节点,当30节点的右子树。

以60节点作为cur节点,90节点作为parent节点,60节点右侧连接90节点,右子树交由90节点作为90的左子树。

void _RotateLR(PNode pParent)
{
    PNode pSubL = pParent->_pLeft;
    PNode pSubLR = pSubL->_pRight;
// 旋转之前,保存pSubLR的平衡因子,旋转完成之后,需要根据该平衡因子来调整其他节点的平
衡因子
    int bf = pSubLR->_bf;
// 先对30进行左单旋
    _RotateL(pParent->_pLeft);
// 再对90进行右单旋
    _RotateR(pParent);
    if(1 == bf)
        pSubL->_bf = -1;
    else if(-1 == bf)
        pParent->_bf = 1;
}

         4. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋

60节点cur,90节点parent,60节点右侧连接90,60的右子树交给90的左侧。

60节点cur,30节点parent,60左侧连接30,60的左子树交给30当右子树。

 假如以pParent为根的子树不平衡,即pParent的平衡因子为2或者-2,分以下情况考虑


1. pParent的平衡因子为2,说明pParent的右子树高,设pParent的右子树的根为pSubR


当pSubR的平衡因子为1时,执行左单旋(右侧高,插在了右侧)


当pSubR的平衡因子为-1时,执行右左双旋(左侧高,插在了较高右子树的左侧)



2. pParent的平衡因子为-2,说明pParent的左子树高,设pParent的左子树的根为pSubL


当pSubL的平衡因子为-1是,执行右单旋(左侧高,插在了在左侧)


当pSubL的平衡因子为1时,执行左右双旋(右侧高,插在了较高左子树的右侧)



旋转完成后,原pParent为根的子树个高度降低,已经平衡,不需要再向上更新

左边高进行右单旋,右边高左单旋 


4.1.5 AVL树的验证



AVL树是在二叉搜索树的基础上加入了平衡性的限制,因此要验证AVL树,可以分两步:
1. 验证其为二叉搜索树
        如果中序遍历可得到一个有序的序列,就说明为二叉搜索树
2. 验证其为平衡树
        每个节点子树高度差的绝对值不超过1(注意节点中如果没有平衡因子)
        节点的平衡因子是否计算正确 


4.1.6 AVL树的性能



AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度,即 O(logN)。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:
插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。
因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合 



4.2 红黑树



4.2.1 红黑树的概念



红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的


4.2.2 红黑树的性质



1. 每个结点不是红色就是黑色
2. 根节点是黑色的
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点


4.2.3 红黑树结构



为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了与根节点进行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft域指向红黑树中最小的节点,_pRight域指向红黑树中最大的节点


4.2.5 红黑树的插入操作


1. 按照二叉搜索的树规则插入新节点

2. 检测新节点插入后,红黑树的性质是否造到破坏

当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连在一起的红色节点,此时需要对红黑树分情况来讨论:
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点

        情况一: cur为红,p为红,g为黑,u存在且为红

        将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。

        


        情况二: cur为红,p为红,g为黑,u不存在/u为黑 

        p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,
        p为g的右孩子,cur为p的右孩子,则进行左单旋转
        p、g变色--p变黑,g变红


        情况三: cur为红,p为红,g为黑,u不存在/u为黑 

        p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相反,
        p为g的右孩子,cur为p的左孩子,则针对p做右单旋转
        则转换成了情况2

 


 

                      

 

 

 

 

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

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

相关文章

实验进行套路【1】

实验是用来证明猜想正确与否的关键方法&#xff0c;做好实验对提升论文发表效率至关重要。本篇博客结合自身经历总结做实验的方法论&#xff0c;希望能对读者有用。本篇不会从技术实现角度来介绍做实验的方法&#xff0c;而会从指导思想角度入手。如果你是一个科研工作者的话&a…

AIPRM for ChatGPT插件让ChatGPT如虎添翼

ChatGPT大热&#xff0c;家人们都申请到了账号&#xff0c;可是总是在一问一答的基础上来完成基本的应用&#xff0c;而不能很好的使用「咒语」&#xff08;Prompt&#xff09;&#xff0c;收获的答案不是通过很多次的反复问获取答案&#xff0c;就是获取的不是想要的答案。所以…

最重要的 JVM 参数总结

1.概述 在本篇文章中&#xff0c;你将掌握最常用的 JVM 参数配置。 2.堆内存相关 Java 虚拟机所管理的内存中最大的一块&#xff0c;Java 堆是所有线程共享的一块内存区域&#xff0c;在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例&#xff0c;几乎所有的对象实…

Auto-GPT来啦,手把手教你安装更稳定的stable的Auto-GPT,实现两个AutoGPT合作执行任务,AutoGPT代理同时执行任务

进入Auto-GPT项目 https://github.com/Significant-Gravitas/Auto-GPT 应该在git bash还是git cmd命令窗口敲以上命令 应该在git bash窗口中敲git命令。 Git Bash是Windows上的一个搭载了Git的终端仿真器&#xff0c;提供了类似Unix的命令行环境&#xff0c;使得在Windows上…

深入浅出剖析JAVA多线程原理

1. 线程基础知识 1.1 线程与进程 1.1.1 进程 ●程序由指令和数据组成&#xff0c;但这些指令要运行&#xff0c;数据要读写&#xff0c;就必须将指令加载至 CPU&#xff0c;数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理…

nacos登录 提示权限认证失败 没有命名空间的访问权限

前言 环境&#xff1a;centos7.9 nacos-2.2.2 问题描述 最近在部署nacos-2.2.2版本的时候&#xff0c;这是目前2023年4月份最新版本&#xff0c;发现按照start.out日志给出的登录地址&#xff0c;http://192.168.158.128:8848/nacos/index.html登录&#xff0c;发现总是提示…

一图看懂系列——文件处理模块(总目录)

本文由 大侠(AhcaoZhu)原创&#xff0c;转载请声明。 链接: https://blog.csdn.net/Ahcao2008 一图看懂系列——文件处理模块&#xff08;总目录&#xff09; 摘要目录注&#xff1a; 摘要 本文介绍了文件处理的模块的目录。 以前每个模块单独撰文&#xff0c;现在把它们归集起…

node版本管理nvm的使用

在很多情况下对node版本需要安装多版本的控制&#xff0c;如何快速的切换node版本&#xff0c;请在配置完node的环境变量的基础上&#xff0c;阅读这篇文章。这里需要介绍nvm这个工具&#xff1a; 一、下载 官方下载地址&#xff1a;https://github.com/coreybutler/nvm-wind…

使用Python创建分形图案

分形是无限复杂的模式&#xff0c;在不同的尺度上具有自相似性。例如&#xff0c;一棵树的树干会分裂成更小的树枝。这些树枝又分裂成更小的树枝&#xff0c;以此类推。 通过编程的方式生成分形&#xff0c;可以将简单的形状变成复杂的重复图案。 本文将探讨如何利用一些简单…

ThinkSystem DM 系列混合闪存 —— 快速、灵活、可靠、安全

ThinkSystem DM 系列混合闪存 —— 快速、灵活、可靠、安全 统一存储优化混合云部署具备一流数据管理的横向扩展混合存储 挑战 实现跨闪存、磁盘和云数据驱动型业务 存储已从 IT 事后思考的问题发展成公司基础架构至关重要的组件。企业感觉迫切需要跟上爆炸式增长的数据。标…

抖音滑块以及轨迹分析

声明 本文以教学为基准、本文提供的可操作性不得用于任何商业用途和违法违规场景。 本人对任何原因在使用本人中提供的代码和策略时可能对用户自己或他人造成的任何形式的损失和伤害不承担责任。 如有侵权,请联系我进行删除。 我们在web端打开用户主页的时候,时不时的会出现滑…

tf-idf+lda分析多篇文章摘要

import pandas as pd import numpy as np import matplotlib.pyplot as plt #import seaborn as sns plt.rcParams[font.sans-serif] [KaiTi] #指定默认字体 SimHei黑体 plt.rcParams[axes.unicode_minus] False #解决保存图像是负号 import jieba import os # stop_list …

RabbitMQ的介绍和安装

文章目录 1.1 RabbitMQ介绍1.2 RabbitMQ的安装1.2.1 下载镜像1.2.2 安装启动1.2.3 测试 1.1 RabbitMQ介绍 RabbitMQ是一个开源的消息队列中间件&#xff0c;可以用于构建分布式应用程序&#xff0c;使应用程序能够快速、可靠地处理大量消息。它实现了AMQP&#xff08;高级消息队…

Vue安装脚手架 vue-cli

Vue 脚手架是 Vue 官方提供的标准化开发工具&#xff08;开发平台&#xff09; 在安装脚手架之前我们还需要安装 Node.JS 和 npm 全局安装 vue-cli 【初次安装】: 首先打开命令行 输入 npm install -g vue/cli 再按回车键 安装脚手架 安装命令行&#xff1a; npm install …

多层LCP技术的毫米波段超宽带槽天线设计

1、引言 无线宽带通信的迅猛发展需要能传输高比特率的新型宽带天线。毫米波段是短距离高比特率无线通信的重要波段。所以近年来&#xff0c;毫米波段小型高性能的超宽带天线吸引了大量的研究人员在这方面进行研究工作。 天线设计的另一个重要趋势是集成天线的射频前端电路。在…

Linux/Unix编写sh脚本,设置开机自动启动脚本在linux下

1编写.sh脚本的基本步骤&#xff1a; 创建一个新的文本文件&#xff0c;使用一个文本编辑器&#xff0c;比如vi或nano&#xff0c;来编写脚本。你需要保存文件为.sh扩展名&#xff0c;以便让系统知道这是一个shell脚本文件。 touch myprogram.sh #!/bin/sh# 进入C程序所在目…

基于JAVA的网络通讯系统设计与实现

一般来说&#xff0c;聊天工具大多数由客户端程序和服务器程序,外加服务器端用于存放客户数据的数据库组成&#xff0c;本系统采用客户机/服务器架构模式&#xff0c;通过Java提供的Socket类来连接客户机和服务器并使客户机和服务器之间相互通信&#xff0c;由于聊天是多点对多…

HTB-Cascade

HTB-Cascade 信息收集立足s.smith -> arksvc使用脚本获取CascAudit.exe加密的密码明文修改IL指令获取 arksvc -> administrator 信息收集 查看smbclient。 rpcclient空密码连接并收集信息。 收集到用户列表&#xff0c;此外没有有意思的信息。 CascGuest arksvc s.smi…

Qt/QML编程学习之心得:二进制兼容、私有实现及Q_D/Q_Q指针(三)

QML画好或说描述好界面之后,实现部分通过C++实现,Qt采用了私有实现的设计模式解决了二进制兼容的问题。 二进制兼容问题描述: 现在有一个Widget, 包含一个私有成员变量m_geometry ,编译 Widget 并且发布为MyWidgetLib 1.0 。该应用程序名字为TestAPP,基于 Qt 4.9。 cla…

【Linux网络服务】Linux网络设置

一、查看网络配置 1.1ifconfig 1.2ip a 1.3什么是mtu 最大传输单元MTU&#xff0c;是指网络能够传输的最大数据包大小&#xff0c;以字节为单位。MTU的大小决定了发送端一次能够发送报文的最大字节数。如果MTU超过了接收端所能够承受的最大值&#xff0c;或者是超过了发送路径…