C++之unordered封裝

目錄

一、哈希表的修改

1.1、哈希表節點結構

1.2、迭代器

1.3、哈希表結構

1.4、完整代碼

二、unordered_map的實現

二、unordered_set的實現


一、哈希表的修改

注意:這里我們使用哈希桶來封裝unordered_map和unordered_set。

1.1、哈希表節點結構

template<class T>
struct HashNode
{T _data;HashNode<T>* _next;HashNode(const T& data):_data(data), _next(nullptr){}
};

因為我們要復用哈希表,即使用同一份哈希表代碼來封裝unordered_map和unordered_set,所以這里將模版參數改為T,T即要存儲的數據類型,對于unordered_set而言,T直接就是要存儲的數據類型;對于unordered_map而言,T是pair類型的。

在插入方法中,我們使用有參構造,在創建節點時直接將數據通過構造函數賦值進去,所以這里還實現了一個構造函數。

1.2、迭代器

iterator核心源碼:

template <class Value, class Key, class HashFcn,class ExtractKey, class EqualKey, class Alloc>struct __hashtable_iterator {typedef hashtable<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>hashtable;typedef __hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>iterator;typedef __hashtable_const_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>const_iterator;typedef __hashtable_node<Value> node;typedef forward_iterator_tag iterator_category;typedef Value value_type;node* cur;hashtable* ht;__hashtable_iterator(node* n, hashtable* tab) : cur(n), ht(tab) {}__hashtable_iterator() {}reference operator*() const { return cur->val; }#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }#endif /* __SGI_STL_NO_ARROW_OPERATOR */
iterator& operator++();iterator operator++(int);bool operator==(const iterator& it) const { return cur == it.cur; }bool operator!=(const iterator& it) const { return cur != it.cur; }
};template <class V, class K, class HF, class ExK, class EqK, class A>
__hashtable_iterator<V, K, HF, ExK, EqK, A>&
__hashtable_iterator<V, K, HF, ExK, EqK, A>::operator++()
{const node* old = cur;cur = cur->next;if (!cur) {size_type bucket = ht->bkt_num(old->val);while (!cur && ++bucket < ht->buckets.size())cur = ht->buckets[bucket];}return *this;
}

iterator實現思路分析:

  • iterator實現的?框架跟list的iterator思路是?致的,??個類型封裝結點的指針,再通過重載運算 符實現,迭代器像指針?樣訪問的?為,要注意的是哈希表的迭代器是單向迭代器。
  • 這?的難點是operator++的實現。iterator中有?個指向結點的指針,如果當前桶下?還有結點, 則結點的指針指向下?個結點即可。如果當前桶?完了,則需要想辦法計算找到下?個桶。這?的難點是反?是結構設計的問題,參考上面源碼,我們可以知道iterator中除了有結點的指針,還有哈希表對象的指針,這樣當前桶?完了,要計算下?個桶就相對容易多了,?key值計算出當前桶位置,依次往后找下?個不為空的桶即可。
  • begin()返回第?個不為空的桶中第?個節點指針構造的迭代器,這?end()返回迭代器可以?空指針表?。
  • unordered_map的iterator不?持修改key但是可以修改value,我們把unordered_map的第?個模板參數pair的第?個參數改成const K即可,HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;(不允許修改Key是因為數據在哈希表中存儲的地址是通過Key映射的,如果修改Key,破壞了哈希表的結構)。
  • unordered_set的iterator也不?持修改,我們把unordered_set的第?個模板參數改成const K即可,HashTable<K, const K, SetKeyOfT, Hash> _ht;(和unordered_map同理)。

