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.pswp.cn/web/67808.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/67808.shtml
英文地址,請注明出處:http://en.pswp.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;致力于…