C++进阶: 红黑树及map与set封装

红黑树总结整理

红黑色概述:

红黑树整理与AVL树类似,但在对树的平衡做控制时,AVL树会比红黑树更严格。

AVL树是通过引入平衡因子的概念进行对树高度控制。

红黑树则是对每个节点标记颜色,对颜色进行控制。

红黑树控制规则:

1.每个节点不是红色就是黑色

2.根节点必须是黑色

3.如果一个节点是红色,那么此节点的左右孩子节点必须是黑色。也就是说在一条路径上,没有连续的红色节点。

4.对任意一个节点,从该节点到其所有的NULL节点上路径的黑色节点数量均相等。

这样组合的特性是:树的最长路径不会超过最短路径的两倍。

最长路径<=2*最短路径

红黑树保证效率的方式就是遵守红黑树的4条规则。

已知红黑树从根节点到任意路径上的NULL节点中都拥有相同数量的黑色节点。

在极端情况下,一条路径全色黑色节点,我们称之为最短路径用bh表示。

又根据规则3,一个红节点它的左右两个孩子就必须是黑色节点,可以反推,一个红色节点的父亲节点是一个黑色节点。所以最长路径的组成就变成了间隔相邻的红黑节点,共有2bh个。

所以结论就为:

        红黑树的高度差控制在bh<=h<=2bh

红黑树的效率:

红黑树的效率与AVL树相差无几,假设 N为红黑树的节点数量,h为最短路径。

        所以求h就等于log以2为底的N。效率也就是logN级别

红黑树的插入:

红黑树的插入必须遵守四个规则。在插入空树时,根节点为黑色。而在插入非空树时,新增节点的初始颜色必须为红色。这是因为若初始颜色为黑色,会导致某一路径的黑色节点数量多于其他路径,违反规则4,并且很难维护。因此,插入时新节点的颜色应始终为红色。

当我们新插入节点为红色时,我们检查父节点,如果父节点为黑色,那么直接完成插入,如果父节点为红色,就违反了规则3,需要进行特殊处理。

先将新插入的节点标记为 c(cur),那么它的父亲为 p(parent) ,它的爷爷为g(grandfather)它的爷爷绝对是黑色节点,如果不为黑色,那么这颗红黑树早就违反了规则3.

并且还需要g节点找到并标记u(uncle)节点,也就是和p同级的兄弟节点。

情况一:变色

情况二:单旋+变色

c,p节点都为红色,那么u节点除了红色就只有存在且为黑色或不存在两种情况。

如果u节点不存在,那么c是新增节点

如果u存在且为黑色,那么c节点绝对不是叶子节点,c节点下还有子树。只不过是c节点的子树变化导致c变成了红色。

那么如何验证这个结论呢?

观察上图,如果u有节点且为黑色的话,此时就以及违反了规则4,所有路径的黑色节点数量不对等。

当u存在且为黑色的时候,C必然不是新增节点,它只可能是a或b子树里进行变换后当值c变成了红色。所以当我们在进行颜色变化的时候,需要循环向上变化。只有当p节点为黑色才停止。

u不存在或u存在且为黑色时候,我们单纯变色是不行的

会发现,当我们仅仅只是变色的话,就会违反规则4,根到左路径会比根到右路径的黑色节点个数多一。

当我们u为空时候,就需要进行一次右旋,让子树达到平衡后更新p节点为黑色,g节点为红色就能确保4条规则都不触犯,并且因为p已经变成了黑色,就不需要再往上跟新节点。

当u不为空时,c子树必然有黑色节点。同样的我们进行右旋后,将p变为黑色,g变成红色后还是遵守着4条规则。

这里也仅仅介绍右旋的情况,如果是在左边的话就同理进行左旋加变色,

情况三:双选+变色

c节点也不会一直如我们所愿,只插入在绝对的左边或绝对的右边,这时候就需要经过两次旋转,才能完成红黑树的变化。

当c在p的右边的时候就必须要通过双选,当c转完两次的时候,c来到最上层,此时将c节点变为黑色,将g节点变为红色,c又恰好为上层节点,就可以直接退出循环。

当u不为空且为黑色时

同样的,u为黑色那么c节点肯定不是新插入的节点,c原本为黑色节点。因为新插入的节点在c的子树内,导致子树的变化影响了C节点从黑色变为红色才发生的双选+变色。

        最后戳了c在左子树,c的情况也会在右子树出现,所实现的方法也是也要的,并不需要特别说明举例。

        以下是红黑树的代码

