STL庫——二叉搜索樹

? ? ? ? ?

づ?ど

?🎉?歡迎點贊支持🎉

個人主頁:勵志不掉頭發的內向程序員;

專欄主頁:C++語言;


文章目錄

前言

一、二叉搜索樹的概念

二、二叉搜索樹的性能分析

三、二叉搜索樹的插入

四、二叉搜索樹的查找

五、二叉搜索樹的刪除

六、二叉搜索樹的析構

七、二叉搜索樹的拷貝

八、二叉搜索樹 key 和 key/value 使用場景

6.1、key搜索場景

6.2、key/value 搜索場景:

6.3、key/value 二叉搜索樹代碼實現

總結


前言

這一章節我們來聊聊我們之前的二叉樹的一種新形態二叉搜索樹,這個形態也有一定的問題,但是它是我們后面講解 map/set 容器的基礎,我們到后面才會講解改怎么解決二叉搜索樹的方式,但是我們本章節搞明白二叉搜索樹的原理和實現也非常重要。


一、二叉搜索樹的概念

二叉搜索樹又稱二叉排序樹,它要么是一顆空樹,要么是具有以下性質的二叉樹:

  • 若它的左子樹不為空,則左子樹上所有結點的值都小于等于根結點的值。
  • 若它的右子樹不為空,則右子樹上所有結點的值都大于等于根節點的值。
  • 它的左右子樹也分別為二叉搜索樹。
  • 二叉搜索樹中可以支持插入相等的值,也可以不支持插入相等的值,具體看使用場景定義,后續我們學習 map/set/multimap/multiset 系列容器底層就是二叉搜索樹,其中 map/set 不支持插入相等值,multimap/multiset 支持插入相等值。

我們二叉樹的邏輯就是,當插入一個新結點時,從頭結點,也就是樹的根結點開始做比較,如果比新結點大,就走到我們的右結點。如果比新小節點小,就走到我們的左節點,然后再和這些結點進行比較,一直到結點走到底,沒有結點比較時就插入即可。

我們學習數據結構的時候可能有聽說過我們二叉樹如果單獨存儲數據是沒有意義的。要想有意義,我們得在二叉樹的基礎上加入一些東西,這樣才有意義,就比如在二叉樹的基礎上加入搜索二叉樹的規則。

二、二叉搜索樹的性能分析

最優情況下,二叉搜索樹為完全二叉樹(或者接近完全二叉樹),其高度為:log2(N)。

最差情況下,二叉樹退化為單支樹(或者類似單支),其高度為:N。

所以綜合而言二叉搜索樹增刪查改時間復雜度為:O(N)。

這樣的效率顯然是無法滿足我們需求的,我們后面章節會繼續講解二叉搜索樹的變形,平衡二叉搜索樹AVL樹和紅黑樹,才能適用于我們在內存中存儲和搜索數據。

另外,我們二分查找也可以實現 O( log2(N) ) 級別的查找效率,但是二分查找有兩大缺陷:

  • 需要存儲在支持下標隨機訪問的結構中,并且有序。
  • 插入和刪除數據效率很低,因為存儲在下標隨機訪問的數據結構中,插入和刪除數據一般需要挪動數據。

三、二叉搜索樹的插入

插入的具體過程如下:

  • 樹為空,則直接新增結點,賦值給 root 指針。
  • 樹不為空,按二叉搜索樹性質,插入值比當前結點大往右走,插入值比當前結點小往左走,找到空位置,插入新結點。
  • 如果支持插入相等的值,插入值跟當前結點相等的值可以往右走,也可以往左走,找到空位置,插入新結點(要注意的是要保持邏輯一致性,插入相等的值不要一會兒往左走,一會兒往右走)。

就如上圖一樣的插入方式。

我們先把二叉搜索樹的框架搭建出來,創建一個結點類,這個結點包含左結點的指針和右結點的指針,以及一個要保存的類型。

