C++:map和set

目录

一.set介绍

1.set介绍

2.insert 使用

 set中的普通迭代器就是用的const迭代器!!

3.find

set::find和std::find对比

4.erase

5.swap 根节点交换

6.count 比find方便

7.lower_bound:返回>= val得位置迭代器

(1)lower_bound

用途:举例:要求删除>=x的所有值:

(2)upper_bound 返回>x位置的迭代器

8. std::multiset 跟set接口一样,只是允许冗余,不去重

9.set相关题目

二.map用法介绍

几个map和set的冷知识:

map:

①map是C++98中已存在的,unordered_map是C++11中才有的

②map中都重载了[]运算符,multimap中没有重载[]运算符,set也没有重载[]。

③map中key不能修改,因为如果修改了就不能保证红黑树的有序特性了

set:

①set中也可以存储键值对,实例化set时,将set中元素类型设置为pair即可

②set默认是升序,但是其内部默认不是按照大于比较,而是按照 less小于比较

③map和set查询的时间复杂度都是O(log_2N)

④map和set底层都是使用红黑树实现的

1.pair和make_pair

(1)pair键值对 的介绍

(2)make_pair 介绍

2.map的遍历

(1)英汉字典的遍历

(2)记录水果次数

3.insert写法提高 记录水果次数 的效率(不这么写,只是为[]做铺垫)

4.operator[] 运算符重载 

(1) 提高 记录水果次数 的效率的真正写法:

(2) 字典中利用[]插入或修改 示例

5.multimap 允许键值冗余

三.相关题目

1.692. 前K个高频单词

(1)做法一:stable_sort稳定排序

(2)做法二:stable_sort稳定排序 2

(3)做法三:sort 非稳定排序,可以控制比较方法使其稳定

 (4)做法四:利用map自身按照first排序

四.模拟实现

Map.h

Set.h

RBTree.h


一.set介绍

1.set介绍

set 是一个K模型的搜索二叉树 #include<set>

2.insert 使用

(1)和(2)相当于一样,在pos位置插入也会自动排序

 insert :排序 + 去重 

void test_set1()
{
	set<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(2);
	s.insert(1);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(1);


	// 排序 + 去重 
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		//*it = 10;    迭代器不支持修改
		cout << *it << " ";
		++it;
	}
	cout << endl;

    for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}

 set中的普通迭代器就是用的const迭代器!!


 

3.find

能找到就返回元素的迭代器,找不到就返回end

set::find和std::find对比

set::find 搜索二叉树特性查找,时间复杂度是O(logN)

全局的find 是暴力查找,时间复杂度是O(N)

所以set::find效率更高

void test_set2()
{
	set<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(2);
	s.insert(1);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(1);

	set<int>::iterator pos = s.find(20);  // O(logN)
	if (pos != s.end())
	{
		cout << "set.find找到了" << endl;
	}

	pos = find(s.begin(), s.end(), 2); // O(N)
	if (pos != s.end())
	{
		cout << "find找到了" << endl;
	}
}

4.erase

size_type就是size_t,也就是unsigned int

(1) void erase (iterator position); 必须加检查if (pos != s.end()) s.erase(pos); 因为有pos时,正常运行,如果没有pos,就会报错。例如:s.erase(pos);

(2)size_ type erase (const value_ type& val) ; 则可以随便删,无论有没有都不报错 例如:s.erase(3)

(3)void erase (iterator first,iterator last) 删的是[ first, last),即不包含 last

