中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

網(wǎng)站關鍵詞優(yōu)化方法西安優(yōu)化外

網(wǎng)站關鍵詞優(yōu)化方法,西安優(yōu)化外,265上網(wǎng)導航,.net做的大型網(wǎng)站嗎好了,上次我們了解完了AVL平衡樹和紅黑樹之后,我們就可以去了解關于map與set的底層實現(xiàn)原理了。 全局觀STL的操作: 我們先來看看STL中是如何利用紅黑樹進行對map與set的實現(xiàn)的? 從上面我們可以看到: 為了實現(xiàn)一顆紅黑…

好了,上次我們了解完了AVL平衡樹和紅黑樹之后,我們就可以去了解關于map與set的底層實現(xiàn)原理了。

全局觀STL的操作:

我們先來看看STL中是如何利用紅黑樹進行對map與set的實現(xiàn)的?

從上面我們可以看到:

為了實現(xiàn)一顆紅黑樹,即可map又可set,即即可key結構,也可K,V結構,這取決于 第二個模板參數(shù)你傳什么?能不能只傳Value,不傳Key(傳第二個模板參數(shù),不傳第一個模板參數(shù)?)

不能,因為當find接口時,對于set沒問題,set的value就是Key,但對于map不能。

所以為了統(tǒng)一適配,要傳兩個模板參數(shù)。但實際上,set是一個模板參數(shù),map是兩個模板參數(shù)。

(ps:Key與pair中的Key是同一類型)

set的模擬實現(xiàn)(set是一個模板參數(shù))

typedef Key key_type;

typedef Key value_type;?

那么有人又會想:它會不會存在樹被修改的問題?

答案:不存在的,因為你并不會動這棵樹,你只是動map與set而已,接觸不了樹的那層。

看上面的圖:K是為了讓find接口更加好搞,T是為了決定樹的結點里面存什么。

好了,上面了解庫的大概實現(xiàn)的方式后,現(xiàn)在我們來實現(xiàn)一下:

自己模擬:

ps:這里我們會采用set與map兩者之間的對比差異結合來實現(xiàn)(即同一部分的放在一起,并不會像之前那樣set與map分開來實現(xiàn)。)

紅黑樹創(chuàng)建結點和顏色管理

紅黑樹部分跟上一篇的差不多,只不過這里改了_kv類型改了一下:

我們上一篇的是以pair<K,V> _kv,而現(xiàn)在改成了T _data

這里可以認為在紅黑樹這一層它走了一個泛型,以前實現(xiàn)紅黑樹都是確定的是pair<K,V>類型,而現(xiàn)在是不確定的,而是通過一個模板來接受它的類型。

這里的本意就是想要通過模板來使紅黑樹實例化出來兩份:一份是<K,K>,一份是<K,pair<K,V>>

enum Color
{BLACK,RED
};template<class T>
struct RBTreeNode
{RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;T _data;Color _col;RBTreeNode(const T& data):_left(nullptr),_right(nullptr),_parent(nullptr),_data(data),_col(RED){ }};

構建其成員變量:

ps:有些模板參數(shù)后面會講,可暫時先不用管。

紅黑樹部分:

template<class K,class T,class KeyOFT>
class RBTree
{typedef RBTreeNode<T> Node;public:
private:Node* _root = nullptr;
};

?set部分

namespace bai
{template<class K>class My_set{private:RBTree<K, K, SetKeyOFT> _t;};
}

map部分

namespace bai
{template<class K, class V>class My_map{private:RBTree<K, pair<const K, V>, MapKeyOFT> _t;};
}

插入部分

1.這里如果按照上一篇的方式之間比較的話,它就會行不通,為什么呢?

因為insert部分的比較:通過上面我們知道對于set,可以直接比較,它的結構本質上<K,K>第二個模板是K,而map的話,它的結構是<K,pair<K,V>>,第二個模板參數(shù)是pair類型,它并不可以像我們之前那樣直接比較??赡苡腥藭?#xff1a;那為什么不可以直接用K模板比較?注意:我們這里比較的是值,這個K是個類型,而這比較需要拿的是對象,對象不確定,是K還是pair?所以不可以。

那么,我們該怎么去解決這個問題呢?這里就使用到了仿函數(shù)了。

