STL之set和map

目录

  • 一. 原型
  • 二. 模板参数适配
  • 三. 迭代器
  • 四. 插入函数的修改
  • 四. 代码

一. 原型

  • 简单实现的红黑树
template
struct RBTreeNode
{
    RBTreeNode* _left;
	RBTreeNode* _right;
	RBTreeNode* _parent;
    
	pair _kv;
	Colour _col;
};

template
struct RBTree
{
    typedef RBTreeNode Node;
public:
    bool Insert(const pair& kv);
    Node* Find(const K& key); 
private:
	Node* _root = nullptr;
};
  • set
template
class set
{
private:
    RBTree _t;
};
  • map
template
class map
{
private:
    RBTree _t;
};

二. 模板参数适配

  • 红黑树
template
struct RBTreeNode
{
	RBTreeNode* _left;
	RBTreeNode* _right;
	RBTreeNode* _parent;

	T _data;
	Colour _col;
};

template
struct RBTree
{
    typedef RBTreeNode Node;
public:
    bool Insert(const T& data);
    Node* Find(const K& key);     
private:
	Node* _root = nullptr;
}
  • set
template
class set
{
    //仿函数
    struct SetKeyOfT//返回K对象的key
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};
private:
    RBTree _t;
};
  • map
template
class map
{
	struct MapKeyOfT//返回pair对象的key
	{
		const K& operator()(const pair& kv)
		{
			return kv.first;
		}
	};
private:
    RBTree, MapKeyOfT> _t;
};

STL之set和map_第1张图片

红黑树作为底层结构而言,它不能够区分使用者是set还是map。

class K:表示键值类型

class T:表示存储类型

class KeyOfT:仿函数,用于从T类型中提取K键值

对于set容器,底层存储K类型元素,键值也为K

对于map容器,底层存储键值对,键值为K

三. 迭代器

设计迭代器,方便遍历,让用户在使用时不需要在意底层实现。

template
struct __RBTreeIterator
{
	typedef RBTreeNode Node;
	typedef __RBTreeIterator Self;

	Node* _node;

	__RBTreeIterator(Node* node)
		:_node(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++();
    Self& operator--();
};

template
struct RBTree
{
	typedef __RBTreeIterator iterator;
public:
    // 最左节点
    iterator begin()
	{
		Node* left = _root;
		while (left && left->_left)
		{
			left = left->_left;
		}

		return iterator(left);
	}
	// 最后一个节点的下一个位置
	iterator end()
	{
		return iterator(nullptr);
	}
};

STL之set和map_第2张图片

  1. operator++()

步骤:

  • 右子树不为空,++就是找右子树中序第一个(最左节点)
  • 右子树为空,++找孩子不是父亲右的那个祖先
Self& operator++()
{
    if (_node->_right)
    {
        // 下一个就是右子树的最左节点
        Node* left = _node->_right;
        while (left->_left)
        {
            left = left->_left;
        }

        _node = left;
    }
    else
    {
        // 找祖先里面孩子不是祖先的右的那个
        Node* parent = _node->_parent;
        Node* cur = _node;
        while (parent && cur == parent->_right)
        {
            cur = cur->_parent;
            parent = parent->_parent;
        }

        _node = parent;
    }

    return *this;
}
  1. operator--()

与++相反,步骤:

  • 左子树不为空,–就是找左子树的最右节点
  • 左子树为空,–找孩子不是父亲的左的那个祖先
Self& operator--()
{
    if (_node->_left)
    {
        // 下一个是左子树的最右节点
        Node* right = _node->_left;
        while (right->_right)
        {
            right = right->_right;
        }

        _node = right;
    }
    else
    {
        // 孩子不是父亲的左的那个祖先
        Node* parent = _node->_parent;
        Node* cur = _node;
        while (parent && cur == parent->_left)
        {
            cur = cur->_parent;
            parent = parent->_parent;
        }

        _node = parent;
    }

    return *this;
}

四. 插入函数的修改

pair 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;//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);
    Node* newnode = cur;//标记新节的

    if (kot(parent->_data) < kot(data))//新节点的键值大于parent
    {
        parent->_right = cur;//放在parent的右边
    }
    else
    {
        parent->_left = cur;//左边
    }
    cur->_parent = parent;