namespace zxl
{template <class K>struct BSTNode{BSTNode<K>* _left;BSTNode<K>* _right;K _key;BSTNode(const K& key): _key(key),_left(nullptr),_right(nullptr){}};template <class T>class BSTree{typedef BSTNode<T> Node;public:private:Node* _root = nullptr;};
}

我們設計一個插入的成員函數,它的返回值可以是布爾類型來查看是否插入成功。我們可以通過while 循環比較的方式一直比較到 nullptr 時讓循環停下來,但是此時我們的 cur 指向的是一個空指針,我們應該指向它的上一個指針,所以我們還得創建一個變量來記錄上一個變量,通過 cur 的上一個變量來插入我們的新結點。我們這里實現的是不允許有相等的情況出現的,如果想要實現有相等的情況可以在比較那里改一下即可。

我們可以來看看下面的動畫來幫助理解。

bool insert(const T& key)
{if (_root == nullptr){_root = new Node(key);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(key);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;
}

此時我們可以寫一個中序遍歷來看看我們實現的怎么樣,由于我們的二叉搜索樹的結構,這導致我們的中序遍歷出來的是一個從小到大排序好的數據,這樣就可以驗證我們的插入實現的是否成功。

我們把中序遍歷寫在私有位置,這樣就可以不把根結點暴露出去。我們想要調用遞歸,就必須傳Node 的指針,如果我們把我們的中序遍歷寫在公有,那它有默認的 this 指針,可以調用 _root,但是此時去下一層就得傳下一層的地址,但是由于我們之前是靠 this 指針而得到的 _root。所以此時我們就無法傳值到遞歸下一層。但是如果我們想要寫一個傳值的成員函數,不寫在私有的話因為要傳指針所以就得暴露我們的 _root。所以為了避免我們干脆直接寫成私有的。

private:void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}

此時我們就有一個問題,那就是我們在外界沒辦法調用我們的中序遍歷,此時我們可以在類內公有位置創建一個成員函數,讓這個成員函數去調用我們的中序遍歷即可。

public:void InOrder(){_InOrder(_root);cout << endl;}

此時我們就可以嘗試去測試我們的插入了。

int main()
{zxl::BSTree<int> t;int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };for (int i = 0; i < sizeof(a) / sizeof(int); i++){t.insert(a[i]);}t.InOrder();return 0;
}

四、二叉搜索樹的查找

我們查找的邏輯就和搜索的邏輯一樣。

  • 從根開始比較,查找 x,x 比根的值大則往右邊查找,x 比根小則往左邊查找。
  • 最多查找高度次,走到空還沒找到這個值就不存在。
  • 如果不支持插入相等的值,找到 x 即可返回。
  • 如果支持插入相等的值,意味著有多個 x 存在,一般要求查找中序的第一個 x。
bool Find(const T& key)
{Node* cur = _root;while (cur){if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return true;}}return false;
}

五、二叉搜索樹的刪除

首先查找元素是否在二叉搜索樹中,如果不存在,則返回 false。

如果查找元素存在則分以下四種情況分別處理:(假設要刪除的結點為 N)

  1. 要刪除結點 N 左右孩子結點均為空。
  2. 要刪除結點 N 左孩子結點為空,右孩子結點不為空。
  3. 要刪除結點 N 右孩子結點為空,左孩子結點不為空。
  4. 要刪除結點 N 左右孩子結點均不為空。

第一種情況:

第二種情況:

第三種情況:

第四種情況:

對應以上四種情況的解決方案:

  1. 由于 N 結點左右孩子都是空,所以我們直接銷毀掉我們的這個結點即可,但是為了讓它的父親結點不會指向野指針,我們在銷毀這個結點后要記得把指向它的父親結點指向 nullptr。
  2. 把N結點的父親對應孩子指針指向N的右孩子,然后就像 1 一樣刪除掉 N 結點即可。
  3. 把N結點的父親對應孩子指針指向N的左孩子,然后就像 1 一樣刪除掉 N 結點即可。
  4. 無法直接刪除 N 結點,因為 N 的兩個孩子無處安放,只能用替換法刪除。找 N 左子樹的值最大結點 R(最右結點)或者?N 右子樹的值最小結點 L(最左結點)代替 N,因為這兩個結點中任意一個,放到 N 的位置,都滿足二叉搜索樹的規則。替代 N 的意思就是 N 和 R 的兩個結點的值的交換,轉而變成刪除 R 結點,R 結點符號情況 2 或 情況 3,可以直接刪除。