#pragma once
#include<iostream>
using namespace std;
enum Color { red ,black };template<class K, class V>
struct TreeNode
{pair<K, V> _val;TreeNode* _left;TreeNode* _right;TreeNode* _parent;Color _col;TreeNode(const pair<K, V>& val):_val(val),_left(nullptr),_right(nullptr),_parent(nullptr),_col(red){}
};template<class K,class V>
class RBTree
{typedef TreeNode<K, V> Node;
public:bool Insert(const pair<K,V> &val){if(_root==nullptr){_root = new Node(val);_root->_col = black;return true;}Node* parent = nullptr;Node* cur = _root;while (cur){parent = cur;if(cur->_val.first>val.first){cur = cur->_left;}else if (cur->_val.first < val.first){cur = cur->_right;}else{return false;}}cur = new Node(val);if (parent->_val.first>cur->_val.first){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;//判断红黑树是否要更新while (parent&&parent->_col!=black){Node* grandfather = parent->_parent;Node* uncle;if (grandfather->_left==parent){uncle = grandfather->_right;if (uncle&&uncle->_col==red)//情况一:只变色{grandfather->_col = red;uncle->_col = parent->_col = black;cur = grandfather;parent = cur->_parent;}else{if (parent->_left==cur)//情况二:单旋+变色{TurnR(grandfather);grandfather->_col = red;parent->_col = black;break;}else//情况三:双循+变色{TurnL(parent);TurnR(grandfather);cur->_col = black;grandfather->_col = red;break;}}}else{uncle = grandfather->_left;if (uncle && uncle->_col == red)//情况一:只变色{grandfather->_col = red;uncle->_col = parent->_col = black;cur = grandfather;parent = cur->_parent;}else{if (parent->_right == cur)//情况二:单旋+变色{TurnL(grandfather);grandfather->_col = red;parent->_col = black;break;}else//情况三:双循+变色{TurnR(parent);TurnL(grandfather);cur->_col = black;grandfather->_col = red;break;}}}}_root->_col = black;}bool Check(Node*_root,int ibnum,const int rnum){if (_root==nullptr){if (ibnum != rnum) {cout << "存在黑色结点的数量不相等的路径" << endl;return false;}return true;}if (_root->_col==red&&_root->_parent->_col==red){cout << _root->_val.first<< "存在连续的红色结点" << endl;return false;}if (_root->_col==black){++ibnum;}return Check(_root->_left, ibnum, rnum) && Check(_root->_right, ibnum, rnum);}bool IsBalance(){if (_root==nullptr||_root->_col==red){return false;}int rnum = 0;Node* cur = _root;while (cur){if (cur->_col == black)rnum++;cur = cur->_left;}return Check(_root, 0, rnum);}// blackNum 根到当前结点的黑色结点的数量//bool Check(Node* root, int blackNum, const int refNum)//{//	if (root == nullptr)//	{//		// 前序遍历走到空时,意味着一条路径走完了//		//cout << blackNum << endl;//		if (refNum != blackNum)//		{//			cout << "存在黑色结点的数量不相等的路径" << endl;//			return false;//		}//		return true;//	}//	// 检查孩子不太方便,因为孩子有两个,且不一定存在,反过来检查父亲就方便多了//	if (root->_col == red && root->_parent->_col == red)//	{//		cout << root->_val.first << "存在连续的红色结点" << endl;//		return false;//	}//	if (root->_col == black)//	{//		blackNum++;//	}//	return Check(root->_left, blackNum, refNum)//		&& Check(root->_right, blackNum, refNum);//}//bool IsBalance()//{//	if (_root == nullptr)//		return true;//	if (_root->_col == red)//		return false;//	// 参考值//	int refNum = 0;//	Node* cur = _root;//	while (cur)//	{//		if (cur->_col == black)//		{//			++refNum;//		}//		cur = cur->_left;//	}//	return Check(_root, 0, refNum);//}void InOrder(){_InOrder(_root);}protected:void _InOrder(Node*cur){if (cur==nullptr){return;}_InOrder(cur->_left);cout << "first:" << cur->_val.first << " second:" << cur->_val.second << endl;_InOrder(cur->_right);}void TurnR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;subL->_right = parent;if (subLR){subLR->_parent = parent;}Node* Pparent = parent->_parent;parent->_parent = subL;if (Pparent){if (Pparent->_left == parent){Pparent->_left = subL;}else{Pparent->_right = subL;}}subL->_parent = parent;}void TurnL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;subR->_left = parent;if (subRL) { subRL->_parent = parent; }Node* Pparent = parent->_parent;parent->_parent = subR;if (Pparent){if (Pparent->_left == parent){Pparent->_left = subR;}else{Pparent->_right = subR;}}subR->_parent = parent;}private:Node* _root=nullptr;
};

封装map与set:

        在map与set中都是对底层的红黑树进行上层的封装。

        封装后的红黑树:

#pragma once
#include<iostream>
using namespace std;enum color
{red,black
};template<class T>
struct TreeNode
{TreeNode(const T&ky):_ky(ky),_col(red),_parent(nullptr),_left(nullptr),_right(nullptr){}T _ky;color _col;TreeNode* _parent;TreeNode* _left;TreeNode* _right;
};template<class T, class Ref,class Ptr >
struct Tree_Iterator
{typedef TreeNode<T> Node;typedef Tree_Iterator<T,Ref,Ptr> Self;Tree_Iterator(Node* node, Node* root):_node(node), _root(root){}Ref operator *(){return _node->_ky;}Ptr operator ->(){return &_node->_ky;}Self&operator++(){if (_node->_right){Node* minleft = _node->_right;while (minleft->_left){minleft = minleft->_left;}_node = minleft;}else{Node* cur = _node;Node* parent = cur->_parent;while (parent&&parent->_right==cur){cur = parent;parent = parent->_parent;}_node = parent;}return *this;}Self &operator --(){if (_node==nullptr){Node* cur = _root;while (cur&&cur->_right){cur = cur->_right;}_node = cur;}else if (_node->_left){Node* maxright = _node->_left;while (maxright->_right){maxright = maxright->_right;}_node = maxright;}else{Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_left == cur){cur = parent;parent = parent->_parent;}_node = parent;}return *this;}bool operator !=(const Self&kv ){return _node != kv._node;}bool operator ==(const Self& kv){return _node == kv._node;}Node* _node;Node* _root;};template<class K,class T,class KeyOFT>
class RBTree
{typedef TreeNode<T> Node;
public:typedef Tree_Iterator<T,T&,T*> Iterator;typedef Tree_Iterator<T, const T&, const T*> Const_Iterator;Iterator Begin(){Node* cur = _root;while (cur&&cur->_left){cur = cur->_left;}return Iterator(cur, _root);}Iterator End(){return Iterator(nullptr, _root);}Const_Iterator CBegin()const {Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return Iterator(cur, _root);}Const_Iterator CEnd()const {return Iterator(nullptr, _root);}pair<Iterator,bool> Insert(const T&ky){if(!_root){_root = new Node(ky);_root->_col = black;return make_pair(Iterator(_root,_root),true);}Node* cur = _root;Node* parent = nullptr;KeyOFT kot;while (cur){if (kot(cur->_ky) > kot(ky)){parent = cur;cur = cur->_left;}else if (kot(cur->_ky) < kot(ky)){parent = cur;cur = cur->_right;}else{return make_pair(Iterator(cur, _root), false);;}}cur = new Node(ky);Node* node = cur;if (kot(parent->_ky)>kot(cur->_ky)){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;while (parent&&parent->_col==red){Node* garendparent = parent->_parent;Node* uncle;if (garendparent->_left==parent)//只变色{uncle = garendparent->_right;if (uncle&&uncle->_col==red){uncle->_col = parent->_col = black;garendparent->_col = red;cur = garendparent;parent = cur->_parent;}else {if (parent->_left==cur)//单选变色{TurnR(garendparent);parent->_col = black;cur->_col = garendparent->_col = red;break;}else//双旋变色{TurnL(parent);TurnR(garendparent);cur->_col = black;parent->_col = garendparent->_col = red;break;}}}else{uncle = garendparent->_left;if (uncle && uncle->_col == red){uncle->_col = parent->_col = black;garendparent->_col = red;cur = garendparent;parent = cur->_parent;}else{if (parent->_right == cur)//单选变色{TurnL(garendparent);parent->_col = black;cur->_col = garendparent->_col = red;break;}else//双旋变色{TurnR(parent);TurnL(garendparent);cur->_col = black;parent->_col = garendparent->_col = red;break;}}}}_root->_col = black;return make_pair(Iterator(node, _root), true);}Node*Find(const K &val){Node* cur = _root;KeyOFT kot;while (cur){if (kot(cur->_ky) > val){cur = cur->_left;}else if (kot(cur->_ky) < val){cur = cur->_right;}else{return cur;}}return nullptr;}private:void TurnR(Node*parent){KeyOFT kot;Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if(subLR){subLR->_parent = parent;}subL->_right = parent;Node* Pparent = parent->_parent;parent->_parent = subL;if (!Pparent){subL->_parent = nullptr;_root = subL;}else{if (kot(Pparent->_ky)> kot(subL->_ky)){Pparent->_left = subL;}else{Pparent->_right = subL;}subL->_parent = Pparent;}}void TurnL(Node*parent){KeyOFT kot;Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL){subRL->_parent = parent;}subR->_left = parent;Node* Pparent = parent->_parent;parent->_parent = subR;if (!Pparent){subR->_parent = nullptr;_root = subR;}else{if (kot(Pparent->_ky) > kot(subR->_ky)){Pparent->_left = subR;}else{Pparent->_right = subR;}subR->_parent = Pparent;}}Node* _root = nullptr;
};

        对于map与set在底层用的都是同一颗红黑树,只是通过类模板进行了实例化两份,所以在红黑树的自身的封装中需要改动以下措施:

        1.树节点存储的值只用一个T类,因为编译器不知道要存的是Key模型,还是pair模型。

        2.为红黑树添加迭代器,map与set都支持迭代器访问数据。需要重点注意的是迭代器的++与迭代器的--,这也是封装后的红黑树的重点

                

Self& operator++()(前置递增)

  1. 当前节点有右子树

    • 找到右子树中的最左节点(即右子树中的最小节点),该节点即为当前节点的后继。

    • 例如,若当前节点为 A,右子树为 C,则后继是 C 的最左子节点(假设为 D

    if (_node->_right) {Node* minleft = _node->_right;while (minleft->_left) {minleft = minleft->_left;}_node = minleft;
    }
  2. 当前节点无右子树

    • 从当前节点向上回溯,找到第一个祖先节点,使得当前节点位于该祖先节点的左子树中。

    • 例如,若当前节点为 E,其父节点为 B,祖父节点为 A,则 A 是 E 的后继。

    else {Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_right == cur) {cur = parent;parent = parent->_parent;}_node = parent; // 找到的祖先节点即为后继

Self& operator--()(前置递减)

  1. 当前节点为 nullptr(如 end() 迭代器)

    • 找到树中的最右节点(即最大值节点),作为前驱。

    • 例如,若树为 A(B(D, E), C),则最右节点为 C

    if (_node == nullptr) {Node* cur = _root;while (cur && cur->_right) {cur = cur->_right;}_node = cur; // 指向最大值节点
    }
  2. 当前节点有左子树

    • 找到左子树中的最右节点(即左子树中的最大节点),该节点即为当前节点的前驱。

    • 例如,若当前节点为 A,左子树为 B,则前驱是 B 的最右子节点 E

    else if (_node->_left) {Node* maxright = _node->_left;while (maxright->_right) {maxright = maxright->_right;}_node = maxright;
    }

        还需要注意对于为什么有KeyOFT,是因为我们红黑树在插入时需要进行比较大小,而map插入的是一个pair,而set插入的就只是Key。红黑树本身是并不知道该拿什么进行比较。所以这里传入一个KeyOFT,是上层map或set传入的一个函数模板,map就通过类模板过滤进行pair的first进行比较,set通过自身类模板比较的还是Key。

        封装map:

                map的封装也并没有太大难度,上述写道的类模板比较需要自己写,并且在定义成员变量红黑树的时,第二个类模板应传入的是pair,而不是V。并且map是支持运算符重载[ ],所以我们这里也同样支持,其余的也只是对红黑树的再一次调用。

#pragma once
#include"RBTree.h"namespace cat
{template<class K,class V >class mymap{struct MapOFT{const K &operator ()(const pair<K, V>& kv){return kv.first;}};public:typedef typename RBTree<K, pair<const K, V>, MapOFT>::Iterator iterator;typedef typename RBTree<K, pair<const K,const V>, MapOFT>::Const_Iterator const_iterator;pair<iterator, bool> insert(const pair<K,V> &kv){return _rbt.Insert(kv);}iterator begin(){return _rbt.Begin();}iterator end(){return _rbt.End();}const_iterator cbegin() const {return _rbt.CBegin();}const_iterator cend()const {return _rbt.CEnd();}V& operator[](const K&ky){pair<iterator, bool> ret = _rbt.Insert({ ky,V() });return ret.first->second;}private:RBTree< K, pair<const K,V>, MapOFT> _rbt;};void test_map(){mymap<int, int> m;m.insert({ 1,1 });m.insert({ 5,5 });m.insert({ 2,2 });m.insert({ 6,6 });mymap<int, int>::iterator it = m.begin();while (it != m.end()){//it->first += 1;it->second += 1;cout << it->first << ":" << it->second << endl;++it;}mymap<string, string> dict;dict.insert({ "sort", "排序" });dict.insert({ "left", "左边" });dict.insert({ "right", "右边" });dict["left"] = "左边,剩余";dict["insert"] = "插入";dict["string"];for (auto& kv : dict){cout << kv.first << " " << kv.second << endl;}cout << endl;string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };mymap<string, int> countMap;for (const auto& str : arr){countMap[str]++;}for (const auto& e : countMap){cout << e.first << ":" << e.second << endl;}cout << endl;}}

        封装Set

#pragma once
#include"RBTree.h"namespace cat
{template<class K>class myset{struct SetOFT{const K& operator()(const K& ky){return ky;}};public:typedef typename RBTree<K, K, SetOFT>::Iterator iterator;typedef typename RBTree<K, K, SetOFT>::Const_Iterator const_iterator;pair<iterator,bool> insert(const K& ky){return _rbt.Insert(ky);}iterator begin(){return _rbt.Begin();}iterator end(){return _rbt.End();}const_iterator begin() const {return _rbt.CBegin();}const_iterator end() const{return _rbt.CEnd();}private:RBTree<K, K, SetOFT> _rbt;};void test_set(){myset<int> s;/*s.insert(4);s.insert(1);s.insert(5);s.insert(3);*/int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };for (auto e : a){if(e==14){int x = 1;}s.insert(e);}myset<int>::iterator it = s.begin();// *it += 10;while (it != s.end()){cout << *it << " ";++it;}cout << endl;it = s.end();while (it != s.begin()){--it;cout << *it << " ";}cout << endl;}
}

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

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

相关文章

在Qt中,slots 关键字有什么用?

有下面的Qt代码&#xff1a; #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent nullptr…

列表标签(无序列表、有序列表)

无序列表 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head><…

Kanass基础教程-创建项目

Kanass是一款国产开源免费的项目管理工具&#xff0c;工具简洁易用&#xff0c;开源免费&#xff0c;之前介绍过kanass的一些产品简介及安装配置方法&#xff0c;本文就从如何创建第一个项目来开始kanass上手之旅吧。 1. 创建项目 点击项目->项目添加 按钮进入项目添加页面…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.10 ndarray内存模型:从指针到缓存优化

2.10 ndarray内存模型&#xff1a;从指针到缓存优化 目录 #mermaid-svg-p0zxLYqAnn59O2Xe {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-p0zxLYqAnn59O2Xe .error-icon{fill:#552222;}#mermaid-svg-p0zxLYqAnn59O…

80-《红球姜》

红球姜 红球姜&#xff08;学名&#xff1a;Zingiber zerumbet (L.) Smith&#xff09;是姜科姜属多年生草本植物&#xff0c;根茎块状&#xff0c;株高可达2米。叶片披针形至长圆状披针形&#xff0c;无柄或短柄&#xff1b;总花梗长可达30厘米&#xff0c;花序球果状&#xf…

Hive之数据定义DDL

Hive之数据定义DDL 文章目录 Hive之数据定义DDL写在前面创建数据库查询数据库显示数据库查看数据库详情切换当前数据库 修改数据库删除数据库创建表管理表(内部表)外部表管理表与外部表的互相转换 修改表重命名表增加、修改和删除表分区增加/修改/替换列信息 删除表 写在前面 …

DeepSeek 核心技术全景解析

DeepSeek 核心技术全景解析&#xff1a;突破性创新背后的设计哲学 DeepSeek的创新不仅仅是对AI基础架构的改进&#xff0c;更是一场范式革命。本文将深入剖析其核心技术&#xff0c;探讨 如何突破 Transformer 计算瓶颈、如何在 MoE&#xff08;Mixture of Experts&#xff09…

UE 5.3 C++ 对垃圾回收的初步认识

一.UObject的创建 UObject 不支持构造参数。 所有的C UObject都会在引擎启动的时候初始化&#xff0c;然后引擎会调用其默认构造器。如果没有默认的构造器&#xff0c;那么 UObject 将不会编译。 有修改父类参数的需求&#xff0c;就使用指定带参构造 // Sets default value…

点击WPS 任务栏上的图标,不是马上进入工作页面,而是呈现多个文档页面选择时的处理方法

问题&#xff1a; 点击WPS以后不是直接进入 解决&#xff1a; 首页-配置和修复工具-高级-兼容设置-改为与microsoft office 2010兼容(D)

批量处理多个模型的预测任务

#!/bin/bash# 检查是否传入必要的参数&#xff0c;若未传入参数则打印用法并退出 if [ "$#" -lt 1 ]; thenecho "用法: $0 <file_path>"echo "示例: $0 /home/aistudio/work/PaddleSeg/city/cityscapes_urls_extracted.txt"exit 1 fi# 读取…

【LLM-agent】(task4)搜索引擎Agent

note 新增工具&#xff1a;搜索引擎Agent 文章目录 note一、搜索引擎AgentReference 一、搜索引擎Agent import os from dotenv import load_dotenv# 加载环境变量 load_dotenv() # 初始化变量 base_url None chat_model None api_key None# 使用with语句打开文件&#xf…

【自然语言处理(NLP)】基于Transformer架构的预训练语言模型:BERT 训练之数据集处理、训练代码实现

文章目录 介绍BERT 训练之数据集处理BERT 原理及模型代码实现数据集处理导包加载数据生成下一句预测任务的数据从段落中获取nsp数据生成遮蔽语言模型任务的数据从token中获取mlm数据将文本转换为预训练数据集创建Dataset加载WikiText-2数据集 BERT 训练代码实现导包加载数据构建…

LeetCode435周赛T2贪心

题目描述 给你一个由字符 N、S、E 和 W 组成的字符串 s&#xff0c;其中 s[i] 表示在无限网格中的移动操作&#xff1a; N&#xff1a;向北移动 1 个单位。S&#xff1a;向南移动 1 个单位。E&#xff1a;向东移动 1 个单位。W&#xff1a;向西移动 1 个单位。 初始时&#…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.5 高级索引应用:图像处理中的区域提取

2.5 高级索引应用&#xff1a;图像处理中的区域提取 目录/提纲 #mermaid-svg-BI09xc20YqcpUam7 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-BI09xc20YqcpUam7 .error-icon{fill:#552222;}#mermaid-svg-BI09xc20…

ubuntu直接运行arm环境qemu-arm-static

qemu-arm-static 嵌入式开发有时会在ARM设备上使用ubuntu文件系统。开发者常常会面临这样一个问题&#xff0c;想预先交叉编译并安装一些应用程序&#xff0c;但是交叉编译的环境配置以及依赖包的安装十分繁琐&#xff0c;并且容易出错。想直接在目标板上进行编译和安装&#x…

通过Redisson构建延时队列并实现注解式消费

目录 一、序言二、延迟队列实现1、Redisson延时消息监听注解和消息体2、Redisson延时消息发布器3、Redisson延时消息监听处理器 三、测试用例四、结语 一、序言 两个月前接了一个4万的私活&#xff0c;做一个线上商城小程序&#xff0c;在交易过程中不可避免的一个问题就是用户…

MVC 文件夹:架构之美与实际应用

MVC 文件夹:架构之美与实际应用 引言 MVC(Model-View-Controller)是一种设计模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种架构模式不仅提高了代码的可维护性和可扩展性,而且使得开发流程更加清晰。本文将深入探讨MVC文…

【PyQt】lambda函数,实现动态传递参数

为什么需要 lambda&#xff1f; 在 PyQt5 中&#xff0c;clicked 信号默认会传递一个布尔值&#xff08;表示按钮是否被选中&#xff09;。如果我们希望将按钮的文本内容传递给槽函数&#xff0c;需要通过 lambda 函数显式传递参数。 这样可以实现将按钮内容传递给槽函数&…

pytorch深度Q网络

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 DQN 引入了深度神经网络来近似Q函数&#xff0c;解决了传统Q-learning在处理高维状态空间时的瓶颈&#xff0c;尤其是在像 Atari 游戏这样的复杂环境中。DQN的核心思想是使用神经网络 Q(s,a;θ)Q(s, a; \theta)Q(s,…

Baklib构建高效协同的基于云的内容中台解决方案

内容概要 随着云计算技术的飞速发展&#xff0c;内容管理的方式也在不断演变。企业面临着如何在数字化转型过程中高效管理和协同处理内容的新挑战。为应对这些挑战&#xff0c;引入基于云的内容中台解决方案显得尤为重要。 Baklib作为创新型解决方案提供商&#xff0c;致力于…