之前我們說過,仿函數(shù)是可以做到像函數(shù)一樣的。

這里我們可以直接在各自那里:實現(xiàn)一個仿函數(shù)。通過模板還傳進去樹的結構那里。

使用仿函數(shù)比較

set部分
        struct SetKeyOFT{const K& operator()(const K& key){return key;}};bool insert(const K& key){return _t.Insert(key);}
map部分
        struct MapKeyOFT{const K& operator()(const pair<K, V>& kv){return kv.first;}};//后面我們再實現(xiàn)V& operator[](const K& key);bool insert(const pair<K, V>& kv){return _t.Insert(kv);}

完了之后,就可以直接利用仿函數(shù)的使用方法,通過仿函數(shù)比較insert部分里面的比較內容了。

由于代碼太多了,這里只展現(xiàn)出部分的:(展示如何利用上仿函數(shù)就行)其余的代碼跟上一篇的紅黑樹插入部分已經(jīng)有了。

bool Insert(const T& data)
{……………………………………………………KeyOfT kot;while (cur){if (kot(cur->_data) < kot(data)){……………………}else if (kot(cur->_data) > kot(data)){……………………}
………………
………………
}

說明:為什么在紅黑樹中不通過KeyOfT實現(xiàn)比較?

這樣設計是為了保持KeyOfT的純粹性。如果讓KeyOfT負責比較,就會失去其核心價值。我們要思考的是:KeyOfT存在的真正意義是什么?是為了讓樹結構本身更清晰。

我們的做法是:使用者只需關注比較邏輯,無需理會KeyOfT的具體實現(xiàn)。因此將兩者分離,只需傳入比較接口即可實現(xiàn)功能。

迭代器部分:

紅黑樹部分:

迭代器的構造(加上構造+拷貝構造)
template<class T,class Ptr,class Ref>
struct TreeIterator
{typedef RBTreeNode<T> Node;typedef TreeIterator<T,Ptr,Ref> Self;typedef TreeIterator<T, T*, T&> Iterator;Node* _node;TreeIterator(Node*node):_node(node){ }TreeIterator(const Iterator&it):_node(it._node){ }};
operator*
Ref operator*()
{return _node->_data;
}
operator->?
    Ptr operator->(){return &_node->_data;}
operator!=
    bool operator!=(const Self&s){return _node != s._node;}
operator==
    bool operator==(const Self& s) const{return _node == s._node;}
operator++

講解:

1.首先,我們來看一下上面的圖來使我們更加清楚了解它是如何進行++的?

2.我們先來看一下它的總思路:(結合著上圖一起看)

1)右不為空,訪問右樹的最左結點(即最小結點)。

2)右為空,下一個要訪問的孩子是父親左的那個祖先。

Self& operator++(){//右樹不為空,找右樹的最左結點(即最小結點)if (_node->_right){Node* subleft = _node->_right;while (subleft->_left){subleft = subleft->_left;}_node = subleft;}//右樹為空,else{Node* cur = _node;Node* parent = cur->_parent;//找孩子是父親左的那個祖先節(jié)點,就是下一個要訪問的節(jié)點while (parent && cur==parent->_right){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}
?operator--

1.減減的思路和加加的思路相反:

1)左不為空,訪問左樹的最右結點(即最大結點)。

2)左為空,下一個要訪問的孩子是父親右的那個祖先。

Self& operator--(){if (_node->_left){Node* subright = _node->_right;while (subright->_right){subright = subright->_right;}_node = subright;}else{Node* cur = _node;Node* parent = cur->_parent;while (parent && cur==parent->_left){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}

好了,迭代器接口的類已經(jīng)寫完了,現(xiàn)在我們利用上寫的迭代器函數(shù),進行對begin(),end()等實現(xiàn)上去。

begin()和end()函數(shù)

首先,我們先來看一下庫里面是如何進行實現(xiàn)的;

庫那利用了一個哨兵節(jié)點。

除了它的開銷:在旋轉操作中,為了維護父節(jié)點而付出了一定的代價。而且,當在最左邊或最右邊插入或刪除節(jié)點時,也需要進行相應的維護和修改

在這里,我們就不像它那樣實現(xiàn)了,復雜,難!

1.我們先對迭代器進行封裝,還是用上我們的模板:

2.begin()函數(shù)的解釋:因為底層實現(xiàn)是紅黑樹,即平衡二叉搜索樹,所以,我們開始的結點(中序遍歷)是左子樹最左的那個值,所以,要進行查找遍歷到左數(shù)最小的值,最后返回。

3.end()函數(shù)的解釋:直接返回迭代器為nullptr時。為什么呢?返回nullptr構造的迭代器,當遍歷完紅黑樹時,迭代器到達這個位置就說明遍歷完了有效的元素,和STL容器的迭代器使用習慣一致,方便搭配基于范圍for循環(huán)等遍歷方式:for(auto it=rbtree.begin();it!=end();it++).

4.下面還有就是實現(xiàn)了const迭代器。

template<class K,class T,class KeyOFT>
class RBTree
{typedef RBTreeNode<T> Node;public:typedef TreeIterator<T,T*,T&> iterator;iterator begin(){Node* LeftMin = _root;while (LeftMin && LeftMin->_left){LeftMin = LeftMin->_left;}return iterator(LeftMin);}iterator end(){return iterator(nullptr);}const_iterator begin()const{Node* LeftMin = _root;while (LeftMin && LeftMin->_left){LeftMin = LeftMin->_left;}return const_iterator(LeftMin);}const_iterator end()const {return const_iterator(nullptr);}
private:Node* _root = nullptr;
};

好了,紅黑樹里的迭代器封裝我們就基本實現(xiàn)完成了,那么現(xiàn)在,就開始對set與map進行對迭代器模板的使用。

set迭代器

同樣,我們來進行實現(xiàn)兩個迭代器,分別是普通迭代器和const迭代器。

但是,由上面一開始的分析我們也知道,set中是不可被修改的,否則就不是搜索樹了。

所以普通迭代器底層對紅黑樹的迭代器封裝時,也是使用了const迭代器進行封裝的,從而做到不可修改。

1.注意:為什么iterator begin()后面不加const不會通過編譯,會報錯?

因為:不加const的話,那么_t就是普通迭代器的_t,普通迭代器的t就只能調用普通的begin,普通的begin(),end(),返回的就是普通的iterator,普通的iterator能不能跟這個匹配?不能。

那么,我們只提供const版本的迭代器,有沒有價值呢?

答案是有點:反正它是不能被修改的,const對象可以調用const(平移),普通對象也是可以調用const的(縮小)。因為我們說過,對象可以平移或者縮小,但是不可以擴大。

比如:我們使用時:bai::set<int>::iterator it=_t.begin();

iterator可以轉化為const_itrerator,那要單獨寫一個構造進行轉化,但是typedef里的iterator還是要寫的,因為像我們平常的話,更多習慣用的還是iterator而不是const_iterator,對吧。

2.注意補充一點:類模板沒有實例化,編譯器不會去找。

內嵌類型:內部類,typedef

要加typename,相當于給編譯器吃一顆定心丸,告知編譯器它是合法的。(具體的可以去看一下關于進階模板的文章)

//有些代碼已經(jīng)省略
namespace bai
{template<class K>class My_set{public:typedef typename RBTree<K,K,SetKeyOFT>::const_iterator iterator;typedef typename RBTree<K, K, SetKeyOFT>::const_iterator const_iterator;iterator begin()const{return _t.begin();}iterator end()const{return _t.end();}private:RBTree<K, K, SetKeyOFT> _t;};
}

map迭代器

1.我們的map可以修改:即不可以修改K,可以修改Value,那么我們能不能繼續(xù)像剛才set那樣,,底層都是const_iterator?來保證K不變。

答:不可以,因為set只有一個,讓K不可被修改,若map也用的話,它不僅僅K不可改,連V也不可修改了。

那么,我們該怎么去做到不改變K,但是改變V呢?

我們可以在pair內部進行操作,即在pair<const K,V>,這樣的話pair可以被修改,但是K不可以修改了,達成我們的目的!

其他的做法,跟我們set的差不多!

namespace bai
{template<class K, class V>class My_map{public:typedef typename RBTree<K, pair<const K,V>, MapKeyOFT>::iterator iterator;typedef typename RBTree<K, pair<const K, V>, MapKeyOFT>::const_iterator const_iterator;iterator begin(){return _t.begin();}iterator end(){return _t.end();}const_iterator begin()const{return _t.begin();}const_iterator end()const{return _t.end();}private:RBTree<K, pair<const K, V>, MapKeyOFT> _t;};
}

隨之我們的迭代器部分的完善,我們的insert部分也要進一步改善的!

完善insert部分

insert部分返回值要改成pair<iterator,bool>

紅黑樹部分

講解

1.為什么要用newnode保存一下cur呢?不能直接用cur?

答:因為紅黑樹插入的過程中會有變色,cur的grandfather,cur可能往上走,不一定是新插入的結點,所以要保存一下新節(jié)點

pair<iterator, bool> insert(const T& data){KeyOFT kot;if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return make_pair(iterator(_root),true);}Node* cur = _root;Node* parent = nullptr;//Node* newnode = cur;while (cur){if (kot(cur->_data) < kot(data)){parent = cur;cur = cur->_right;}else if (kot(cur->_data) > kot(data)){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur), false);}}cur = new Node(data);//寫錯1Node* newnode = cur;cur->_col = RED;if (kot(parent->_data) < kot(data)){parent->_right=cur;}else{parent->_left=cur;}cur->_parent = parent;while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED){parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;//繼續(xù)向上更新cur = grandfather;parent = cur->_parent;}else//不存在 或者uncle為黑   旋轉+變色{if (cur == parent->_left){//        g//    p//cRotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;						}else //cur==parnet->right{//       g//	  p//       cRotateL(parent);RotateR(grandfather);cur->_col = BLACK;//parent->_col = BLACK;grandfather->_col = RED;}break;}  }else //(parent == grandfather->_right){Node* uncle = grandfather->_left;//Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;//繼續(xù)向上更新cur = grandfather;parent = cur->_parent;}else //(uncle不存在時)旋轉+變色{//		g //			p//				c	if (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}//		g //			p//		celse{RotateR(parent);RotateL(grandfather);cur->_col = BLACK;//parent->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return make_pair(iterator(newnode),true);}

你把樹里的改了,那么set與map的也要跟著改。但是這時候就會set的insert出現(xiàn)問題:

現(xiàn)在我們來看一下改變的代碼:

set部分

pair<iterator, bool> insert(const K& key)
{return _t.insert(key);
}

set沒有pair,而pair又是全局的。

會出現(xiàn)迭代器問題:

返回值的pair<iterator,bool>是RBTree::const_iterator

而你return的 _t.Insert(key)是pair<RBTree::iterator,bool>

那么,我們在insert() const? 行不行?

不能,_t是const,Insert也是const,那么必須去調用const insert,那就不能夠修改樹的結構了,所以不能!

再來回顧,make_pair會根據(jù)它的類型自己去推,在類里面直接用iterator,本質也是const_iterator.

這里的做法是:

拿一個普通迭代器去構造const迭代器!

按理說,迭代器不需要寫拷貝構造,因為編譯器默認寫:淺拷貝。


template<class T,class Ptr,class Ref>
struct TreeIterator
{typedef RBTreeNode<T> Node;typedef TreeIterator<T,Ptr,Ref> Self;typedef TreeIterator<T, T*, T&> Iterator;Node* _node;TreeIterator(Node*node):_node(node){ }TreeIterator(const Iterator&it):_node(it._node){ }
}

但這個函數(shù)也不完全是拷貝構造,因為它的返回值不是Self 。

Self與Iterator的區(qū)別:Self就是這個迭代器,但Iterator就不一定了。

可能聽到這里有點疑惑,別急,讓我們再來捋捋思路:

_t.insert是一個普通樹的對象,

pair<typename RBTree<K,K,SetkeyofT>::iterator,bool> ret=t.insert()

返回的是一個普通的迭代器,而set這層的iterator是const迭代器,傳不過去,所以我們的做法是:

單獨用一個pair對象普通樹的迭代器的對象去接受,接受了以后,再用這個東西去構造,傳參,first傳的是普通迭代器,

那么,普通迭代器為什么可以初始化const迭代器?

因為const迭代器中支持了一個構造,這兩個pair是同一個類模板,并不是同類型的。

當這個類被實例化成const迭代器時,這個函數(shù)是一個構造,支持普通迭代器構造const迭代器,為什么?

1.因為我實例化出const迭代器,我自己就是const迭代器,但是這個參數(shù)是iterator,特點是不管你是普通迭代器還是const迭代器,都是普通迭代器,因為這參數(shù)傳的是?

typedef TreeIterator<T, T*, T&> Iterator;

并不受Ref,Ptr影響。

2.當這個類被實例化成普通迭代器,這個函數(shù)就是一個拷貝構造(普通構造普通)。

map部分

      pair<iterator,bool> insert(const pair<K, V>& kv){return _t.insert(kv);}

也是跟上面的一樣理解。

map的operator[]部分

        V& operator[](const K& key){pair<iterator, bool> ret = insert(make_pair(key, V()));return ret.first->second;}

1.這是一個關聯(lián)式容器:

- ?make_pair(key, V())??:創(chuàng)建一個 ?pair??對象,?first??是傳入的 ?key??,?second??是默認構造的 ?V??類型對象(如果 ?V??是自定義類型,需有默認構造函數(shù) )。

- ?insert(make_pair(key, V()))??:調用下方自定義的 ?insert??函數(shù),嘗試插入pair??。

?insert??函數(shù)返回一個 ?pair??,其中 ?first??是指向插入位置(或已存在元素位置 )的迭代器,?second??是 ?bool??類型,?true??表示插入成功(之前無該 ?key??),?false??表示已存在(未插入新元素 )。

- ?return ret.first->second??:不管插入是否成功,通過迭代器 ?ret.first??訪問 ?pair??的 ?second??(即對應 ?key??的 ?value??)并返回其引用,

大整體部分就這樣了。

好的,本次分享就到處結束了,希望我們一起進步!

最后,到了本次雞湯環(huán)節(jié):

?下面圖片與大家共勉!

http://www.risenshineclean.com/news/4307.html

相關文章:

  • 青島網(wǎng)站開發(fā)公司一份完整的電商運營方案
  • lazada網(wǎng)站seo運營
  • 海外公司網(wǎng)站 國內做備案美國婚戀網(wǎng)站排名
  • 注冊個人網(wǎng)站要多少錢寧波關鍵詞優(yōu)化時間
  • 電子商務網(wǎng)站建設漢獅網(wǎng)站權重查詢工具
  • 淮安做網(wǎng)站的有多少站長之家音效
  • 小程序加盟平臺快速排名優(yōu)化
  • 免費php網(wǎng)站模板下載北京百度推廣電話號碼
  • 有個在家做的客服網(wǎng)站營銷型網(wǎng)站建站推廣
  • 網(wǎng)站標題分隔符搜索引擎競價排名
  • 地產公司做網(wǎng)站維護寫代碼么莆田百度seo公司
  • wordpress密碼忘記了百度問答優(yōu)化
  • 宿州網(wǎng)站建設哪家公司好新聞軟文范例大全
  • 可信賴的武漢網(wǎng)站建設信息如何優(yōu)化上百度首頁公司
  • 網(wǎng)站建設如何交稅南京seo報價
  • 校園網(wǎng)站設計全網(wǎng)seo優(yōu)化電話
  • 如何做屬于自己的領券網(wǎng)站長安seo排名優(yōu)化培訓
  • 新鄭做網(wǎng)站seo專業(yè)培訓費用
  • 南昌網(wǎng)站設計制作品牌推廣文案
  • 網(wǎng)站百度不收錄怎么做好網(wǎng)絡銷售
  • 做網(wǎng)站建設銷售員準備什么企業(yè)培訓課程設置
  • 百度廣告搜索推廣江蘇網(wǎng)站seo
  • 地稅城市維護建設稅網(wǎng)站是什么3a汽車集團公司網(wǎng)絡營銷方案
  • 免費可商用素材網(wǎng)站云浮seo
  • 哪些大型網(wǎng)站用python做的it培訓班學出來有用嗎
  • 找做牙工作上哪個網(wǎng)站百度站長鏈接提交
  • 中山公司做網(wǎng)站手機優(yōu)化軟件排行
  • wordpress app展示做網(wǎng)站優(yōu)化的公司
  • 網(wǎng)站模板怎么打開近期時政熱點新聞20條
  • 4網(wǎng)站建設上海百度關鍵詞推廣