    // 调整
    //(cur最差会遍历到根节点)p为红色
    while (parent && parent->_col == RED)
    {
        Node* grandfater = parent->_parent;//parent的父节点

        // 关键看叔叔
        if (parent == grandfater->_left)//p是g的左孩子
        {
            Node* uncle = grandfater->_right;//叔叔节点

            // 情况一 : u为红,
            if (uncle && uncle->_col == RED)
            {
                // 变色
                parent->_col = uncle->_col = BLACK;
                grandfater->_col = RED;
                // 继续往上处理
                cur = grandfater;
                parent = cur->_parent;
            }
            else// 情况二:u为黑
            {
                if (cur == parent->_left)//c为p的左孩子
                {
                    // 右单旋+变色
                    //     g 
                    //   p   u
                    // c
                    RotateR(grandfater);//右旋
                    parent->_col = BLACK;
                    grandfater->_col = RED;
                }
                else//c为p的右孩子
                {
                    //  左右单旋+变色
                    //     g 
                    //   p   u
                    //     c
                    RotateL(parent);//左旋
                    RotateR(grandfater);//右旋
                    cur->_col = BLACK;
                    grandfater->_col = RED;
                }
                break;//结束
            }
        }
        else // (parent == grandfater->_right) //p是g的右孩子
        {
            Node* uncle = grandfater->_left;//叔叔节点

            // 情况一 : u为红,
            if (uncle && uncle->_col == RED)
            {
                // 变色
                parent->_col = uncle->_col = BLACK;
                grandfater->_col = RED;
                // 继续往上处理
                cur = grandfater;
                parent = cur->_parent;
            }
            else//情况二 : u为黑,
            {
                if (cur == parent->_right)//c为p的右孩子
                {
                    // 左单旋+变色
                    //     g 
                    //   u   p
                    //         c
                    RotateL(grandfater);//左旋
                    parent->_col = BLACK;
                    grandfater->_col = RED;
                }
                else// c为p的左孩子
                {
                    // 情况三:右左单旋+变色
                    //     g 
                    //   u   p
                    //     c
                    RotateR(parent);//右旋
                    RotateL(grandfater);//左旋
                    cur->_col = BLACK;
                    grandfater->_col = RED;
                }
                break;//结束
            }
        }
    }
    _root->_col = BLACK;//根节点颜色为黑色(可能在情况一下被修改)

    return make_pair(iterator(newnode), true);
}

将Insert()的返回值改为pair的形式,主要是为了实现map中的operator[]

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

四. 代码

  • 红黑树
#pragma once
enum Colour
{
	RED,
	BLACK
};

template
struct RBTreeNode
{
	RBTreeNode* _left;
	RBTreeNode* _right;
	RBTreeNode* _parent;

	T _data;
	Colour _col;

	RBTreeNode(const T& data)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _data(data)
		, _col(RED)
	{}
};

template
struct __RBTreeIterator
{
	typedef RBTreeNode Node;
	typedef __RBTreeIterator Self;

	Node* _node;

	__RBTreeIterator(Node* node)
		:_node(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->_right)
		{
			// 下一个就是右子树的最左节点
			Node* left = _node->_right;
			while (left->_left)
			{
				left = left->_left;
			}

			_node = left;
		}
		else
		{
			// 找祖先里面孩子不是祖先的右的那个
			Node* parent = _node->_parent;
			Node* cur = _node;
			while (parent && cur == parent->_right)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}

	Self& operator--()
	{
		if (_node->_left)
		{
			// 下一个是左子树的最右节点
			Node* right = _node->_left;
			while (right->_right)
			{
				right = right->_right;
			}

			_node = right;
		}
		else
		{
			// 孩子不是父亲的左的那个祖先
			Node* parent = _node->_parent;
			Node* cur = _node;
			while (parent && cur == parent->_left)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}
};

template
struct RBTree
{
	typedef RBTreeNode Node;
	typedef __RBTreeIterator iterator;

public:

	iterator begin()
	{
		Node* left = _root;
		while (left && left->_left)
		{
			left = left->_left;
		}

		return iterator(left);
	}

	iterator end()
	{
		return iterator(nullptr);
	}

	pair 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;//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);
		Node* newnode = cur;//标记新节的

		if (kot(parent->_data) < kot(data))//新节点的键值大于parent
		{
			parent->_right = cur;//放在parent的右边
		}
		else
		{
			parent->_left = cur;//左边
		}
		cur->_parent = parent;