具體代碼:

	// 前置聲明template<class K, class T, class KeyOfT, class Hash>class HashTable;template<class K, class T, class Ptr, class Ref, class KeyOfT, class Hash>struct HTIterator{typedef HashNode<T> Node;typedef HTIterator<K, T, Ptr, Ref, KeyOfT, Hash> Self;Node* _node;const HashTable<K, T, KeyOfT, Hash>* _pht;HTIterator(Node* node, const HashTable<K, T, KeyOfT, Hash>* pht):_node(node),_pht(pht){}Self& operator++(){if (_node->_next){//當前桶還有節點_node = _node->_next;}else{//當前桶走完了,找下一個不為空的桶KeyOfT kot;Hash hs;size_t hashi = hs(kot(_node->_data)) % _pht->_tables.size();++hashi;while (hashi < _pht->_tables.size()){if (_pht->_tables[hashi]){break;}++hashi;}if (hashi == _pht->_tables.size()){_node = nullptr; //end()}else{_node = _pht->_tables[hashi];}}return *this;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const Self& s){return _node != s._node;}};

注意:這里需要對哈希表進行前置聲明,因為在迭代器中用到了哈希表,但是編譯器編譯時是向上查找,而哈希表在下面,會因為找不到而報錯,將哈希表放到上面也不行,因為哈希表里也會封裝迭代器,如果哈希表在上面向上查找時就會找不到迭代器,總之必須有一個進行前置聲明。另外,迭代器中重載++運算符時為了確定當前節點的位置訪問了哈希表的私有成員,所以后面在哈希表中還需要進行友元聲明。

