红黑树封装实现树形结构的关联式容器(map,set)
生活随笔
收集整理的這篇文章主要介紹了
红黑树封装实现树形结构的关联式容器(map,set)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄
- 紅黑樹的改造
- 節點問題
- 插入問題
- 迭代器
- 紅黑樹的迭代器
- 改造紅黑樹
- map簡單模擬
- set簡單模擬
紅黑樹的改造
節點問題
map和set不同,map存放的是pair<K,V>鍵值對,而set中只有Key,我們要對紅黑樹節點進行改造,是她既能存放鍵值對,又能存放K值。
改造的節點結構體如下
插入問題
當紅黑樹插入一個數據時不用考慮只需直接和已經存在的節點比較大小,插入到合適的位置,但是我們這里實現map存放的是鍵值對pair<K,V>,不能直接比較大小,我們就采用仿函數,提取出key來比較大小,對于set來說插入k仿函數提取k,map插入pair<K,V>提取Key。
set的仿函數:
map仿函數:
struct mapoft {const K& operator () (const pair<K, V>& k) {return k.first;}};迭代器
紅黑樹的迭代器
迭代器的好處是可以方便遍歷,是數據結構的底層實現與用戶透明。如果想要給紅黑樹增加迭代器,需要考慮以下問題:
- STL明確規定,begin()與end()代表的是一段前閉后開的區間,而對紅黑樹進行中序遍歷后,可以得到一個有序的序列,因此:==begin()可以放在紅黑樹中最小節點(即最左側節點)的位置,end()放在最大節點(最右側節點)的下一個位置,即右子樹的最右節點的下一個節點為空。
改造紅黑樹
#pragma once #include<iostream> using namespace std;enum color {RED, BLACK,}; template<class T> struct tree {tree<T> *left;tree<T> *right;tree<T> *parent;T kv;color _col;tree(const T &_kv):kv(_kv), left(nullptr), right(nullptr), parent(nullptr),_col(RED){}}; //迭代器 template<class T,class Ref,class Ptr> struct RHterriterator {typedef RHterriterator<T, Ref, Ptr> self;//防止模板參數變動typedef tree<T> Node;Node* node;RHterriterator(Node* node):node(node) {}//返回節點kv的值T operator*() {return (node->kv);}//返回節點kv的地址Ptr operator->() {return &(node->kv);}//++it 前置++ 中序遍歷//左子樹 根 右子樹self operator++() {//找中序的下一個if (node->right) { //右數的最左節點Node* cur = node->right;while (cur && cur->left) {cur = cur->left;}node = cur;}else {//右為空,node所在子樹已經訪問完了//沿著路徑往根走,找孩子不是父親的右的哪個祖先Node* cur = node;Node* parent = cur->parent;while (parent&&parent->right==cur) {cur = parent;parent = cur->parent;}node = parent;}return *this;}//--it 前置-- 中序遍歷// 右子樹 根 左子樹//和++方向相反self operator--() {//找中序的下一個if (node->left) { //z左數的最右節點Node* cur = node->left;while (cur && cur->right) {cur = cur->right;}node = cur;}else {//左為空,node所在子樹已經訪問完了//沿著路徑往根走,找孩子不是父親的左的哪個祖先Node* cur = node;Node* parent = cur->parent;while (parent&&parent->left==cur) {cur = parent;parent = cur->parent;}node = parent;}return *this;}bool operator !=(const self s) const {return node != s.node;}bool operator ==(const self s) const {return node == s.node;} }; //set<K,K>----->Rh<k,V>; //map<k,V>----> RH<k,pair<K,V>> template<class K,class T,class keyoft1> class RHterr {public:typedef tree<T> Node;typedef RHterriterator<T, T*, T&> Iterator;typedef RHterriterator<const T,const T*, const T&> ConstIterator;//中序遍歷,找到紅黑樹的最左節點Iterator begin() {Node* cur = root;while (cur && cur->left) {cur = cur->left;}return Iterator(cur);}Iterator end() {return Iterator(nullptr);}pair<Node*, bool> Instor(const T &kv) {keyoft1 keyoft;if (root == nullptr) {root = new Node(kv);root->_col = BLACK;return make_pair(root, true);}Node* _parent = nullptr;Node* cur = root;while (cur) {if (keyoft(cur->kv) > keyoft( kv)) {_parent = cur;cur = cur->left;}else if (keyoft(cur->kv) < keyoft(kv)) {_parent = cur;cur = cur->right;}else {return make_pair(cur, false);}}cur = new Node(kv);if (keyoft(_parent->kv) > keyoft(kv)) {_parent->left = cur;cur->parent = _parent;}else {_parent->right = cur;cur->parent = _parent;}Node* newnode = cur;while (_parent&&_parent->_col==RED) {Node* grandfather = _parent->parent;if (grandfather->left == _parent) {Node* uncle = grandfather->right;//4.1的情況叔叔存在且為紅if (uncle && uncle->_col==RED) {uncle->_col = _parent->_col = BLACK;grandfather->_col = RED; //繼續往上處理cur = grandfather;_parent = cur->parent;//4.2叔叔不存在或為黑}else{//4.2.1if (cur ==_parent->left) {RHR(grandfather);_parent->_col = BLACK;grandfather->_col = RED;}//4.2.2else if(cur == _parent->right){RHL(_parent);RHR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}//4.3}else if (grandfather->right == _parent) {Node* uncle = grandfather->left;if (uncle && uncle->_col == BLACK) {uncle->_col = _parent->_col = BLACK;grandfather->_col = RED;cur = grandfather;_parent = cur->parent;}else{if (cur ==_parent->right) {RHL(grandfather);_parent->_col = BLACK;grandfather->_col = RED;}else if (cur == _parent->left) {RHR(_parent);RHL(grandfather);grandfather->_col = RED;cur->_col = BLACK;}break;}}}root->_col = BLACK;return make_pair(newnode, true);}void RHR(Node* parent){Node* subL = parent->left;Node* subLR = subL->right;parent->left = subLR;//但是subLR有可能是空的,那么下面這個代碼就會崩if (subLR)subLR->parent = parent;Node* parentParent = parent->parent;subL->right = parent;parent->parent = subL;//此時還需要最后一步,把根結點換掉if (parent == root){root = subL;root->parent = nullptr;}else{//此時你需要把30這個結點連接住,但是應該連接在哪一邊還需要進行判斷if (parentParent->left == parent){parentParent->left = subL;}else{parentParent->right = subL;}subL->parent = parentParent;}}void RHL(Node* parent){Node* subR = parent->right;Node* subRL = subR->left;parent->right = subRL;if (subRL)subRL->parent = parent;Node* parentParent = parent->parent;//先保存下來,因為后面會改變這個,就找不到最開始的父節點了subR->left = parent;parent->parent = subR;if (parent == root){root = subR;subR->parent = nullptr;}else{//作為子樹的一部分if (parentParent->left == parent){parentParent->left = subR;}else{parentParent->right = subR;}subR->parent = parentParent;}}bool isBalance(){//根節點為黑if (root->_col == RED) {cout << "不符合紅黑樹結構" << endl;return false;}int num = 0;int truenum = 0;Node* cutt = root;while(cutt) {if (cutt->_col == BLACK) {truenum++;}cutt =cutt->left;}//檢測是否滿足紅黑樹的性質,用來記錄路徑中黑色節點的個數return chackRED(root)//檢查紅節點&& chackBLACK(root, num,truenum);//根不可能是紅色的}bool chackRED(Node* cur) {if (cur == nullptr) {return true;}if (cur->_col == RED) {//檢查Cur的父親是否符合條件Node* parent = cur->parent;if (parent->_col == RED) {cout << "違反限制:存在連續的紅節點" << endl;return false;}}return chackRED(cur->left) && chackRED(cur->right);//如果左子樹違反就不用遍歷右子樹了}//qbool chackBLACK(Node *root,int BlackNum ,int truenum) {if (root == nullptr) {//當走到NULL時,truenum這條路徑黑色節點的數量return BlackNum==truenum;}// 統計黑色節點的個數if (root->_col == BLACK) {BlackNum++;}return chackBLACK(root->left, BlackNum,truenum) &&chackBLACK(root->right, BlackNum,truenum);} private:Node* root=nullptr;};map簡單模擬
map的底層就是紅黑樹,因此map封裝了一顆紅黑樹,模擬map只需調用紅黑樹的接口實現map的功能
#include "rg.h" namespace stt {template<class K, class V >class Map {struct mapoft {const K& operator () (const pair<K, V>& k) {return k.first;}};private:RHterr<K, const pair<const K, V>, mapoft> t;public:/* pair<tree<pair<const K, V>>*, bool> inse(const pair<const K, V>& k) {return t.Instor(k);}*/typedef typename RHterr<K, K, mapoft>::Iterator iterator;iterator begin() {return t.begin();}iterator end() {return t.end();}V& operator[](const K&k) {pair<iterator, bool> ret = inse(make_pair(k, V()));return ret.first->second;}pair<tree<pair<K,V>>*, bool> inse(const pair<const K, V>& kv){return t.Instor(kv);}};void text() {Map<int, int> m;m.inse(make_pair(1, 1));m.inse(make_pair(2, 1));m.inse(make_pair(3, 1));m.inse(make_pair(4, 1));} }set簡單模擬
set的底層就是紅黑樹,因此set封裝了一顆紅黑樹,模擬set只需調用紅黑樹的接口實現set的功能
#pragma once#include "rg.h" namespace st {template<class k >class set {struct setoft {const k& operator () (const k& k) {return k;}};private:RHterr<k, k, setoft> t;public://typedef是對一個類型重命名,因為他是一個類模板,只有在實例化才生成代碼,而在這沒有實例化,typename告訴這是一個類型typedef typename RHterr<k, k, setoft>::Iterator iterator;iterator begin() {return t.begin();}iterator end() {return t.end();}pair<tree<k>*, bool> inse(const k& k) {return t.Instor(k);}};void te() {st::set<int> s;s.inse(1);s.inse(2);s.inse(3);s.inse(4);s.inse(5);set<int>::iterator it = s.begin();while (it!=s.end()) {cout << *it << endl;++it;}} }總結
以上是生活随笔為你收集整理的红黑树封装实现树形结构的关联式容器(map,set)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MATLAB中alignsignals函
- 下一篇: Arthas : 具体问题分析小册子