		// 调整
		//(cur最差会遍历到根节点)p为红色
		while (parent && parent->_col == RED)
		{
			Node* grandfater = parent->_parent;//parent的父节点

			// 关键看叔叔
			if (parent == grandfater->_left)//p是g的左孩子
			{
				Node* uncle = grandfater->_right;//叔叔节点

				// 情况一 : u为红,
				if (uncle && uncle->_col == RED)
				{
					// 变色
					parent->_col = uncle->_col = BLACK;
					grandfater->_col = RED;
					// 继续往上处理
					cur = grandfater;
					parent = cur->_parent;
				}
				else// 情况二:u为黑
				{
					if (cur == parent->_left)//c为p的左孩子
					{
						// 右单旋+变色
						//     g 
						//   p   u
						// c
						RotateR(grandfater);//右旋
						parent->_col = BLACK;
						grandfater->_col = RED;
					}
					else//c为p的右孩子
					{
						//  左右单旋+变色
						//     g 
						//   p   u
						//     c
						RotateL(parent);//左旋
						RotateR(grandfater);//右旋
						cur->_col = BLACK;
						grandfater->_col = RED;
					}
					break;//结束
				}
			}
			else // (parent == grandfater->_right) //p是g的右孩子
			{
				Node* uncle = grandfater->_left;//叔叔节点

				// 情况一 : u为红,
				if (uncle && uncle->_col == RED)
				{
					// 变色
					parent->_col = uncle->_col = BLACK;
					grandfater->_col = RED;
					// 继续往上处理
					cur = grandfater;
					parent = cur->_parent;
				}
				else//情况二 : u为黑,
				{
					if (cur == parent->_right)//c为p的右孩子
					{
						// 左单旋+变色
						//     g 
						//   u   p
						//         c
						RotateL(grandfater);//左旋
						parent->_col = BLACK;
						grandfater->_col = RED;
					}
					else// c为p的左孩子
					{
						// 情况三:右左单旋+变色
						//     g 
						//   u   p
						//     c
						RotateR(parent);//右旋
						RotateL(grandfater);//左旋
						cur->_col = BLACK;
						grandfater->_col = RED;
					}
					break;//结束
				}
			}
		}
		_root->_col = BLACK;//根节点颜色为黑色(可能在情况一下被修改)

		return make_pair(iterator(newnode), true);
	}
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

	bool IsRBTree()
	{
		if (_root == nullptr)
		{
			return true;
		}

		if (_root->_col == RED)
		{
			cout << "根节点不是黑色" << endl;
			return false;
		}

		int benchmark = 0;// 黑色节点数量基准值

		return PrevCheck(_root, 0, benchmark);
	}

private:
	// 休息21:18继续
	bool PrevCheck(Node* root, int blackNum, int& benchmark)
	{
		if (root == nullptr)//路径走完,到空节点
		{
			//benchark更新为第一条路径上黑色节点的数量
			if (benchmark == 0)
			{
				benchmark = blackNum;
				return true;
			}

			if (blackNum != benchmark)
			{
				cout << "某条路径黑色节点的数量不相等" << endl;
				return false;
			}
			else
			{
				return true;
			}
		}

		if (root->_col == BLACK)
		{
			++blackNum;
		}

		if (root->_col == RED && root->_parent->_col == RED)
		{
			cout << "存在连续的红色节点" << endl;
			return false;
		}

		return PrevCheck(root->_left, blackNum, benchmark)
			&& PrevCheck(root->_right, blackNum, benchmark);
	}

	void _InOrder(Node* root)
	{
		KeyOfT kot;
		if (root == nullptr)
		{
			return;
		}

		_InOrder(root->_left);
		cout << kot(root->_data) << ":" << root->_data << endl;
		_InOrder(root->_right);
	}

	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

		Node* ppNode = parent->_parent;

		subR->_left = parent;
		parent->_parent = subR;

		if (_root == parent)
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subR;
			}
			else
			{
				ppNode->_right = subR;
			}

			subR->_parent = ppNode;
		}

	}

	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		if (subLR)
		{
			subLR->_parent = parent;
		}

		Node* ppNode = parent->_parent;

		subL->_right = parent;
		parent->_parent = subL;

		if (_root == parent)
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subL;
			}
			else
			{
				ppNode->_right = subL;
			}

			subL->_parent = ppNode;
		}

	}

private:
	Node* _root = nullptr;
};
  • set
#pragma once

#include "RBTree.h"

template
class set
{
	struct SetKeyOfT
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};
public:
	typedef typename RBTree::iterator iterator;

	iterator begin()
	{
		return _t.begin();
	}

	iterator end()
	{
		return _t.end();
	}

	pair insert(const K& key)
	{
		return _t.Insert(key);
	}

private:
	RBTree _t;
};
  • map
#pragma once

#include "RBTree.h"

template
class map
{
	struct MapKeyOfT
	{
		const K& operator()(const pair& kv)
		{
			return kv.first;
		}
	};
public:
	typedef typename RBTree, MapKeyOfT>::iterator iterator;

	iterator begin()
	{
		return _t.begin();
	}

	iterator end()
	{
		return _t.end();
	}

	pair insert(const pair& kv)
	{
		return _t.Insert(kv);
	}

	V& operator[](const K& key)
	{
		pair ret = insert(make_pair(key, V()));
		return ret.first->second;
	}
private:
	RBTree, MapKeyOfT> _t;
};

观看~~

你可能感兴趣的:(数据结构,一块来学C++,c++,开发语言)