void test_set3()
{
	set<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(2);
	s.insert(1);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(1);

	cout << s.erase(3) << endl;    //有就返回1
	cout << s.erase(30) << endl;   //没有就返回0

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	set<int>::iterator pos = s.find(3);
	if (pos != s.end())
		s.erase(pos);

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

5.swap 根节点交换

6.count 比find方便


	if (s.count(5))
	{
		cout << "5在" << endl;
	}

	if (s.find(5) != s.end())
	{
		cout << "5在" << endl;
	}

打印:

5在

5在

7.lower_bound:返回>= val得位置迭代器

(1)lower_bound

返回>= val得位置迭代器 3返回3位置 6 返回7位置

返回>= val的位置迭代器 3返回3位置 6 返回7位置
    set<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(7);
	s.insert(9);
    set<int>::iterator lowIt = s.lower_bound(3); 存在
	lowIt = s.lower_bound(6); 不存在

用途:举例:要求删除>=x的所有值:

void test_set4()
{
	set<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(7);
	s.insert(9);
    for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	// 要求删除>=x的所有值
	int x;
	cin >> x;
	set<int>::iterator lowIt = s.lower_bound(x);
	s.erase(lowIt, s.end());

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}

(2)upper_bound 返回>x位置的迭代器

返回>x位置的迭代器,s.upper_bound(5) 存在5,不存在6,则返回7;s.upper_bound(6) 不存在6,返回7;

    set<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(7);
	s.insert(9);

	返回>x位置的迭代器  -》 都是返回 7位置的迭代器
	set<int>::iterator upIt = s.upper_bound(5);  // 存在
	upIt = s.upper_bound(6); // 不存在

用途:例如 删除x <=  <= y的区间 删除 [x,y]

void test_set4()
{
	set<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(7);
	s.insert(8);

	// 返回>= val得位置迭代器  3返回3位置  6 返回7位置
	/*set<int>::iterator lowIt = s.lower_bound(3); 存在
	lowIt = s.lower_bound(6); 不存在*/
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	// 删除x <=  <= y的区间 删除 [x,y]
	int x, y;
	cin >> x >> y;
	auto leftIt = s.lower_bound(x);  // [
	auto rightIt = s.upper_bound(y); // )
	s.erase(leftIt, rightIt);
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}

8. std::multiset 跟set接口一样,只是允许冗余,不去重

插入重复的数时set会去重,multiset不去重,允许冗余

不同:

multiset 的count和erase 返回查找或删除个数

find(x) 多个x的话,find返回中序第一个x

void test_set6()
{
	multiset<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(2);
	s.insert(1);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(1);
	s.insert(3);
	s.insert(3);
	s.insert(3);
	s.insert(3);

	// 排序 
	set<int>::iterator it = s.begin();    //迭代器打印
	while (it != s.end())
	{
		//*it = 10;
		cout << *it << " ";
		++it;
	}
	cout << endl;

	for (auto e : s)        //范围for打印
	{
		cout << e << " ";
	}
	cout << endl;

	cout << s.count(1) << endl;    //测试count,打印3,因为1有3个
	cout << s.erase(1) << endl;    //测试erase,打印3,因为1有3个
	for (auto e : s)    
	{
		cout << e << " ";
	}
	cout << endl;
                           
	auto pos = s.find(3);         // 多个x的话,find返回中序第一个x
	while (pos != s.end())        //从中序第一个3开始打印完整个
	{
		cout << *pos << " ";
		++pos;
	}
	cout << endl;
}

 

9.set相关题目

349. 两个数组的交集

方法一:把nums1和nums2分别放进s1和s2中进行去重,再利用范围for把s2中的每个元素在s1中进行查找,如果找到就放进v中。时间复杂度是:O(n*logn) n个节点,每个节点找logn高度次

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        //去重
        set<int> s1;
        for(auto e:nums1)
        {
            s1.insert(e);
        }
        //去重
        set<int> s2;
        for(auto e:nums2)
        {
            s2.insert(e);
        }
        vector<int> v;
        for(auto e:s2)
        {
            if(s1.count(e))
            {
                v.push_back(e);
            }
        }
        return v;
    }
};

方法二:

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        set<int> s1;
        for(auto e:nums1)
        {
            s1.insert(e);
        }

        set<int> s2;
        for(auto e:nums2)
        {
            s2.insert(e);
        }
        vector<int> v;
        set<int>::iterator it1=s1.begin();
        set<int>::iterator it2=s2.begin();
        while(it1!=s1.end() && it2!=s2.end())
        {
            if(*it1>*it2)    //相比较,值小的++
            {
                ++it2;
            }
            else if(*it1<*it2)    //相比较,值小的++
            {
                ++it1;
            }
            else                //相比较,值相等就放进v中,同时++
            {
                v.push_back(*it1);
                ++it1;
                ++it2;
            }
        }
        return v;
    }
};

二.map用法介绍

map是KV模型的搜索二叉树,insert和[]用法是重点,其他用法参考set        #include<map>

几个map和set的冷知识:

map:

①map是C++98中已存在的,unordered_map是C++11中才有的

②map中都重载了[]运算符,multimap中没有重载[]运算符,set也没有重载[]。

原因:map中key是唯一的,每个key都有与之对应的value,经常需要通过key获取value,因此 map为了形象简单 就重载了[]运算符, multimap中key是可以重复的,如果重载了[]运算符,给定 一个key时,就没有办法返回     value了,因此,multimap中没有重载[]运算符

