【C++】set模拟实现

前言:

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

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
cpp 复制代码
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的构造函数

cpp 复制代码
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);
}
cpp 复制代码
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的查找。本质上是一样的。
cpp 复制代码
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的迭代器

迭代器的封装

  • set迭代器类似于list的迭代器
  • 主要区别在于++--
  • Ptr是T*,Ref是T&,设置这么多的模板参数是为适配出const的迭代器
  • 注意的是需要Iterator的构造函数,因为set的迭代器都是const的迭代器。
cpp 复制代码
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;
	}

};

前置++

  • 前置++ 的本质上就是中序的遍历,左子树-根-右子树
  • 如果右子树存在就去右子树的最左节点
  • _node 不是右节点那么,证明子树的左右节点均访问完成,需要访问祖父的节点
cpp 复制代码
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;
}

前置--

  • 前置-- 是前置++的镜像的一个顺序的访问,右子树-根-左子树
  • 方法是类似于前置++
cpp 复制代码
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时候只需要调用,在这里面可以认为红黑树是容器的适配器
cpp 复制代码
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

cpp 复制代码
#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;
	};
}

红黑树

cpp 复制代码
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;
};
相关推荐
湫ccc44 分钟前
《Python基础》之字符串格式化输出
开发语言·python
弗拉唐44 分钟前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi771 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
mqiqe1 小时前
Python MySQL通过Binlog 获取变更记录 恢复数据
开发语言·python·mysql
AttackingLin1 小时前
2024强网杯--babyheap house of apple2解法
linux·开发语言·python
少说多做3432 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀2 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20202 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea