当前位置:首页 » 《休闲阅读》 » 正文

【C++】set模拟实现

23 人参与  2024年09月10日 09:21  分类 : 《休闲阅读》  评论

点击全文阅读


前言:

C++中的set是标准模板库(STL)中的一种关联容器,它存储了一组唯一的元素,并且这些元素是按照特定的顺序(默认是升序)进行排序的

set的介绍

C++中的set是标准模板库(STL)中的一种关联容器,它存储了一组唯一的元素,并且这些元素是按照特定顺序(默认是升序)排序的。set内部使用红黑树这种平衡二叉搜索树来组织元素,这使得set能够提供对数时间复杂度的查找、插入和删除操作。

set的特点

唯一性:set中的元素是唯一的,插入重复元素时,新元素不会被添加到容器中。自动排序:set会自动对元素进行排序,不需要用户手动维护元素的顺序。高效的查找、插入和删除操作:由于set内部通常使用红黑树实现,这些操作的时间复杂度为对数级别(O(log n))。迭代器稳定性:在set中插入或删除元素不会使现有的迭代器失效,除了指向被删除元素的迭代器

set的实现(set的底层是红黑树)红黑树

set的结构

由于set和map是公用一棵树,set是K 、map是KV的结构,为了适应map的结构,set做出一定的改变内部类是为了取到set内所存储的数据在set的map中 set所存储的是key而map是pair
template<class K>    class set    {        struct setofkey        {            const K& operator()(const K& key)            {                return key;            }        };        public:        private:        RBTree <K, K, setofkey> _t;    };

set的插入

这是红黑树的底层插入,大体上和红黑树是一样的

寻找插入位置,进行插入。

调整红黑树,保持红黑树的结构

第一行的iterator是普通迭代器,而return返回的是const迭代器。在迭代器的封装的时候就要写iterator的构造函数