③map中key不能修改,因为如果修改了就不能保证红黑树的有序特性了

set:

①set中也可以存储键值对,实例化set时,将set中元素类型设置为pair即可

②set默认是升序,但是其内部默认不是按照大于比较,而是按照 less小于比较

less是把小的放左边,所以是升序;greater是把大的放左边,所以是降序

map和set查询的时间复杂度都是O(log_2N)

解释:map和set的底层结构都是红黑树,而红黑树是近似的平衡二叉搜索树,故查询时间 复杂度为O(log_2N)

map和set底层都是使用红黑树实现的

1.pair和make_pair

(1)pair键值对 的介绍

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代
表键值,value表示与key对应的信息。比如:现在要建立一个英汉互译的字典,那该字典中必然
有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应
该单词,在词典中就可以找到与其对应的中文含义。

pair 打包了KV模型的key和val两个类型的值,c++不支持返回两个值,也就不知道返回key和val哪一个了,所以干脆打包key和val,返回一个pair结构

(value_type 是 pair<const key_type,mapped_type>)

pair中的first就相当于KV模型中的key,second相当于KV模型中的val

(2)make_pair 介绍

make_pair 相当于返回了一个pair的匿名对象

2.map的遍历

(1)英汉字典的遍历

几种插入英汉字典的方式:匿名对象插入,普通对象插入,make_pair插入

void test_map1()
{
	map<string, string> dict;

	// pair构造函数
	dict.insert(pair<string, string>("sort", "排序")); //匿名对象插入更便捷
	pair<string, string> kv("insert", "插入");    //普通对象插入
	dict.insert(kv);

	// make_pair
	auto ret1 = dict.insert(make_pair("left", "左边"));  //make_pair插入
	auto ret2 = dict.insert(make_pair("left", "剩余"));
	// 遍历
//map<string, string>::iterator it = dict.begin();
	auto it = dict.begin();
	while (it != dict.end())
	{
		//cout << *it << " "; // it->operator*()
		//cout << (*it).first << ":" << (*it).second << endl;
		cout << it->first << ":" << it->second << endl;
		++it;
	}
	cout << endl;

	for (const auto& kv : dict)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
}

int main()
{
	test_map1();
	return 0;
}

(2)记录水果次数

void test_map2()
{
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
	map<string, int> countMap;
	for (auto& str : arr)
	{
		map<string, int>::iterator it = countMap.find(str);	
		if (it != countMap.end())	//如果countMap中有,就计数加1
		{
			it->second++;
		}
		else
		{
			countMap.insert(make_pair(str, 1));	//没有就插入水果
		}
	}
	for (auto& str : arr)
	{
		countMap[str]++;
	}
	for (const auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
}

3.insert写法提高 记录水果次数 的效率(不这么写,只是为[]做铺垫)

map的insert默认是按照pair中的first进行排序的

 

    string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
	map<string, int> countMap;
	for (auto& str : arr)
	{
pair<map<string, int>::iterator, bool> ret = countMap.insert(make_pair(str, 1));
		//或者 auto ret = countMap.insert(make_pair(str, 1));
		if (ret.second == false)
		{
			ret.first->second++;
		}
	}
	for (const auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}

解释:

pair<map<string, int>::iterator, bool>  ret = countMap.insert(make_pair(str, 1)) 插入节点,若插入成功,ret.first这个iterator 存的是新插入节点的迭代器,ret.second 存的是true;若插入失败,ret.first这个iterator 存的是已有的相同节点的迭代器,ret.second 存的是false;插入失败就再记录个数++就行,ret.first->second++; 用于访问记录水果个数,ret.first 是节点迭代器,ret.first->second++; 节点中的second用于记录对应水果的个数

4.operator[] 运算符重载 

(1) 提高 记录水果次数 的效率的真正写法:

void test_map2()
{
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
	map<string, int> countMap;
	for (auto& str : arr)
	{
		countMap[str]++;
	}

	for (const auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
}

 

 解释:

 countMap[str]++; 中 countMap[str] 返回的是新插入节点中的 次数second 。

如果插入的str不在 对象countMap中,countMap[str]++; 就是插入这个节点,迭代器就是新节点的迭代器,看原码可知 int类型的次数second用的是缺省值(对应原码中的mapped_typed(),是缺省值 ),所以开始second就是0,++后就是1。作用就是插入并修改val (val意思就是second)。

如果插入的str在 对象countMap中,countMap[str]++; 就是查找到这个节点,迭代器就是已有节点的迭代器,int类型的次数second在第一次已经是1了,++后就是2。作用就是插入并修改val (val意思就是second,用于计水果次数)。

(2) 字典中利用[]插入或修改 示例

void test_map1()
{
	map<string, string> dict;

	// pair构造函数
	dict.insert(pair<string, string>("sort", "排序"));
	pair<string, string> kv("insert", "插入");
	dict.insert(kv);

	// make_pair
	auto ret1 = dict.insert(make_pair("left", "左边"));
	auto ret2 = dict.insert(make_pair("left", "剩余"));

	dict["operator"] = "重载"; // 插入+修改
	dict["left"] = "左边、剩余"; // 修改
	dict["erase"];  // 插入
	cout << dict["left"] << endl; // 查找
}

5.multimap 允许键值冗余

相比map,multimap使用函数接口最大的区别是什么?
答:不支持operator[] 。

三.相关题目

1.692. 前K个高频单词

(1)做法一:stable_sort稳定排序

把map中的pair放到v中再用stable_sort稳定排序,再把各个pair对应的first放到vv中,再输出vv

class Solution {
public:
    typedef map<string,int>::iterator CountIter;
    struct less
    {
        bool operator()(const pair<string,int>& x,const pair<string,int>& y)
        {
            return x.second>y.second;
        }
    };

    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int> countMap;
        for(auto& str:words)
        {
           countMap[str]++;
        }

        vector<pair<string,int>> v;
        CountIter it=countMap.begin();
        while(it!=countMap.end())
        {
            //cout<<it->first<<" "<<it->second<<endl;
            v.push_back(*it);
            ++it;
        }

        stable_sort(v.begin(),v.end(),less());  //stable_sort稳定排序
        vector<string> vv;
        for(int i=0;i<k;i++)
        {
            vv.push_back(v[i].first);
        }
        for(auto e:v)
        {
            cout<<e.first<<" "<<e.second<<endl;
        }
        return vv;
    }
};

(2)做法二:stable_sort稳定排序 2

与做法一不同的是:pair很大,为了减少拷贝,我们可以选择不拷贝pair而是拷贝迭代器,把map中的迭代器放到v中,比较方法中通过迭代器找到second,再用stable_sort稳定排序这些迭代器,再把各个迭代器对应的first放到vv中,再输出vv

自己敲的:

class Solution {
public:
    typedef map<string,int>::iterator CountIter;
    struct less //降序
    {
        bool operator()(const CountIter& x,const CountIter& y)
        {
            return x->second > y->second;
        }
    };
    
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int> countMap;
        for(auto& str:words)
        {
           countMap[str]++;
        }

        vector<CountIter> v;
        CountIter it=countMap.begin();
        while(it!=countMap.end())
        {
            //cout<<it->first<<" "<<it->second<<endl;
            v.push_back(it);
            ++it;
        }

        stable_sort(v.begin(),v.end(),less());  //stable_sort稳定排序
        for(auto e:v)
        {
            cout<<e->first<<" "<<e->second<<endl;
        }
        vector<string> vv;
        for(int i=0;i<k;i++)
        {
            vv.push_back(v[i]->first);
        }
        
        return vv;
    }
};

(3)做法三:sort 非稳定排序,可以控制比较方法使其稳定

相比较上面的方法,把stable_sort换成sort后,只需要控制比较方法即可使其稳定:因为map中默认是按照分first小的在前排序的,sort 时我们设计的比较方法是按second排序的,但是当second相等时,sort有可能打乱之前map中按 first 排的先后顺序,这样就是不稳定。我们只需要比较方法中让second相等时的情况再按first小的在前排好就可以达到稳定的目的。(相等时会多比一下first,会影响一点效率)

自己敲的:

 (4)做法四:利用map自身按照first排序

map的insert默认是按照pair中的first进行排序的,因此我们可以创建一个sortMap,int对应first,string对应second,然后一个一个从kv中插入进sortMap(kv中的first和second颠倒一下插入进去),因为map默认去掉重复的first,这样会导致把次数重复的元素去掉(因为次数放在了first位置),因此要用允许重复的multimap,插入顺序map默认是less降序,因为是top-k问题,我们要把map中插入顺序改成升序插入greater<int>。

