【C++】set模拟实现

chian-ocean 2024-09-17 09:35:10 阅读 70

前言:

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

<code>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;

};



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。