1.3、哈希表結構

	template<class K, class T, class KeyOfT, class Hash>class HashTable{// 友元聲明template<class K, class T, class Ptr, class Ref, class KeyOfT, class Hash>friend struct HTIterator;typedef HashNode<T> Node; //節點不想讓外界訪問public:typedef HTIterator<K, T, T*, T&, KeyOfT, Hash> Iterator; //迭代器需要讓外界訪問typedef HTIterator<K, T, const T*, const T&, KeyOfT, Hash> ConstIterator;Iterator Begin(){if (_n == 0) //沒有有效數據{return End();}for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];if (cur){return Iterator(cur, this);}}return End();}Iterator End(){return Iterator(nullptr, this);}ConstIterator Begin() const{if (_n == 0)return End();for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];if (cur){return ConstIterator(cur, this);}}return End();}ConstIterator End() const{return ConstIterator(nullptr, this);}HashTable(){_tables.resize(10, nullptr);}~HashTable(){for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_tables[i] = nullptr;}}pair<Iterator,bool> Insert(const T& data){KeyOfT kot;Iterator it = Find(kot(data));//去重if (it != End()){return make_pair(it,false);}Hash hs;size_t hashi = hs(kot(data)) % _tables.size();//負載因子==1  擴容if (_n == _tables.size()){// 需要新建節點和釋放舊節點,效率較低//	HashTable<K, V, Hash> newHT;//	for (size_t i = 0; i < _tables.size(); i++)//	{//		Node* cur = _tables[i];//		while (cur)//		{//			newHT.Insert(cur->_kv);//			cur = cur->_next;//		}//	}//	_tables.swap(newHT._tables);vector<Node*> newtables(_tables.size() * 2, nullptr);for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;//舊表中的節點重新映射在新表中的位置size_t hashi = hs(kot(cur->_data)) % newtables.size();cur->_next = newtables[hashi];newtables[hashi] = cur;cur = next;}//節點都挪到新表上了,舊表置空_tables[i] = nullptr;}_tables.swap(newtables);}//頭插Node* newnode = new Node(data);newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return make_pair(Iterator(newnode,this),true);}Iterator Find(const K& key){KeyOfT kot;Hash hs;size_t hashi = hs(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key){return Iterator(cur,this);}cur = cur->_next;}return End();}bool Erase(const K& key){KeyOfT kot;Hash hs;size_t hashi = hs(key) % _tables.size();Node* prev = nullptr;Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key){if (prev == nullptr){_tables[hashi] = cur->_next;}else{prev->_next = cur->_next;}delete cur;--_n;return true;}prev = cur;cur = cur->_next;}return false;}private:vector<Node*> _tables; //指針數組size_t _n; //表中存儲數據個數};}

為什么需要KeyOfT模版參數:

跟map和set相???unordered_map和unordered_set的模擬實現類結構更復雜?點,但是?框架和思路是完全類似的。因為HashTable實現了泛型不知道T參數是K,還是pair, 那么insert內部進?插?時要?K對象轉換成整形取模和K?較相等(去重),因為pair的value不需要參與計算取模,且pair默認?持的是key和value?起?較相等,但實際上我們需要的是任何時候只需要?較K對象,所以我們在unordered_map和unordered_set層分別實現?個MapKeyOfT和SetKeyOfT的仿函數傳給 HashTable的KeyOfT,然后HashTable中通過KeyOfT仿函數取出T類型對象中的K對象,再轉換成整形取模和K?較相等。

返回值的修改:

這里為了符合unordered_map和unordered_set的使用將Find方法的返回值改為迭代器,為了實現unordered_map的 [ ] 運算符重載,將Insert方法的返回值該為pair類型,其中返回的pair對象的first屬性的值是新插入節點/原有節點的迭代器,second屬性的值是bool類型,代表是否插入成功。

1.4、完整代碼

namespace hash_bucket
{template<class T>struct HashNode{T _data;HashNode<T>* _next;HashNode(const T& data):_data(data), _next(nullptr){}};// 前置聲明template<class K, class T, class KeyOfT, class Hash>class HashTable;template<class K, class T, class Ptr, class Ref, class KeyOfT, class Hash>struct HTIterator{typedef HashNode<T> Node;typedef HTIterator<K, T, Ptr, Ref, KeyOfT, Hash> Self;Node* _node;const HashTable<K, T, KeyOfT, Hash>* _pht;HTIterator(Node* node, const HashTable<K, T, KeyOfT, Hash>* pht):_node(node),_pht(pht){}Self& operator++(){if (_node->_next){//當前桶還有節點_node = _node->_next;}else{//當前桶走完了,找下一個不為空的桶KeyOfT kot;Hash hs;size_t hashi = hs(kot(_node->_data)) % _pht->_tables.size();++hashi;while (hashi < _pht->_tables.size()){if (_pht->_tables[hashi]){break;}++hashi;}if (hashi == _pht->_tables.size()){_node = nullptr; //end()}else{_node = _pht->_tables[hashi];}}return *this;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const Self& s){return _node != s._node;}};template<class K, class T, class KeyOfT, class Hash>class HashTable{// 友元聲明template<class K, class T, class Ptr, class Ref, class KeyOfT, class Hash>friend struct HTIterator;typedef HashNode<T> Node; //節點不想讓外界訪問public:typedef HTIterator<K, T, T*, T&, KeyOfT, Hash> Iterator; //迭代器需要讓外界訪問typedef HTIterator<K, T, const T*, const T&, KeyOfT, Hash> ConstIterator;Iterator Begin(){if (_n == 0) //沒有有效數據{return End();}for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];if (cur){return Iterator(cur, this);}}return End();}Iterator End(){return Iterator(nullptr, this);}ConstIterator Begin() const{if (_n == 0)return End();for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];if (cur){return ConstIterator(cur, this);}}return End();}ConstIterator End() const{return ConstIterator(nullptr, this);}HashTable(){_tables.resize(10, nullptr);}~HashTable(){for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_tables[i] = nullptr;}}pair<Iterator,bool> Insert(const T& data){KeyOfT kot;Iterator it = Find(kot(data));//去重if (it != End()){return make_pair(it,false);}Hash hs;size_t hashi = hs(kot(data)) % _tables.size();//負載因子==1  擴容if (_n == _tables.size()){// 需要新建節點和釋放舊節點,效率較低//	HashTable<K, V, Hash> newHT;//	for (size_t i = 0; i < _tables.size(); i++)//	{//		Node* cur = _tables[i];//		while (cur)//		{//			newHT.Insert(cur->_kv);//			cur = cur->_next;//		}//	}//	_tables.swap(newHT._tables);vector<Node*> newtables(_tables.size() * 2, nullptr);for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;//舊表中的節點重新映射在新表中的位置size_t hashi = hs(kot(cur->_data)) % newtables.size();cur->_next = newtables[hashi];newtables[hashi] = cur;cur = next;}//節點都挪到新表上了,舊表置空_tables[i] = nullptr;}_tables.swap(newtables);}//頭插Node* newnode = new Node(data);newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return make_pair(Iterator(newnode,this),true);}Iterator Find(const K& key){KeyOfT kot;Hash hs;size_t hashi = hs(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key){return Iterator(cur,this);}cur = cur->_next;}return End();}bool Erase(const K& key){KeyOfT kot;Hash hs;size_t hashi = hs(key) % _tables.size();Node* prev = nullptr;Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key){if (prev == nullptr){_tables[hashi] = cur->_next;}else{prev->_next = cur->_next;}delete cur;--_n;return true;}prev = cur;cur = cur->_next;}return false;}private:vector<Node*> _tables; //指針數組size_t _n; //表中存儲數據個數};}

二、unordered_map的實現

這里的實現沒有什么困難,就是直接套一層殼,所有的調用最終還是去調哈希表的方法,所以這里就不在贅述了,直接上代碼。

#include"HashTable.h"namespace bit
{template<class K, class V, class Hash = HashFunc<K>>class unordered_map{struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::Iterator iterator;typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::ConstIterator const_iterator;iterator begin(){return _ht.Begin();}iterator end(){return _ht.End();}const_iterator begin() const{return _ht.Begin();}const_iterator end() const{return _ht.End();}V& operator[](const K& key){pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));return ret.first->second;}pair<iterator, bool> insert(const pair<K, V>& kv){return _ht.Insert(kv);}iterator find(const K& key){return _ht.Find(key);}bool erase(const K& key){return _ht.Erase(key);}private:hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;};void test_map(){unordered_map<string, string> dict;dict.insert({ "sort", "排序" });dict.insert({ "left", "左邊" });dict.insert({ "right", "右邊" });dict["left"] = "左邊,剩余";dict["insert"] = "插入";dict["string"];unordered_map<string, string>::iterator it = dict.begin();while (it != dict.end()){// 不能修改first,可以修改second//it->first += 'x';it->second += 'x';cout << it->first << ":" << it->second << endl;++it;}cout << endl;}
}

二、unordered_set的實現

這里和unordered_map一樣,就是直接套一層殼,所有的調用最終還是去調哈希表的方法,所以這里就不在贅述了,直接上代碼。

#include"HashTable.h"namespace bit
{template<class K, class Hash = HashFunc<K>>class unordered_set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::Iterator iterator;typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::ConstIterator const_iterator;iterator begin(){return _ht.Begin();}iterator end(){return _ht.End();}const_iterator begin() const{return _ht.Begin();}const_iterator end() const{return _ht.End();}pair<iterator, bool> insert(const K& key){return _ht.Insert(key);}iterator find(const K& key){return _ht.Find(key);}bool erase(const K& key){return _ht.Erase(key);}private:hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;};void Print(const unordered_set<int>& s){unordered_set<int>::const_iterator it = s.begin();while (it != s.end()){// *it += 1;cout << *it << " ";++it;}cout << endl;}struct Date{int _year;int _month;int _day;bool operator==(const Date& d) const{return _year == d._year&& _month == d._month&& _day == d._day;}};struct HashDate{size_t operator()(const Date& key){// 112// 121return (key._year * 31 + key._month) * 31 + key._day;}};void test_set(){unordered_set<int> s;int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14, 3,3,15 };for (auto e : a){s.insert(e);}for (auto e : s){cout << e << " ";}cout << endl;unordered_set<int>::iterator it = s.begin();while (it != s.end()){//*it += 1;cout << *it << " ";++it;}cout << endl;unordered_set<Date, HashDate> us;us.insert({ 2024, 7, 25 });us.insert({ 2024, 7, 26 });Print(s);}
}

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

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

相關文章

[滲透測試]滲透測試靶場docker搭建 — —全集

[滲透測試]滲透測試靶場docker搭建 — —全集 對于初學者來說&#xff0c;僅僅了解漏洞原理是不夠的&#xff0c;還需要進行實操。對于公網上的服務我們肯定不能輕易驗證某些漏洞&#xff0c;否則可能觸犯法律。這是就需要用到靶場。 本文主要給大家介紹幾種常見漏洞對應的靶場…

Docker如何更換鏡像源提高拉取速度

在國內&#xff0c;由于網絡政策和限制&#xff0c;直接訪問DockerHub速度很慢&#xff0c;尤其是在拉取大型鏡像時。為了解決這個問題&#xff0c;常用的方法就是更換鏡像源。本文將詳細介紹如何更換Docker鏡像源&#xff0c;并提供當前可用的鏡像源。 換源方法 方法1&#x…

第一篇:從哲學到管理——實踐論與矛盾論如何重塑企業思維

引言&#xff1a;當革命哲學照亮現代商業 1937年&#xff0c;毛澤東在戰火中寫就的《實踐論》《矛盾論》&#xff0c;為中國共產黨提供了認識世界的方法論。今天&#xff0c;這兩部著作正成為企業破解管理困局的“思維操作系統”&#xff1a; 戰略模糊&#xff1a;據Gartner統…

云原生--基礎篇-2--云計算概述(云計算是云原生的基礎,IaaS、PaaS和SaaS服務模型)

1、云計算概念 云計算是一種通過互聯網提供計算資源&#xff08;包括服務器、存儲、數據庫、網絡、軟件等&#xff09;和服務的技術模式。用戶無需擁有和維護物理硬件&#xff0c;而是可以根據需要租用這些資源&#xff0c;并按使用量付費。 2、云計算特點 &#xff08;1&am…

一級濾波器設計:IL_cmdm > 80dB

目錄 背景 目的 操作 仿真測試 搭建仿真模型 插入損耗測試 優化設計后重新測試 思考 背景 在選購共模電感時&#xff0c;規格書中通常會提供插損曲線或者阻抗-頻率曲線&#xff0c;但這些數據都是在特定條件下測試獲得的。如果將其集中在我們的樣機中性能會如何&#…

qt 配置 mysql 驅動問題:Cannot load library qsqlmysql;QMYSQL driver not loaded

項目場景&#xff1a; 環境版本&#xff1a; qt &#xff1a;5.14.2 mysql&#xff1a;8.0 windows&#xff1a;10 提示&#xff1a;qt 配置 mysql 驅動&#xff1a; 項目場景&#xff1a;qt 配置 mysql 驅動 問題描述 提示&#xff1a;這里描述項目中遇到的問題&#xff1a;…

Kubernetes相關的名詞解釋Container(16)

什么是Container&#xff1f; 在 Kubernetes 中&#xff0c;Container&#xff08;容器&#xff09; 是一個核心概念&#xff0c;你可以將鏡像&#xff08;Image&#xff09;類比為程序的“源代碼”&#xff0c;而容器是這段“代碼”運行時的進程。例如&#xff0c;一個 nginx…

學習設計模式《四》——單例模式

一、基礎概念 單例模式的本質【控制實例數目】&#xff1b; 單例模式的定義&#xff1a;是用來保證這個類在運行期間只會被創建一個類實例&#xff1b;單例模式還提供了一個全局唯一訪問這個類實例的訪問點&#xff08;即GetInstance方法&#xff09;單例模式只關心類實例的創建…

零基礎上手Python數據分析 (19):Matplotlib 高級圖表定制 - 精雕細琢,讓你的圖表脫穎而出!

寫在前面 —— 超越默認樣式,掌握 Matplotlib 精細控制,打造專業級可視化圖表 上一篇博客,我們學習了 Matplotlib 的基礎繪圖功能,掌握了如何繪制常見的折線圖、柱狀圖、散點圖和餅圖,并進行了基本的圖表元素定制,例如添加標題、標簽、圖例等。 這些基礎技能已經能讓我…

信奧中的數學

信奧賽的數學大綱 ps:知識點是其他小伙伴分享的&#xff0c;我現在在做一下系列視頻 會逐步更新&#xff0c;希望大家支持喜歡。 1.基礎數學 數論 整數和自然數 素數、合數和因數分解 最大公約數(GCD)和最小公倍數(LCM) 同余和取模運算 歐幾里得算法 擴展歐幾里得算法 中國…

PHP騰訊云人臉核身獲取Access Token

參考騰訊云官方文檔&#xff1a; 人臉核身 獲取 Access Token_騰訊云 public function getAccessToken(){$data [appId > , //WBappid,https://cloud.tencent.com/document/product/1007/49634secret > ,grant_type > client_credential, //授權類型version > 1…

《作用域大冒險:從閉包到內存泄漏的終極探索》

“愛自有天意&#xff0c;天有道自不會讓有情人分離” 大家好&#xff0c;關于閉包問題其實實際上是js作用域的問題&#xff0c;那么js有幾種作用域呢&#xff1f; 作用域類型關鍵字/場景作用域范圍示例全局作用域var&#xff08;無聲明&#xff09;整個程序var x 10;函數作用…

為什么Makefile中的clean需要.PHONY

原因一&#xff1a;避免Makefile檢查時間戳 前置知識&#xff1a;makefile在依賴文件沒有改變時不會執行編譯命令 #第一次執行&#xff0c;OK [rootVM-16-14-centos ~]# make g -E main.cc -o main.i g -S main.i -o main.s g -c main.s -o main.o g main.o -o main#第二…

垂直行業突圍:工業軟件在汽車、航空領域的 “破壁” 實踐

在當今科技高速發展的時代&#xff0c;工業軟件已悄然完成從通用工具到垂直行業 “戰略武器” 的蛻變。特別是在汽車與航空這兩大高端制造領域&#xff0c;工業軟件的價值早已超越單純的效率提升&#xff0c;成為關乎核心技術自主可控的關鍵要素&#xff0c;一場圍繞工業軟件的…

07.Python代碼NumPy-排序sort,argsort,lexsort

07.Python代碼NumPy-排序sort&#xff0c;argsort&#xff0c;lexsort 提示&#xff1a;幫幫志會陸續更新非常多的IT技術知識&#xff0c;希望分享的內容對您有用。本章分享的是NumPy的使用語法。前后每一小節的內容是存在的有&#xff1a;學習and理解的關聯性&#xff0c;希望…

LVDS系列8:Xilinx 7系可編程輸入延遲(一)

在解析LVDS信號時&#xff0c;十分重要的一環就是LVDS輸入信號線在經過PCB輸入到FPGA中后&#xff0c;本來該嚴格對齊的信號線會出現時延&#xff0c;所以需要在FPGA內部對其進行延時對齊后再進行解析。 Xilinx 7系器件中用于輸入信號延時的組件為IDELAYE2可編程原語&#xff0…

AI驅動研發效率在中后臺的實踐

本文探討了AI驅動的中后臺前端研發實踐&#xff0c; 涵蓋設計出碼、接口定義轉換、代碼擬合、自動化測試等多個環節&#xff0c;通過具體案例展示了AI技術如何優化研發流程并提升效率。特別是在UI代碼編寫和接口聯調階段&#xff0c;并提出了設計出碼&#xff08;Design to Cod…

【Rust 精進之路之第6篇-流程之舞】控制流:`if/else`, `loop`, `while`, `for` 與模式匹配初窺

系列: Rust 精進之路:構建可靠、高效軟件的底層邏輯 作者: 碼覺客 發布日期: 2025-04-20 引言:讓代碼“活”起來——指令的流動 在前面的文章中,我們已經掌握了 Rust 的基礎數據類型(標量和復合類型)以及如何通過變量綁定來存儲和命名它們。這相當于我們準備好了程序…

C++ 表達式求值的基礎(四十九)

1. 運算符的分類 1.1 按操作數個數 一元運算符&#xff08;Unary&#xff09; 作用于單個操作數&#xff1a; 取地址 &obj解引用 *ptr邏輯非 !b一元加減 x, -x遞增遞減 i, i-- 二元運算符&#xff08;Binary&#xff09; 作用于兩個操作數&#xff1a; 算術運算 a b, a …

Three.js + React 實戰系列 : 從零搭建 3D 個人主頁

可能你對tailiwindcss毫不了解&#xff0c;別緊張&#xff0c;記住我們只是在學習&#xff0c;學習的是作者的思想和技巧&#xff0c;并不是某一行代碼。 在之前的幾篇文章中&#xff0c;我們已經熟悉了 Three.js 的基本用法&#xff0c;并通過 react-three-fiber 快速構建了一…