class Solution {
public:
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int> countMap;
        for(auto& str:words)
        {
           countMap[str]++;
        }
        //排序
        multimap<int,string,greater<int>> sortMap;
        for(auto& kv:countMap)
        {
            sortMap.insert(make_pair(kv.second,kv.first));
        }
        // auto it=sortMap.begin();  
        // while(it!=sortMap.end())
        // {
        //     cout<<it->first<<" "<<it->second<<endl;
        //     ++it;
        // }
        vector<string> vv;
        auto it=sortMap.begin();
        for(int i=0;i<k;i++)
        {
            vv.push_back(it->second);
            ++it;
        }
        
        return vv;
    }
};

官方写法:

四.用红黑树模拟实现map,set

重点:

struct SetKeyOfT 仿函数,用于在RBTree.h找到map/set中所要比较的值,用于控制RBTree.h中pair类型的比较方法,因为库中的pair类型 先比first再比second 的比较方法不是我们想要的

Map.h

#pragma once
#include "RBTree.h"

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

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

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

		pair<iterator, bool> insert(const pair<K, V>& kv)
		{
			return _t.Insert(kv);
		}

		iterator find(const K& key)
		{
			return _t.Find(key);
		}

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

	private:
		RBTree<K, pair<K, V>, MapKeyOfT> _t;
	};

	void test_map1()
	{
		map<string, int> m;
		m.insert(make_pair("111", 1));
		m.insert(make_pair("555", 5));
		m.insert(make_pair("333", 3));
		m.insert(make_pair("222", 2));

		map<string, int>::iterator it = m.begin();
		while (it != m.end())
		{
			cout << it->first << ":" << it->second << endl;
			++it;
		}
		cout << endl;

		for (auto& kv : m)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
		cout << endl;
	}

	void test_map2()
	{
		string arr[] = { "ƻ", "", "ƻ", "", "ƻ", "ƻ", "", "ƻ", "㽶", "ƻ", "㽶" };

		map<string, int> countMap;
		for (auto& str : arr)
		{
			countMap[str]++;
		}

		for (const auto& kv : countMap)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
	}

	void test_map3()
	{
		map<string, string> dict;
		dict["insert"];
		dict["insert"] = "";
		dict["left"] = "";

	}
}

Set.h

#pragma once

#include "RBTree.h"

namespace bit
{
	template<class K>
	class set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;

		iterator begin() const    //set内容不想被修改(key值不修改),则给this设置const,
		{                          //调用时会调用带const的Begin()
			return _t.Begin();
		}

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

		pair<iterator, bool> insert(const K& key)
		{
			//pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(key);
			auto ret = _t.Insert(key);
			return pair<iterator, bool>(iterator(ret.first._node), ret.second);
		}

		iterator find(const K& key)
		{
			return _t.Find(key);
		}
	private:
		RBTree<K, K, SetKeyOfT> _t;
	};

	void test_set1()
	{
		set<int> s;
		s.insert(8);
		s.insert(6);
		s.insert(11);
		s.insert(5);
		s.insert(6);
		s.insert(7);
		s.insert(10);
		s.insert(13);
		s.insert(12);
		s.insert(15);

		set<int>::iterator it = s.begin();
		while (it != s.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;

		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}

RBTree.h

pragma once

enum Colour
{
	RED,
	BLACK,
};

template<class T>
struct RBTreeNode
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	T _data; // 数据

	Colour _col;

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

template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef __RBTreeIterator<T, Ref, Ptr> Self;
	Node* _node;

	__RBTreeIterator(Node* node)
		:_node(node)
	{}

	Ref operator*()
	{
		return _node->_data;
	}

	Ptr operator->()
	{
		return &_node->_data;
	}
	// 休息17:00
	Self& operator++() //中序遍历
	{
		if (_node->_right == nullptr) //当前节点的右节点为空
		{
			// 就找祖先里面,孩子是父亲左的那个父亲
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && parent->_right == cur)
			{    //只要这个父亲的孩子不是父亲的左,就继续往上找
				cur = cur->_parent;
				parent = parent->_parent;
			}
            //直到这个父亲的孩子是父亲的左,这个父亲就是该++走到的节点
			_node = parent;
		}
		else    //当前节点的右节点不为空
		{
			// 就走完右子树的最左节点
			Node* subLeft = _node->_right;
			while (subLeft->_left)
			{
				subLeft = subLeft->_left;
			}

			_node = subLeft;
		}
		
		return *this;
	}

	Self operator++(int)
	{
		Self tmp(*this);
		
		++(*this);

		return tmp;
	}

	Self& operator--()
	{
		if (_node->_left == nullptr)
		{
			// 找祖先里面,孩子是父亲
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_left)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}

			_node = parent;
		}
		else
		{
			// 左子树的最右节点
			Node* subRight = _node->_left;
			while (subRight->_right)
			{
				subRight = subRight->_right;
			}

			_node = subRight;
		}

		return *this;
	}

	Self operator--(int)
	{
		Self tmp(*this);

		--(*this);

		return tmp;
	}

	bool operator!=(const Self& s) const
	{
		return _node != s._node;
	}

	bool operator==(const Self& s) const
	{
		return _node == s->_node;
	}
};