pair<iterator,bool> insert(const K& key){    pair<typename RBTree <K, K, setofkey>::iterator, bool> ret = _t.insert(key);    return pair<iterator, bool>(ret.first, ret.second);}
pair<iterator,bool> insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return make_pair(iterator(_root),true);}Node* parent = nullptr;Node* cur = _root;keyofT kot;while (cur){if (kot(data) > kot(cur->_data)){parent = cur;cur = cur->_right;}else if (kot(data) < kot(cur->_data)){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur), false);}}cur = new Node(data);Node* newnode = cur;cur->_col = RED;if (kot(data) < kot(parent->_data)){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;while (parent && parent->_col == RED){Node* grandparent = parent->_parent;if (parent == grandparent->_left){Node* uncle = grandparent->_right;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}else//uncle is not or black{if (cur == parent->_left){RotateR(grandparent);grandparent->_col = RED;parent->_col = BLACK;}else{RotateL(parent);RotateR(grandparent);grandparent->_col = RED;cur->_col = BLACK;}break;}}else//parent == grandparent->_right{Node* uncle = grandparent->_left;if (uncle && uncle->_col == RED){grandparent->_col = RED;parent->_col = uncle->_col = BLACK;cur = grandparent;parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandparent);parent->_col = BLACK;grandparent->_col = RED;}else{RotateR(parent);RotateL(grandparent);cur->_col = BLACK;grandparent->_col = RED;}}break;}}_root->_col = BLACK;return make_pair(iterator(newnode),true );}

set的查找

红黑树的查找类似于,AVL的查找。本质上是一样的。
Node* find(const T& data){    keyofT kot;    Node* cur = _root;    while (cur)    {        if (kot(data) > kot(cur->_data))        {            cur = cur->_right;        }        else if (kot(data) < kot(cur->_data))        {            cur = cur->_left;        }        else        {            return cur;        }    }    return nullptr;}

set的迭代器

迭代器的概念

迭代器是一种抽象数据类型,它提供了一种方法来遍历容器中的元素,就像指针遍历数组一样。C++中的迭代器分为五种:输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器。set的迭代器是双向迭代器,这意味着它们可以向前和向后遍历元素

迭代器的封装

set迭代器类似于list的迭代器主要区别在于++--Ptr是T*,Ref是T&,设置这么多的模板参数是为适配出const的迭代器注意的是需要Iterator的构造函数,因为set的迭代器都是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){}Ref operator* (){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator != (const self & s) const {return _node!= s._node;}bool operator== (const self & s) const {return _node == s._node;}};

迭代器的核心

set的迭代器在内部维护了指向树中节点的指针。由于set是有序的,迭代器在递增或递减时会沿着树的左子树或右子树进行遍历。迭代器的operator++(递增)和operator–(递减)操作会更新迭代器所指向的节点,移动到下一个或上一个有序元素。

前置++

前置++ 的本质上就是中序的遍历,左子树-根-右子树如果右子树存在就去右子树的最左节点_node 不是右节点那么,证明子树的左右节点均访问完成,需要访问祖父的节点
self& operator++(){    if (_node->_right)    {        Node* cur = _node->_right;        while (cur->_left)        {            cur = cur->_left;        }        _node = cur;    }    else    {        Node* cur = _node;        Node* parent = _node->_parent;        while (parent)        {            if (cur == parent->_left)            {                break;            }            else            {                cur = cur->_parent;                parent = parent->_parent;            }        }        _node = parent;    }    return *this;}

前置- -

前置-- 是前置++的镜像的一个顺序的访问,右子树-根-左子树方法是类似于前置++
self& operator--(){if (_node->_left){Node* cur = _node->_right;while (cur->_left){cur = cur->_right;}_node = cur;}else{Node* cur = _node;Node* parent = _node->_parent;while (parent && parent->_left){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}

迭代器

前面是将迭代器封装,因为正常的++或者–已不可以支持自定义类型的加减在红黑树的类中实现,在实现set时候只需要调用,在这里面可以认为红黑树是容器的适配器
typedef TreeIterator<T, T*, T&> iterator;typedef TreeIterator<T,const T*,const T&> const_iterator;iterator begin(){    Node* leftmin = _root;    while (leftmin->_left)    {        leftmin = leftmin->_left;    }    return iterator(leftmin);}iterator end(){    return iterator(nullptr);}const_iterator begin()const {    Node* leftmin = _root;    while (leftmin->_left)    {        leftmin = leftmin->_left;    }    return const_iterator(leftmin);}const_iterator end()const {    return const_iterator(nullptr);}

源码

set

#pragma once#include"RBTree.h"#include<iostream>using namespace std;namespace Set{template<class K>class set{struct setofkey{const K& operator()(const K& key){return key;}};public:typedef typename RBTree<K, K, setofkey>::const_iterator iterator;typedef typename RBTree<K, K, setofkey>::const_iterator const_iterator;iterator begin()const {return _t.begin();}iterator end()const {return _t.end();}pair<iterator,bool> insert(const K& key){pair<typename RBTree <K, K, setofkey>::iterator, bool> ret = _t.insert(key);return pair<iterator, bool>(ret.first, ret.second);}private:RBTree <K, K, setofkey> _t;};}

红黑树

enum Colour{RED,BLACK};template< class T>class RBTreeNode{public:RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;T _data;Colour _col;RBTreeNode(const T& data):_left(nullptr), _right(nullptr), _parent(nullptr), _col(RED), _data(data){}}; 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){}Ref operator* (){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator != (const self & s) const {return _node!= s._node;}bool operator== (const self & s) const {return _node == s._node;}self& operator--(){if (_node->_left){Node* cur = _node->_right;while (cur->_left){cur = cur->_right;}_node = cur;}else{Node* cur = _node;Node* parent = _node->_parent;while (parent && parent->_left){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}self& operator++(){if (_node->_right){Node* cur = _node->_right;while (cur->_left){cur = cur->_left;}_node = cur;}else{Node* cur = _node;Node* parent = _node->_parent;while (parent){if (cur == parent->_left){break;}else{cur = cur->_parent;parent = parent->_parent;}}_node = parent;}return *this;}};template<class K, class T,class keyofT>class RBTree{typedef RBTreeNode<T> Node;public:typedef TreeIterator<T, T*, T&> iterator;typedef TreeIterator<T,const T*,const T&> const_iterator;iterator begin(){Node* leftmin = _root;while (leftmin->_left){leftmin = leftmin->_left;}return iterator(leftmin);}iterator end(){return iterator(nullptr);}const_iterator begin()const {Node* leftmin = _root;while (leftmin->_left){leftmin = leftmin->_left;}return const_iterator(leftmin);}const_iterator end()const {return const_iterator(nullptr);}Node* find(const T& data){keyofT kot;Node* cur = _root;while (cur){if (kot(data) > kot(cur->_data)){cur = cur->_right;}else if (kot(data) < kot(cur->_data)){cur = cur->_left;}else{return cur;}}return nullptr;}pair<iterator,bool> insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return make_pair(iterator(_root),true);}Node* parent = nullptr;Node* cur = _root;keyofT kot;while (cur){if (kot(data) > kot(cur->_data)){parent = cur;cur = cur->_right;}else if (kot(data) < kot(cur->_data)){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur), false);}}cur = new Node(data);Node* newnode = cur;cur->_col = RED;if (kot(data) < kot(parent->_data)){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;while (parent && parent->_col == RED){Node* grandparent = parent->_parent;if (parent == grandparent->_left){Node* uncle = grandparent->_right;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}else//uncle is not or black{if (cur == parent->_left){RotateR(grandparent);grandparent->_col = RED;parent->_col = BLACK;}else{RotateL(parent);RotateR(grandparent);grandparent->_col = RED;cur->_col = BLACK;}break;}}else//parent == grandparent->_right{Node* uncle = grandparent->_left;if (uncle && uncle->_col == RED){grandparent->_col = RED;parent->_col = uncle->_col = BLACK;cur = grandparent;parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandparent);parent->_col = BLACK;grandparent->_col = RED;}else{RotateR(parent);RotateL(grandparent);cur->_col = BLACK;grandparent->_col = RED;}}break;}}_root->_col = BLACK;return make_pair(iterator(newnode),true );}void RotateR(Node* parent){Node* cur = parent->_left;Node* curright = cur->_right;parent->_left = curright;if (curright){curright->_parent = parent;}cur->_right = parent;Node* ppnode = parent->_parent;parent->_parent = cur;if (ppnode == nullptr){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right = cur;}cur->_parent = ppnode;}}void RotateL(Node* parent){Node* cur = parent->_right;Node* curleft = cur->_left;parent->_right = curleft;if (curleft){curleft->_parent = parent;}cur->_left = parent;Node* ppnode = parent->_parent;parent->_parent = cur;if (parent == _root){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right = cur;}cur->_parent = ppnode;}}private:Node* _root = nullptr;};

点击全文阅读


本文链接:http://zhangshiyu.com/post/157616.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1