我們先用循環去找到我們的 key 值,邏輯和上面一樣,當我們的找到我們 key 時,我們就開始討論這 4 種情況,我們的情況 1 其實可以融合在情況 2 或 3中,所以這里就只討論 3 種情況。

第一種情況:

第二種情況:

bool Erase(const T& key)
{Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{// 0-1個孩?的情況// 刪除情況1 2 3均可以直接刪除,改變?親對應孩?指針指向即可if (cur->_left == nullptr){if (parent == nullptr){_root = cur->_right;}else{if (parent->_left == cur)parent->_left = cur->_right;elseparent->_right = cur->_right;}delete cur;return true;}else if (cur->_right == nullptr){if (parent == nullptr){_root = cur->_left;}else{if (parent->_left == cur)parent->_left = cur->_left;elseparent->_right = cur->_left;}delete cur;return true;}else{// 2個孩?的情況// 刪除情況4,替換法刪除// 假設這?我們取右?樹的最?結點作為替代結點去刪除// 這?尤其要注意右?樹的根就是最?情況的情況的處理,// 對應課件圖中刪除7的情況// ?定要把cur給rightMinP,否會報錯。Node* rightMinP = cur;Node* rightMin = cur->_right;while (rightMin->_left){rightMinP = rightMin;rightMin = rightMin->_left;}cur->_key = rightMin->_key;if (rightMinP->_left == rightMin)rightMinP->_left = rightMin->_right;elserightMinP->_right = rightMin->_right;delete rightMin;return true;}}}return false;
}

六、二叉搜索樹的析構

我們二叉搜索樹的析構可以使用遞歸,向我們的中序遍歷一樣得讓遞歸函數私有,然后再在公有的地方實現析構函數以此來保護我們的根結點。

public:~BSTree(){Destroy(_root);_root = nullptr;}private:void Destroy(Node* root){if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;}

七、二叉搜索樹的拷貝

和我們的析構同理,也是用遞歸來實現。

public:BSTree(const BSTree<K, V>& t){_root = Copy(t._root);}private:Node* Copy(Node* root){if (root == nullptr)return nullptr;Node* newRoot = new Node(root->_key, root->_value);newRoot->_left = Copy(root->_left);newRoot->_right = Copy(root->_right);return newRoot;}

剩下的像默認構造沒有必要實現,而賦值重載用我們的交換大法即可輕松完成,這里就不過多贅述。

八、二叉搜索樹 key 和 key/value 使用場景

6.1、key搜索場景

只有 key 作為關鍵碼,結構中只需要存儲 key 即可,關鍵碼即為需要搜索到的值,搜索場景只需要判斷 key 在不在。key 的搜索場景實現的二叉樹搜索樹支持增刪查,但是不支持修改,修改 key 破壞搜索樹機構了。

場景1:小區無人值守車庫,小區車庫買了車位的業主車才能進小區,那么物業會把買了車位的業主的車牌號錄入后臺系統,車輛進入時掃描車牌在不在系統中,在則抬桿,不在則體現非本小區車輛,無法進入。

場景2:檢查一篇英文文檔拼寫是否正確,將詞庫中所有的單詞放入二叉搜索樹,讀取文章中的單詞,查找是否在二叉搜索樹中,不在則波浪線標紅提示。

6.2、key/value 搜索場景:

每?個關鍵碼 key,都有與之對應的值 value,value 可以任意類型對象。樹的結構中 (結點) 除了需要存儲 key 還要存儲對應的 value,增/刪/查還是以 key 為關鍵字??叉搜索樹的規則進行比較,可以快速查找到 key 對應的 value。key/value 的搜索場景實現的?叉樹搜索樹?持修改,但是不?持修改 key,修改 key 破壞搜索樹性質了,可以修改 value。

場景1:簡單中英互譯字典,樹的結構中 (結點) 存儲 key (英?) 和 vlaue (中?),搜索時輸入英?,則同時查找到了英?對應的中?。

場景2:商場無人值守車庫,入口進場時掃描車牌,記錄?牌和入場時間,出口離場時,掃描車牌,查找入場時間,?當前時間 - 入場時間計算出停車時長,計算出停?費?,繳費后抬桿,車輛離場。

場景3:統計?篇?章中單詞出現的次數,讀取?個單詞,查找單詞是否存在,不存在這個說明第?次出現,(單詞,1),單詞存在,則++單詞對應的次數。

6.3、key/value 二叉搜索樹代碼實現

我們 key/value 的結構和我們上面的 key 結構相比,無非就是多了一個 value,我們在結點創建時多創建一個 value,然后在增刪查的時候我們只要讓我們傳過來的值中的 key 進行比較,然后 value 不管,插入時把 key/value 都插入即可實現,我們可以通過下面的 key/value 的代碼和上面的 key 作比較就能看出其中的相似。

namespace zxl
{template<class K, class V>struct BSTNode{// pair<K, V> _kv;K _key;V _value;BSTNode<K, V>* _left;BSTNode<K, V>* _right;BSTNode(const K& key, const V& value):_key(key), _value(value), _left(nullptr), _right(nullptr){}};template<class K, class V>class BSTree{typedef BSTNode<K, V> Node;public:BSTree() = default;BSTree(const BSTree<K, V>& t){_root = Copy(t._root);}BSTree<K, V>& operator=(BSTree<K, V> t){swap(_root, t._root);return *this;}~BSTree(){Destroy(_root);_root = nullptr;}bool Insert(const K& key, const V& value){if (_root == nullptr){_root = new Node(key, value);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(key, value);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}Node* Find(const K& key){Node* cur = _root;while (cur){if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return cur;}}return nullptr;}bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{if (cur->_left == nullptr){if (parent == nullptr){_root = cur->_right;}else{if (parent->_left == cur)parent->_left = cur->_right;elseparent->_right = cur->_right;}delete cur;return true;}else if (cur->_right == nullptr){if (parent == nullptr){_root = cur->_left;}else{if (parent->_left == cur)parent->_left = cur->_left;elseparent->_right = cur->_left;}delete cur;return true;}else{Node* rightMinP = cur;Node* rightMin = cur->_right;while (rightMin->_left){rightMinP = rightMin;rightMin = rightMin->_left;}cur->_key = rightMin->_key;if (rightMinP->_left == rightMin)rightMinP->_left = rightMin->_right;elserightMinP->_right = rightMin->_right;delete rightMin;return true;}}}return false;}void InOrder(){_InOrder(_root);cout << endl;}private:void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_key << ":" << root->_value << endl;_InOrder(root->_right);}void Destroy(Node* root){if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;}Node* Copy(Node* root){if (root == nullptr)return nullptr;Node* newRoot = new Node(root->_key, root->_value);newRoot->_left = Copy(root->_left);newRoot->_right = Copy(root->_right);return newRoot;}private:Node* _root = nullptr;};}


總結

以上便是我們二叉搜索樹的概念和實現了,二叉搜索樹是一個非常厲害的思想,但是它卻還是有一些弊端,那就是有的時候沒有辦法形成一個完美的完全搜索二叉樹,為了解決這個問題,我們后面會講解決的辦法,所以我們一定要把這一章節搞明白。

🎇堅持到這里已經很厲害啦,辛苦啦🎇

? ? ? ? ?

づ?ど

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/96219.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96219.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/96219.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Linux】線程概念與控制

一. 線程的概念1.什么是線程線程是進程內部的一個執行流&#xff0c;是進程調度的基本單位。它具有輕量的特點&#xff0c;它的創建和銷毀所消耗的資源更少&#xff0c;線程間切換比進程間切換消耗的資源更少&#xff1b;它與進程共享一張虛擬地址空間表&#xff0c;通過進程來…

雙軸傾角傳感器廠家與物聯網角度傳感器應用全解析

本文主要探討雙軸傾角傳感器廠家的核心技術優勢&#xff0c;以及物聯網角度傳感器在智能監測中的創新應用。同時&#xff0c;也詳細介紹了水平監測傳感器廠家的解決方案特點&#xff0c;并分析了專業進口傾角傳感器代理所提供的原廠品質保障與本地化服務支持。以深圳瑞慣科技有…

容器-資源隔離機制

一. 引言&#xff1a; 大家都知道&#xff0c;在一臺機器上&#xff0c;可以運行任意(根據系統資源)個容器實例。且各容器間是相互獨立&#xff0c;不做任何關聯的。那么&#xff0c;docker是通過什么方式來實現容器隔離的呢&#xff1f; 接下來我們了解下。 二. 關于容器隔離…

Agentic RL Survey: 從被動生成到自主決策

Agentic RL Survey: 從被動生成到自主決策 本文將系統解讀《The Landscape of Agentic Reinforcement Learning for LLMs: A Survey》這篇綜述。該綜述首次將智能體強化學習&#xff08;Agentic RL&#xff09;與傳統LLM-RL范式正式區分&#xff0c;通過MDP/POMDP理論框架梳理…

徹底禁用 CentOS 7.9 中 vi/vim 的滴滴聲

在 VMware 虛擬機中安裝的 CentOS 7.9 系統&#xff0c;即使通過修改 /etc/inputrc 禁用了終端鈴聲&#xff08;set bell-style none&#xff09;&#xff0c;vi 或 vim 編輯時仍可能發出滴滴聲。這是因為 vi/vim 有自己獨立的鈴聲控制機制。以下是解決方法&#xff1a;方法 1&…

基于A2A和ADK的內容規劃代理

項目概述 Content Planner Agent 是一個基于 Google Agent Development Kit (ADK) 和 Python A2A SDK 構建的智能內容規劃代理。該代理能夠根據高層次的內容描述&#xff0c;創建詳細的內容大綱。 什么是A2A Protocol A2A Protocol&#xff08;Agent2Agent 協議&#xff09;…

Linux-條件變量

文章目錄條件變量概述條件變量的優缺點條件變量相關函數pthread_cond_init函數pthread_cond_destroy函數pthread_cond_wait函數pthread_cond_signal函數測試生產者和消費者模型條件變量 概述 與互斥鎖不同&#xff0c;條件變量是用來等待而不是用來上鎖的&#xff0c;條件變量…

[硬件電路-166]:Multisim - SPICE與Verilog語言的區別

SPICE與Verilog語言在電子設計領域中扮演不同角色&#xff0c;SPICE是電路仿真語言&#xff0c;用于精確模擬電路行為&#xff1b;Verilog是硬件描述語言&#xff0c;用于描述數字電路的結構和行為。以下是兩者的詳細區別&#xff1a;一、核心定位與用途SPICE&#xff1a;電路仿…

玩轉Docker | 使用Docker部署Umbrel操作系統

玩轉Docker | 使用Docker部署Umbrel操作系統 前言 一、 Umbrel 介紹 Umbrel簡介 Umbrel主要特點 二、系統要求 環境要求 環境檢查 Docker版本檢查 檢查操作系統版本 三、部署Umbrel服務 下載Umbrel鏡像 編輯部署文件 創建容器 檢查容器狀態 檢查服務端口 安全設置 四、訪問Umbr…

Flink Task線程處理模型:Mailbox

Task的線程 和 MailboxProcessor 的綁定executingThread 是 Task 類&#xff08;StreamTask 的父類&#xff09;在構造時創建的物理線程。MailboxProcessor 是 StreamTask 用來處理異步事件和驅動其主要處理邏輯&#xff08;processInput&#xff09;的核心組件。它們之間的綁定…

OpenCV 銀行卡號識別

目錄 一、項目原理與核心技術 二、環境準備與工具包導入 1. 環境依賴 2. 工具包導入 三、自定義工具類 myutils.py 實現 四、主程序核心流程&#xff08;銀行卡識別.py&#xff09; 1. 命令行參數設置 2. 銀行卡類型映射 3. 輔助函數&#xff1a;圖像展示 五、步驟 1…

計算機二級Python

一.靜態語言和腳本語言高級語言根據計算機執行機制的不同分為兩類&#xff1a;靜態語言和腳本語言靜態語言的核心特征&#xff1a;變量的類型在編譯時&#xff08;寫代碼時&#xff09;就必須確定并固定下來&#xff0c;即在使用一個變量前必須顯式地聲明它地類型一旦聲明&…

Mybatis Log Plugin打印日志,會導致CPU升高卡死

原因 大量日志輸出:MyBatis Log Plugin 會打印大量的 SQL 日志,包括 SQL 語句及其參數。如果項目中 SQL 查詢頻繁且復雜,日志量會非常大,導致 CPU 使用率升高,甚至卡死。 日志級別設置不當:如果將日志級別設置為 DEBUG 或 TRACE,MyBatis 會輸出非常詳細的日志信息,這會…

鴻蒙:深色模式適配和淺色模式的切換

前言&#xff1a; 有些時候我們需要對應用進行深色模式的適配處理&#xff0c;并且在不需要的時候切換到淺色狀態&#xff0c;下面和大家一起照著官方文檔來學習。 下面是官方文檔的鏈接&#xff1a; https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-dark-…

Coze源碼分析-資源庫-刪除插件-后端源碼-數據訪問和基礎設施層

5. 數據訪問層 5.1 倉儲接口定義 插件倉儲接口 文件位置&#xff1a;backend/domain/plugin/repository/plugin.go type PluginRepository interface {// DeleteDraftPlugin 刪除插件草稿DeleteDraftPlugin(ctx context.Context, pluginID int64) error// DeleteAPPAllPlugins …

案例一: 對基礎選擇器的使用【網頁盒子】

【1】樣例&#xff1a;首先&#xff0c;觀察到&#xff0c;幾個元素豎著排列的&#xff0c;所以使用塊級元素&#xff0c;而不是行內元素。【2】代碼演示<head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width,…

爬蟲項目優化:如何用 Redis 實現 “斷點續爬”?避免重復采集電商數據

在電商數據采集場景中&#xff0c;爬蟲常因網絡波動、服務器重啟、IP 封禁等問題中斷。若缺乏斷點續爬機制&#xff0c;重啟后需從頭開始&#xff0c;不僅浪費帶寬與時間&#xff0c;還可能因重復采集導致數據冗余。Redis 憑借其高性能、原子操作、多樣數據結構的特性&#xff…

決策樹概念與原理

決策樹簡介決策樹是一種樹形結構樹中每個內部節點表示一個特征上的判斷&#xff0c;每個分支代表一個判斷結果的輸出&#xff0c;每個葉子節點代表一種分類結果(僅舉例無其他意義或隱喻)就像一個女孩去相親&#xff0c;那么首先詢問是否大于30&#xff0c;大于則不見&#xff0…

SQL面試題及詳細答案150道(116-135) --- 高級查詢與函數篇

《前后端面試題》專欄集合了前后端各個知識模塊的面試題,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。 前后端面試題-專欄總目錄 文章目錄 一、本文面試題目錄 116. 如何使用CASE語句實…

VeRL:強化學習與大模型訓練的高效融合框架

本文由「大千AI助手」原創發布&#xff0c;專注用真話講AI&#xff0c;回歸技術本質。拒絕神話或妖魔化。搜索「大千AI助手」關注我&#xff0c;一起撕掉過度包裝&#xff0c;學習真實的AI技術&#xff01; 1 概述&#xff1a;VeRL的起源與核心價值 VeRL&#xff08;Versatile…