// T决定红黑树存什么数据
// set  RBTree<K, K>
// map  RBTree<K, pair<K, V>>
// KeyOfT -> 支持取出T对象中key的仿函数
template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	typedef __RBTreeIterator<T, T&, T*> iterator;
	typedef __RBTreeIterator<T, const T&, const T*> const_iterator;

	// 构造 拷贝构造 赋值 和析构 跟搜索树实现方式是一样的

	iterator Begin()
	{
		Node* subLeft = _root;
		while (subLeft && subLeft->_left)
		{
			subLeft = subLeft->_left;
		}

		return iterator(subLeft);
	}

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

	const_iterator Begin() const
	{
		Node* subLeft = _root;
		while (subLeft && subLeft->_left)
		{
			subLeft = subLeft->_left;
		}

		return const_iterator(subLeft);
	}

	const_iterator End() const
	{
		return const_iterator(nullptr);
	}

	pair<iterator, bool> Insert(const T& data)
	{
		// 1、搜索树的规则插入
		// 2、看是否违反平衡规则,如果违反就需要处理:旋转
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;
			return make_pair(iterator(_root), true);
		}

		KeyOfT kot;

		Node* parent = nullptr;
		Node* cur = _root;
		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), true);
			}
		}

		cur = new Node(data);
		Node* newnode = cur;
		cur->_col = RED;  
		if (kot(parent->_data) < kot(data))
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}

		cur->_parent = parent;

		// 存在连续红色节点
		while (parent && parent->_col == RED)
		{
			Node* grandfater = parent->_parent;
			assert(grandfater);

			if (grandfater->_left == parent)
			{
				Node* uncle = grandfater->_right;
				// 情况一:
				if (uncle && uncle->_col == RED) // 叔叔存在且为红
				{
					// 变色
					parent->_col = uncle->_col = BLACK;
					grandfater->_col = RED;

					// 继续往上处理
					cur = grandfater;
					parent = cur->_parent;
				}
				else // 叔叔不存在 或者 叔叔存在且为黑
				{
					if (cur == parent->_left) // 单旋
					{
						//     g
						//   p
						// c
						RotateR(grandfater);
						parent->_col = BLACK;
						grandfater->_col = RED;
					}
					else // 双旋
					{
						//     g
						//   p
						//     c 
						RotateL(parent);
						RotateR(grandfater);
						cur->_col = BLACK;
						grandfater->_col = RED;
					}

					break;
				}
			}
			else //(grandfater->_right == parent)
			{
				Node* uncle = grandfater->_left;
				// 情况一:
				if (uncle && uncle->_col == RED)
				{
					// 变色
					parent->_col = uncle->_col = BLACK;
					grandfater->_col = RED;

					// 继续往上处理
					cur = grandfater;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_right)
					{
						// g
						//   p
						//     c 
						RotateL(grandfater);
						parent->_col = BLACK;
						grandfater->_col = RED;
					}
					else // 双旋
					{
						// g
						//   p
						// c
						RotateR(parent);
						RotateL(grandfater);
						cur->_col = BLACK;
						grandfater->_col = RED;
					}

					break;
				}
			}
		}

		_root->_col = BLACK;

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

	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 (parent == _root)
		{
			_root = subR;
			_root->_parent = nullptr;
		}
		else
		{
			if (parent == ppNode->_left)
			{
				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 (parent == _root)
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subL;
			}
			else
			{
				ppNode->_right = subL;
			}
			subL->_parent = ppNode;
		}
	}

	iterator Find(const K& key)
	{
		Node* cur = _root;
		KeyOfT kot;
		while (cur)
		{
			if (kot(cur->_data) < key)
			{
				cur = cur->_right;
			}
			else if (kot(cur->_data) > key)
			{
				cur = cur->_left;
			}
			else
			{
				return iterator(cur);
			}
		}

		return End();
	}

private:
	Node* _root = nullptr;
};

猜你喜欢

转载自blog.csdn.net/zhang_si_hang/article/details/126398107