博客 https://blog.lenyiin.com/set-map/ 的代码仓库
This commit is contained in:
commit
7abc18bfce
370
Linux/Main.cc
Normal file
370
Linux/Main.cc
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <set>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "Set.hpp"
|
||||||
|
#include "Map.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Lenyiin;
|
||||||
|
|
||||||
|
// 序列式容器: vector/list/string/deque/array/forward_list
|
||||||
|
// 关联式容器: set/multiset/map/multimap/unordered_set/unordered_multiset/unordered_map/unordered_multimap
|
||||||
|
|
||||||
|
void test_set()
|
||||||
|
{
|
||||||
|
set<int> s1; // set默认排序为从小到大 set底层是搜索树
|
||||||
|
s1.insert(10);
|
||||||
|
s1.insert(20);
|
||||||
|
s1.insert(5);
|
||||||
|
s1.insert(2);
|
||||||
|
s1.insert(1);
|
||||||
|
s1.insert(8);
|
||||||
|
s1.insert(14);
|
||||||
|
s1.insert(44);
|
||||||
|
s1.insert(23);
|
||||||
|
s1.insert(0);
|
||||||
|
s1.insert(2);
|
||||||
|
s1.insert(1);
|
||||||
|
s1.insert(8);
|
||||||
|
s1.insert(14);
|
||||||
|
|
||||||
|
// 排序 + 去重
|
||||||
|
set<int>::iterator it = s1.begin();
|
||||||
|
while (it != s1.end())
|
||||||
|
{
|
||||||
|
//*it = 100; // set中的元素是只读的,不能修改
|
||||||
|
cout << *it << " ";
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 范围for
|
||||||
|
for (auto e : s1)
|
||||||
|
{
|
||||||
|
cout << e << " ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 拷贝构造 底层默认是一个深拷贝
|
||||||
|
set<int> s2(s1);
|
||||||
|
for (auto e : s2)
|
||||||
|
{
|
||||||
|
cout << e << " ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
// find()是成员函数,只能用于set/multiset/map/multimap
|
||||||
|
// set<int>::iterator pos = s2.find(5);
|
||||||
|
auto pos = s2.find(5);
|
||||||
|
|
||||||
|
// find()是泛型算法,可以用于所有容器
|
||||||
|
// s.find() O(logN) s.begin() O(1) s.end() O(1)
|
||||||
|
// find(s.begin(), s.end(), 5) O(N) 效率会低不少
|
||||||
|
// auto pos = find(s2.begin(), s2.end(), 5);
|
||||||
|
|
||||||
|
if (pos != s2.end())
|
||||||
|
{
|
||||||
|
s2.erase(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto e : s2)
|
||||||
|
{
|
||||||
|
cout << e << " ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 或者直接删
|
||||||
|
s2.erase(8);
|
||||||
|
s2.erase(80); // 和迭代器的区别在于:删除不存在的元素,不会报错
|
||||||
|
for (auto e : s2)
|
||||||
|
{
|
||||||
|
cout << e << " ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_map1()
|
||||||
|
{
|
||||||
|
map<int, int> m1;
|
||||||
|
m1.insert(pair<int, int>(1, 1)); // pair是一个模板类,可以用来创建pair对象
|
||||||
|
m1.insert(pair<int, int>(3, 3));
|
||||||
|
m1.insert(pair<int, int>(2, 2));
|
||||||
|
m1.insert(pair<int, int>(5, 5));
|
||||||
|
m1.insert(pair<int, int>(6, 6));
|
||||||
|
m1.insert(pair<int, int>(4, 4)); // pair构造函数,构造一个匿名对象,然后插入到map中
|
||||||
|
|
||||||
|
// 日常大家喜欢用make_pair()来构造pair对象,因为他不用声明模板参数,编译器自动推
|
||||||
|
m1.insert(make_pair(7, 7)); // 函数模板构造一个pair对象
|
||||||
|
|
||||||
|
map<int, int>::iterator it = m1.begin();
|
||||||
|
while (it != m1.end())
|
||||||
|
{
|
||||||
|
// cout << *it << " "; // C++不支持返回两个数
|
||||||
|
cout << (*it).first << " " << (*it).second << endl; // operator*()返回的是节点中值的引用
|
||||||
|
cout << it->first << " " << it->second << endl; // operator->()返回的是节点的指针 也就是pair<k, v>的指针
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 范围for
|
||||||
|
for (auto &e : m1)
|
||||||
|
{
|
||||||
|
cout << e.first << " " << e.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_map2()
|
||||||
|
{
|
||||||
|
std::map<std::string, std::string> dirt;
|
||||||
|
dirt.insert(pair<std::string, std::string>("sort", "排序"));
|
||||||
|
dirt.insert(make_pair("string", "字符串"));
|
||||||
|
dirt.insert(make_pair("left", "左边")); // 按照ASCII码排序
|
||||||
|
|
||||||
|
std::map<std::string, std::string>::iterator it = dirt.begin();
|
||||||
|
while (it != dirt.end())
|
||||||
|
{
|
||||||
|
cout << it->first << " " << it->second << endl;
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_map3()
|
||||||
|
{
|
||||||
|
// 统计单词出现的次数
|
||||||
|
string strArr[] = {"西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果",
|
||||||
|
"西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉",
|
||||||
|
"西瓜", "樱桃", "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果",
|
||||||
|
"西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉"};
|
||||||
|
map<string, int> countMap;
|
||||||
|
|
||||||
|
// 第一种方法
|
||||||
|
for (auto &str : strArr)
|
||||||
|
{
|
||||||
|
map<string, int>::iterator pos = countMap.find(str);
|
||||||
|
if (pos != countMap.end())
|
||||||
|
{
|
||||||
|
pos->second++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
countMap.insert(make_pair(str, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &e : countMap)
|
||||||
|
{
|
||||||
|
cout << e.first << " " << e.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 第二种方法
|
||||||
|
for (auto &str : strArr)
|
||||||
|
{
|
||||||
|
pair<map<string, int>::iterator, bool> ret = countMap.insert(make_pair(str, 1));
|
||||||
|
if (ret.second == false) // 插入失败,说明已经存在
|
||||||
|
{
|
||||||
|
ret.first->second++; // 迭代器指向的是插入的元素
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &e : countMap)
|
||||||
|
{
|
||||||
|
cout << e.first << " " << e.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 第三种方法
|
||||||
|
for (auto &str : strArr)
|
||||||
|
{
|
||||||
|
// 1、如果水果不在map中,则[]会插入pair<str, 0>, 返回映射对象(次数)的引用进行++
|
||||||
|
// 2、如果水果在map中,则[]会返回水果对应的映射对象(次数)的引用,对它进行++
|
||||||
|
countMap[str]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
countMap["葡萄"]; // 插入 一般不这么用
|
||||||
|
countMap["葡萄"] = 100; // 修改
|
||||||
|
cout << countMap["葡萄"] << endl; // 查找
|
||||||
|
countMap["哈密瓜"] = 5; // 插入 + 修改
|
||||||
|
|
||||||
|
// 一般使用operator[]去
|
||||||
|
// 1、插入 + 修改
|
||||||
|
// 2、修改
|
||||||
|
// 一般不会用他去做查找,因为如果key不在,会插入数据。
|
||||||
|
|
||||||
|
for (auto &e : countMap)
|
||||||
|
{
|
||||||
|
cout << e.first << " " << e.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_multi()
|
||||||
|
{
|
||||||
|
// multiset根set的区别就是允许键值冗余
|
||||||
|
multiset<int> s1; // 使用和set一样,只是multiset可以存放重复的元素
|
||||||
|
s1.insert(10);
|
||||||
|
s1.insert(20);
|
||||||
|
s1.insert(5);
|
||||||
|
s1.insert(2);
|
||||||
|
s1.insert(1);
|
||||||
|
s1.insert(8);
|
||||||
|
s1.insert(8);
|
||||||
|
s1.insert(14);
|
||||||
|
s1.insert(44);
|
||||||
|
s1.insert(23);
|
||||||
|
s1.insert(0);
|
||||||
|
s1.insert(2);
|
||||||
|
s1.insert(1);
|
||||||
|
s1.insert(8);
|
||||||
|
s1.insert(8);
|
||||||
|
s1.insert(14);
|
||||||
|
|
||||||
|
for (auto e : s1)
|
||||||
|
{
|
||||||
|
cout << e << " ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
auto pos = s1.find(8); // 查找到的是重复元素的第一个元素地址
|
||||||
|
cout << *pos << endl;
|
||||||
|
pos++;
|
||||||
|
cout << *pos << endl;
|
||||||
|
pos++;
|
||||||
|
cout << *pos << endl;
|
||||||
|
pos++;
|
||||||
|
cout << *pos << endl;
|
||||||
|
pos++;
|
||||||
|
cout << *pos << endl;
|
||||||
|
|
||||||
|
// multimap和map的区别和上面是一样的
|
||||||
|
multimap<string, int> mm;
|
||||||
|
mm.insert(make_pair("苹果", 1));
|
||||||
|
mm.insert(make_pair("苹果", 1));
|
||||||
|
mm.insert(make_pair("苹果", 3));
|
||||||
|
mm.insert(make_pair("西瓜", 2));
|
||||||
|
mm.insert(make_pair("西瓜", 1));
|
||||||
|
|
||||||
|
for (auto &e : mm)
|
||||||
|
{
|
||||||
|
cout << e.first << " " << e.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自己实现的 Set Map 测试
|
||||||
|
void test_Set()
|
||||||
|
{
|
||||||
|
Set<int> s;
|
||||||
|
s.Insert(3);
|
||||||
|
s.Insert(4);
|
||||||
|
s.Insert(1);
|
||||||
|
s.Insert(2);
|
||||||
|
s.Insert(2);
|
||||||
|
s.Insert(5);
|
||||||
|
|
||||||
|
// 迭代器遍历
|
||||||
|
Set<int>::iterator it = s.begin();
|
||||||
|
while (it != s.end())
|
||||||
|
{
|
||||||
|
cout << *it << " ";
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
s.Erase(4);
|
||||||
|
|
||||||
|
// for
|
||||||
|
for (const auto &k : s)
|
||||||
|
{
|
||||||
|
cout << k << " ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
cout << "IsRBTree? " << (s.IsRBTree() ? "true" : "false") << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Map1()
|
||||||
|
{
|
||||||
|
// int a[] = {16, 3, 7, 11, 9, 26, 18, 14, 15};
|
||||||
|
int a[] = {4, 2, 6, 1, 3, 5, 15, 7, 16, 14};
|
||||||
|
Map<int, int> m;
|
||||||
|
for (const auto &e : a)
|
||||||
|
{
|
||||||
|
m.Insert(make_pair(e, e));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 迭代器遍历
|
||||||
|
Map<int, int>::iterator it = m.begin();
|
||||||
|
while (it != m.end())
|
||||||
|
{
|
||||||
|
cout << it->first << ":" << it->second << endl;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
m.Erase(4);
|
||||||
|
|
||||||
|
// 范围for遍历 for_each 底层也是调用的迭代器实现的遍历
|
||||||
|
for (const auto &kv : m)
|
||||||
|
{
|
||||||
|
cout << kv.first << ":" << kv.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
cout << "IsRBTree? " << (m.IsRBTree() ? "true" : "false") << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Map2()
|
||||||
|
{
|
||||||
|
// 统计单词出现的次数
|
||||||
|
string strArr[] = {"西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果",
|
||||||
|
"西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉",
|
||||||
|
"西瓜", "樱桃", "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果",
|
||||||
|
"西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉"};
|
||||||
|
Map<string, int> countMap;
|
||||||
|
for (auto &str : strArr)
|
||||||
|
{
|
||||||
|
countMap[str]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 迭代器遍历
|
||||||
|
Map<string, int>::iterator it = countMap.begin();
|
||||||
|
while (it != countMap.end())
|
||||||
|
{
|
||||||
|
cout << it->first << ":" << it->second << endl;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
countMap.Erase("苹果");
|
||||||
|
|
||||||
|
for (const auto &kv : countMap)
|
||||||
|
{
|
||||||
|
cout << kv.first << ":" << kv.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
cout << "IsRBTree? " << (countMap.IsRBTree() ? "true" : "false") << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// test_set();
|
||||||
|
// test_map1();
|
||||||
|
// test_map2();
|
||||||
|
// test_map3();
|
||||||
|
// test_multi();
|
||||||
|
|
||||||
|
test_Set();
|
||||||
|
test_Map1();
|
||||||
|
test_Map2();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
6
Linux/Makefile
Normal file
6
Linux/Makefile
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
main:Main.cc
|
||||||
|
g++ -o $@ $^
|
||||||
|
|
||||||
|
.PHONY:clean
|
||||||
|
clean:
|
||||||
|
rm -f main
|
66
Linux/Map.hpp
Normal file
66
Linux/Map.hpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RBTree.hpp"
|
||||||
|
|
||||||
|
namespace Lenyiin
|
||||||
|
{
|
||||||
|
template <class K, class V>
|
||||||
|
class Map
|
||||||
|
{
|
||||||
|
struct MapKeyOfT
|
||||||
|
{
|
||||||
|
const K &operator()(const std::pair<K, V> &kv)
|
||||||
|
{
|
||||||
|
return kv.first;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename RBTree<K, std::pair<K, V>, MapKeyOfT>::iterator iterator;
|
||||||
|
typedef typename RBTree<K, std::pair<K, V>, MapKeyOfT>::const_iterator const_iterator;
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return _tree.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return _tree.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
return _tree.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return _tree.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, bool> Insert(const std::pair<K, V> &kv)
|
||||||
|
{
|
||||||
|
return _tree.Insert(kv);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Erase(const K &key)
|
||||||
|
{
|
||||||
|
return _tree.Erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
V &operator[](const K &key)
|
||||||
|
{
|
||||||
|
std::pair<iterator, bool> ret = _tree.Insert(std::make_pair(key, V()));
|
||||||
|
return ret.first->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsRBTree()
|
||||||
|
{
|
||||||
|
return _tree.IsRBTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RBTree<K, std::pair<K, V>, MapKeyOfT> _tree;
|
||||||
|
};
|
||||||
|
}
|
740
Linux/RBTree.hpp
Normal file
740
Linux/RBTree.hpp
Normal file
@ -0,0 +1,740 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace Lenyiin
|
||||||
|
{
|
||||||
|
enum Colour
|
||||||
|
{
|
||||||
|
RED,
|
||||||
|
BLACK
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct RBTreeNode
|
||||||
|
{
|
||||||
|
RBTreeNode<T> *_left; // 左子节点
|
||||||
|
RBTreeNode<T> *_right; // 右子节点
|
||||||
|
RBTreeNode<T> *_parent; // 父节点
|
||||||
|
|
||||||
|
T _data; // 节点存储的数据
|
||||||
|
Colour _colour; // 节点的颜色(红色或黑色)
|
||||||
|
|
||||||
|
// 节点的构造函数,默认为红色节点
|
||||||
|
RBTreeNode(const T &data)
|
||||||
|
: _left(nullptr), _right(nullptr), _parent(nullptr), _data(data), _colour(RED)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, class Ref, class Ptr>
|
||||||
|
struct __TreeIterator
|
||||||
|
{
|
||||||
|
typedef RBTreeNode<T> Node;
|
||||||
|
typedef __TreeIterator<T, Ref, Ptr> Self;
|
||||||
|
Node *_node; // 当前迭代器指向的节点
|
||||||
|
|
||||||
|
// 构造函数
|
||||||
|
__TreeIterator(Node *node)
|
||||||
|
: _node(node)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解引用操作符
|
||||||
|
Ref operator*()
|
||||||
|
{
|
||||||
|
return _node->_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 访问成员操作符
|
||||||
|
Ptr operator->()
|
||||||
|
{
|
||||||
|
return &_node->_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 前置递增运算符
|
||||||
|
Self &operator++()
|
||||||
|
{
|
||||||
|
// 1. 如果右不为空, 中序的下一个就是右子树的最左节点
|
||||||
|
if (_node->_right)
|
||||||
|
{
|
||||||
|
Node *subLeft = _node->_right;
|
||||||
|
while (subLeft->_left)
|
||||||
|
{
|
||||||
|
subLeft = subLeft->_left;
|
||||||
|
}
|
||||||
|
_node = subLeft;
|
||||||
|
}
|
||||||
|
// 2. 如果右为空, 表示 _node 所在的子树已经完成, 下一个节点在他祖先中去找, 沿着路径往上找孩子使它的左的那个祖先
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Node *cur = _node;
|
||||||
|
Node *parent = cur->_parent;
|
||||||
|
while (parent && cur == parent->_right)
|
||||||
|
{
|
||||||
|
cur = parent;
|
||||||
|
parent = cur->_parent;
|
||||||
|
}
|
||||||
|
_node = parent;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 后置递增运算符
|
||||||
|
Self operator++(int)
|
||||||
|
{
|
||||||
|
Node *tmp = _node;
|
||||||
|
++(*this);
|
||||||
|
return Self(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 前置递减运算符
|
||||||
|
Self &operator--()
|
||||||
|
{
|
||||||
|
// 1. 如果左不为空, 中序的上一个就是左树的最右节点
|
||||||
|
if (_node->_left)
|
||||||
|
{
|
||||||
|
Node *subRight = _node->left;
|
||||||
|
while (subRight->_right)
|
||||||
|
{
|
||||||
|
subRight = subRight->_right;
|
||||||
|
}
|
||||||
|
_node = subRight;
|
||||||
|
}
|
||||||
|
// 2. 如果左为空, 表示 _node 所在的子树已经完成, 上一个节点在他祖先中去找, 沿着路径往上找孩子是它的右的那个祖先
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Node *cur = _node;
|
||||||
|
Node *parent = cur->_parent;
|
||||||
|
while (parent && cur == parent->_left)
|
||||||
|
{
|
||||||
|
cur = parent;
|
||||||
|
parent = cur->_parent;
|
||||||
|
}
|
||||||
|
_node = parent;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 后置递减运算符
|
||||||
|
Self operator--(int)
|
||||||
|
{
|
||||||
|
Node *tmp = _node;
|
||||||
|
--(*this);
|
||||||
|
return Self(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Self &n)
|
||||||
|
{
|
||||||
|
return _node != n._node;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Self &n)
|
||||||
|
{
|
||||||
|
return _node == n._node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class K, class T, class KOfT>
|
||||||
|
class RBTree
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef RBTreeNode<T> Node;
|
||||||
|
|
||||||
|
// 左单旋
|
||||||
|
void RotateL(Node *parent)
|
||||||
|
{
|
||||||
|
Node *ppNode = parent->_parent;
|
||||||
|
Node *subR = parent->_right;
|
||||||
|
Node *subRL = subR->_left;
|
||||||
|
|
||||||
|
parent->_right = subRL;
|
||||||
|
if (subRL)
|
||||||
|
{
|
||||||
|
subRL->_parent = parent;
|
||||||
|
}
|
||||||
|
subR->_left = parent;
|
||||||
|
parent->_parent = subR;
|
||||||
|
|
||||||
|
// 1. 原来 parent 是这棵树的根, 现在 subR 是根
|
||||||
|
if (_root == parent)
|
||||||
|
{
|
||||||
|
_root = subR;
|
||||||
|
subR->_parent = nullptr;
|
||||||
|
}
|
||||||
|
// 2. parent 为根的树只是整棵树中的子树, 改变链接关系, 那么 subR 要顶替他的位置
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ppNode->_left == parent)
|
||||||
|
{
|
||||||
|
ppNode->_left = subR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ppNode->_right = subR;
|
||||||
|
}
|
||||||
|
subR->_parent = ppNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右单旋
|
||||||
|
void RotateR(Node *parent)
|
||||||
|
{
|
||||||
|
Node *ppNode = parent->_parent;
|
||||||
|
Node *subL = parent->_left;
|
||||||
|
Node *subLR = subL->_right;
|
||||||
|
|
||||||
|
parent->_left = subLR;
|
||||||
|
if (subLR)
|
||||||
|
{
|
||||||
|
subLR->_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除整个红黑树
|
||||||
|
void DeleteTree(Node *root)
|
||||||
|
{
|
||||||
|
if (root == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归删除左子树
|
||||||
|
DeleteTree(root->_left);
|
||||||
|
// 递归删除右子树
|
||||||
|
DeleteTree(root->_right);
|
||||||
|
|
||||||
|
// 删除当前节点
|
||||||
|
delete root;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef __TreeIterator<T, T &, T *> iterator;
|
||||||
|
typedef __TreeIterator<T, const T &, const T *> const_iterator;
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
Node *cur = _root;
|
||||||
|
while (cur && cur->_left)
|
||||||
|
{
|
||||||
|
cur = cur->_left;
|
||||||
|
}
|
||||||
|
return iterator(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return iterator(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
Node *cur = _root;
|
||||||
|
while (cur && cur->_left)
|
||||||
|
{
|
||||||
|
cur = cur->_left;
|
||||||
|
}
|
||||||
|
return const_iterator(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return const_iterator(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
RBTree(Node *root = nullptr)
|
||||||
|
: _root(root)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~RBTree()
|
||||||
|
{
|
||||||
|
DeleteTree(_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入
|
||||||
|
// 1. 空树。插入结点做根,把他变黑。
|
||||||
|
// 2. 插入红色节点,他的父亲是黑色的,结束。
|
||||||
|
// 3. 插入红色节点,他的父亲是红色的,可以推断他的祖父存在且一定为黑色。关键看叔叔
|
||||||
|
// a. 如果叔叔存在且为红,把父亲和叔叔变黑,祖父变红,继续往上处理。
|
||||||
|
// b. 如果叔叔存在且为黑,或者不存在。旋转(单旋 or 双旋)+ 变色
|
||||||
|
std::pair<iterator, bool> Insert(const T &data)
|
||||||
|
{
|
||||||
|
// 按照搜索树的规则进行插入
|
||||||
|
// 如果树为空,新节点直接作为根节点
|
||||||
|
if (_root == nullptr)
|
||||||
|
{
|
||||||
|
_root = new Node(data);
|
||||||
|
_root->_colour = BLACK; // 根节点是黑色的
|
||||||
|
return std::make_pair(iterator(_root), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入时使用比较器来比较键的大小,以支持不同的数据类型
|
||||||
|
KOfT koft;
|
||||||
|
Node *parent = nullptr;
|
||||||
|
Node *cur = _root;
|
||||||
|
while (cur)
|
||||||
|
{
|
||||||
|
if (koft(cur->_data) > koft(data))
|
||||||
|
{
|
||||||
|
parent = cur;
|
||||||
|
cur = cur->_left;
|
||||||
|
}
|
||||||
|
else if (koft(cur->_data) < koft(data))
|
||||||
|
{
|
||||||
|
parent = cur;
|
||||||
|
cur = cur->_right;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 如果键已经存在, 插入无效, 返回 false, 并且返回该键的迭代器
|
||||||
|
return std::make_pair(iterator(cur), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到位置, 根据父节点插入新节点
|
||||||
|
cur = new Node(data);
|
||||||
|
Node *newnode = cur;
|
||||||
|
if (koft(parent->_data) > koft(cur->_data))
|
||||||
|
{
|
||||||
|
parent->_left = cur;
|
||||||
|
cur->_parent = parent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent->_right = cur;
|
||||||
|
cur->_parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入后需要修复红黑树的性质
|
||||||
|
InsertFixUp(parent, cur);
|
||||||
|
|
||||||
|
return std::make_pair(iterator(newnode), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InsertFixUp(Node *parent, Node *cur)
|
||||||
|
{
|
||||||
|
// 调整结点颜色
|
||||||
|
// 新结点给红的还是黑的? 红色
|
||||||
|
// 1. 空树。插入结点做根, 把他变黑。
|
||||||
|
// 2. 插入红色节点, 他的父亲是黑色的, 结束。
|
||||||
|
// 3. 插入红色节点, 他的父亲是红色的, 可以推断他的祖父存在且一定为黑色。关键看叔叔
|
||||||
|
// a. 如果叔叔存在且为红, 把父亲和叔叔变黑, 祖父变红, 继续往上处理。
|
||||||
|
// b. 如果叔叔存在且为黑, 或者不存在。旋转(单旋 or 双旋)+ 变色
|
||||||
|
while (parent && parent->_colour == RED)
|
||||||
|
{
|
||||||
|
// 关键看叔叔
|
||||||
|
Node *grandfather = parent->_parent;
|
||||||
|
// 父节点是祖父节点的左子节点
|
||||||
|
if (grandfather->_left == parent)
|
||||||
|
{
|
||||||
|
Node *uncle = grandfather->_right;
|
||||||
|
|
||||||
|
// 情况1: uncle 存在, 且为红
|
||||||
|
if (uncle && uncle->_colour == RED)
|
||||||
|
{
|
||||||
|
parent->_colour = uncle->_colour = BLACK;
|
||||||
|
grandfather->_colour = RED;
|
||||||
|
|
||||||
|
// 继续向上处理
|
||||||
|
cur = grandfather;
|
||||||
|
parent = cur->_parent;
|
||||||
|
}
|
||||||
|
// 情况 2 or 情况 3 : uncle 不存在 or uncle 存在且为黑
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 情况 3 : 双旋 -> 变单旋
|
||||||
|
if (cur == parent->_right)
|
||||||
|
{
|
||||||
|
RotateL(parent);
|
||||||
|
std::swap(parent, cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第二种情况 (ps: 有可能是第三种情况变过来的)
|
||||||
|
RotateR(grandfather);
|
||||||
|
grandfather->_colour = RED;
|
||||||
|
parent->_colour = BLACK;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 父节点是祖父节点的右子节点
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Node *uncle = grandfather->_left;
|
||||||
|
|
||||||
|
// 情况1: uncle 存在, 且为红
|
||||||
|
if (uncle && uncle->_colour == RED)
|
||||||
|
{
|
||||||
|
parent->_colour = uncle->_colour = BLACK;
|
||||||
|
grandfather->_colour = RED;
|
||||||
|
|
||||||
|
// 继续向上调整
|
||||||
|
cur = grandfather;
|
||||||
|
parent = cur->_parent;
|
||||||
|
}
|
||||||
|
// 情况 2 or 情况 3 : uncle 不存在 or uncle 存在且为黑
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 情况 3 : 双旋 -> 变单旋
|
||||||
|
if (cur == parent->_left)
|
||||||
|
{
|
||||||
|
RotateR(parent);
|
||||||
|
std::swap(parent, cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第二种情况 (ps: 有可能是第三种情况变过来的)
|
||||||
|
RotateL(grandfather);
|
||||||
|
grandfather->_colour = RED;
|
||||||
|
parent->_colour = BLACK;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保证根节点为黑
|
||||||
|
_root->_colour = BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除操作
|
||||||
|
bool Erase(const K &key)
|
||||||
|
{
|
||||||
|
Node *nodeToDelete = _root;
|
||||||
|
KOfT koft;
|
||||||
|
|
||||||
|
// 1. 寻找要删除的节点
|
||||||
|
while (nodeToDelete)
|
||||||
|
{
|
||||||
|
if (koft(nodeToDelete->_data) > key)
|
||||||
|
{
|
||||||
|
nodeToDelete = nodeToDelete->_left;
|
||||||
|
}
|
||||||
|
else if (koft(nodeToDelete->_data) < key)
|
||||||
|
{
|
||||||
|
nodeToDelete = nodeToDelete->_right;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break; // 找到了要删除的节点
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 节点若不存在, 直接返回 false
|
||||||
|
if (nodeToDelete == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行删除操作
|
||||||
|
Node *parent, *child;
|
||||||
|
// 保存原节点的颜色,以便后续调整
|
||||||
|
Colour originalColour = nodeToDelete->_colour;
|
||||||
|
|
||||||
|
// 2. 处理删除节点的各种情况
|
||||||
|
if (nodeToDelete->_left == nullptr)
|
||||||
|
{
|
||||||
|
// 情况 1:没有左子节点
|
||||||
|
child = nodeToDelete->_right;
|
||||||
|
parent = nodeToDelete->_parent;
|
||||||
|
Transplant(nodeToDelete, nodeToDelete->_right);
|
||||||
|
}
|
||||||
|
else if (nodeToDelete->_right == nullptr)
|
||||||
|
{
|
||||||
|
// 情况 2:没有右子节点
|
||||||
|
child = nodeToDelete->_left;
|
||||||
|
parent = nodeToDelete->_parent;
|
||||||
|
Transplant(nodeToDelete, nodeToDelete->_left);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 情况 3:有两个子节点
|
||||||
|
// 找到右子树中的最小节点(后继节点)
|
||||||
|
Node *successor = Minimum(nodeToDelete->_right);
|
||||||
|
originalColour = successor->_colour;
|
||||||
|
child = successor->_right;
|
||||||
|
if (successor->_parent == nodeToDelete)
|
||||||
|
{
|
||||||
|
parent = successor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 后继节点有右子节点,用它的右子节点替换它
|
||||||
|
Transplant(successor, successor->_right);
|
||||||
|
successor->_right = nodeToDelete->_right;
|
||||||
|
successor->_right->_parent = successor;
|
||||||
|
parent = successor->_parent;
|
||||||
|
}
|
||||||
|
// 用后继节点替换删除节点
|
||||||
|
Transplant(nodeToDelete, successor);
|
||||||
|
successor->_left = nodeToDelete->_left;
|
||||||
|
successor->_left->_parent = successor;
|
||||||
|
successor->_colour = nodeToDelete->_colour; // 保持颜色不变
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除节点
|
||||||
|
delete nodeToDelete;
|
||||||
|
|
||||||
|
// 3. 修复红黑树的性质
|
||||||
|
// 如果删除的节点是黑色, 需要进行调整
|
||||||
|
if (originalColour == BLACK)
|
||||||
|
{
|
||||||
|
EraseFixUp(child, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *Minimum(Node *node)
|
||||||
|
{
|
||||||
|
while (node->_left != nullptr)
|
||||||
|
{
|
||||||
|
node = node->_left; // 一直向左走,直到找到最左节点
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transplant(Node *u, Node *v)
|
||||||
|
{
|
||||||
|
// 如果u是根节点,v成为新的根节点
|
||||||
|
if (u->_parent == nullptr)
|
||||||
|
{
|
||||||
|
_root = v;
|
||||||
|
}
|
||||||
|
// u是左子节点,用v替换它
|
||||||
|
else if (u == u->_parent->_left)
|
||||||
|
{
|
||||||
|
u->_parent->_left = v;
|
||||||
|
}
|
||||||
|
// u是右子节点,用v替换它
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u->_parent->_right = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 连接v与u的父节点
|
||||||
|
if (v != nullptr)
|
||||||
|
{
|
||||||
|
v->_parent = u->_parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EraseFixUp(Node *child, Node *parent)
|
||||||
|
{
|
||||||
|
while (child != _root && (child == nullptr || child->_colour == BLACK))
|
||||||
|
{
|
||||||
|
if (child == parent->_left)
|
||||||
|
{
|
||||||
|
Node *brother = parent->_right;
|
||||||
|
// 情况1: child 的兄弟节点 brother 是红色的
|
||||||
|
if (brother->_colour == RED)
|
||||||
|
{
|
||||||
|
brother->_colour = BLACK;
|
||||||
|
parent->_colour = RED;
|
||||||
|
RotateL(parent);
|
||||||
|
brother = parent->_right;
|
||||||
|
}
|
||||||
|
// 情况2: child 的兄弟节点 brother 是黑色的, 且 brother 的两个节点都是黑色的
|
||||||
|
if ((brother->_left == nullptr || brother->_left->_colour == BLACK) &&
|
||||||
|
(brother->_right == nullptr || brother->_right->_colour == BLACK))
|
||||||
|
{
|
||||||
|
brother->_colour = RED;
|
||||||
|
child = parent;
|
||||||
|
parent = child->_parent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 情况3: brother 是黑色的, 并且 brother 的左子节点是红色, 右子节点是黑色
|
||||||
|
if (brother->_right == nullptr || brother->_right->_colour == BLACK)
|
||||||
|
{
|
||||||
|
if (brother->_left)
|
||||||
|
{
|
||||||
|
brother->_left->_colour = BLACK;
|
||||||
|
}
|
||||||
|
brother->_colour = RED;
|
||||||
|
RotateR(brother);
|
||||||
|
brother = parent->_right;
|
||||||
|
}
|
||||||
|
// 情况4: brother 是黑色的, 并且 brother 的右子节点是红色
|
||||||
|
if (brother)
|
||||||
|
{
|
||||||
|
brother->_colour = parent->_colour;
|
||||||
|
parent->_colour = BLACK;
|
||||||
|
if (brother->_right)
|
||||||
|
{
|
||||||
|
brother->_right->_colour = BLACK;
|
||||||
|
}
|
||||||
|
RotateL(parent);
|
||||||
|
}
|
||||||
|
child = _root;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Node *brother = parent->_left;
|
||||||
|
// 情况1: child 的兄弟节点 brother 是红色的
|
||||||
|
if (brother->_colour == RED)
|
||||||
|
{
|
||||||
|
brother->_colour = BLACK;
|
||||||
|
parent->_colour = RED;
|
||||||
|
RotateR(parent);
|
||||||
|
brother = parent->_left;
|
||||||
|
}
|
||||||
|
// 情况2: child 的兄弟节点 parent 是黑色的, 且 brother 的两个节点都是黑色的
|
||||||
|
if ((brother->_left == nullptr || brother->_left->_colour == BLACK) &&
|
||||||
|
(brother->_right == nullptr || brother->_right->_colour == BLACK))
|
||||||
|
{
|
||||||
|
brother->_colour = RED;
|
||||||
|
child = parent;
|
||||||
|
parent = child->_parent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 情况3: brother 是黑色的, 并且 brother 的右子节点是红色, 左子节点是黑色
|
||||||
|
if (brother->_left == nullptr || brother->_left->_colour == BLACK)
|
||||||
|
{
|
||||||
|
if (brother->_right)
|
||||||
|
{
|
||||||
|
brother->_right->_colour = BLACK;
|
||||||
|
}
|
||||||
|
brother->_colour = RED;
|
||||||
|
RotateL(brother);
|
||||||
|
brother = parent->_left;
|
||||||
|
}
|
||||||
|
// 情况4: brother 是黑色的, 并且 brother 的左子节点是红色
|
||||||
|
if (brother)
|
||||||
|
{
|
||||||
|
brother->_colour = parent->_colour;
|
||||||
|
parent->_colour = BLACK;
|
||||||
|
if (brother->_left)
|
||||||
|
{
|
||||||
|
brother->_left->_colour = BLACK;
|
||||||
|
}
|
||||||
|
RotateR(parent);
|
||||||
|
}
|
||||||
|
child = _root;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
child->_colour = BLACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找节点
|
||||||
|
iterator &Find(const K &key)
|
||||||
|
{
|
||||||
|
KOfT koft;
|
||||||
|
Node *cur = _root;
|
||||||
|
while (cur)
|
||||||
|
{
|
||||||
|
if (koft(cur->_data) > key)
|
||||||
|
{
|
||||||
|
cur = cur->_left;
|
||||||
|
}
|
||||||
|
else if (koft(cur->_data) < key)
|
||||||
|
{
|
||||||
|
cur = cur->_right;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return iterator(cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iterator(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否是红黑树
|
||||||
|
bool IsRBTree()
|
||||||
|
{
|
||||||
|
Node *root = _root;
|
||||||
|
|
||||||
|
// 空树也是红黑树
|
||||||
|
if (root == nullptr)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 判断跟是否是黑色的
|
||||||
|
if (root->_colour != BLACK)
|
||||||
|
{
|
||||||
|
std::cout << "根节点不是黑色" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取任意一条路径上黑色节点的数量
|
||||||
|
size_t blackCount = 0;
|
||||||
|
Node *cur = _root;
|
||||||
|
while (cur)
|
||||||
|
{
|
||||||
|
if (cur->_colour == BLACK)
|
||||||
|
{
|
||||||
|
blackCount++;
|
||||||
|
}
|
||||||
|
cur = cur->_left;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否满足红黑树的性质, k 用来记录路径中黑色节点的个数
|
||||||
|
size_t k = 0;
|
||||||
|
return _IsRBTree(_root, k, blackCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _IsRBTree(Node *root, size_t k, size_t blackCount)
|
||||||
|
{
|
||||||
|
// 走到 nullptr 之后, 判断 k 和 blackCount 是否相等
|
||||||
|
if (root == nullptr)
|
||||||
|
{
|
||||||
|
// 最终黑色节点个数
|
||||||
|
if (blackCount != k)
|
||||||
|
{
|
||||||
|
std::cout << "违反性质四: 每条路径中黑色节点的个数必须相等" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统计黑色节点个数
|
||||||
|
if (root->_colour == BLACK)
|
||||||
|
{
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测当前节点与其父亲节点是否都为红色
|
||||||
|
Node *parent = root->_parent;
|
||||||
|
if (parent && parent->_colour == RED && root->_colour == RED)
|
||||||
|
{
|
||||||
|
std::cout << "违反了性质三: 红色节点的孩子必须是黑色" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _IsRBTree(root->_left, k, blackCount) && _IsRBTree(root->_right, k, blackCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Node *_root;
|
||||||
|
};
|
||||||
|
}
|
66
Linux/Set.hpp
Normal file
66
Linux/Set.hpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RBTree.hpp"
|
||||||
|
|
||||||
|
namespace Lenyiin
|
||||||
|
{
|
||||||
|
template <class K>
|
||||||
|
class Set
|
||||||
|
{
|
||||||
|
struct SetKeyOfT
|
||||||
|
{
|
||||||
|
const K &operator()(const K &k)
|
||||||
|
{
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
// 这里RBTree<K, K, SetKeyOfT>::iterator还没有实例化, 系统找不到, typename告诉编译器现在先不着急找
|
||||||
|
typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;
|
||||||
|
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return _tree.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return _tree.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
return _tree.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return _tree.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, bool> Insert(const K &key)
|
||||||
|
{
|
||||||
|
return _tree.Insert(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Erase(const K &key)
|
||||||
|
{
|
||||||
|
return _tree.Erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator &Find(const K &key)
|
||||||
|
{
|
||||||
|
return _tree.Find(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsRBTree()
|
||||||
|
{
|
||||||
|
return _tree.IsRBTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RBTree<K, K, SetKeyOfT> _tree;
|
||||||
|
};
|
||||||
|
}
|
BIN
Linux/main
Normal file
BIN
Linux/main
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Windows_Set_Map/.vs/Windows_Set_Map/v17/.suo
Normal file
BIN
Windows_Set_Map/.vs/Windows_Set_Map/v17/.suo
Normal file
Binary file not shown.
BIN
Windows_Set_Map/.vs/Windows_Set_Map/v17/Browse.VC.db
Normal file
BIN
Windows_Set_Map/.vs/Windows_Set_Map/v17/Browse.VC.db
Normal file
Binary file not shown.
@ -0,0 +1,100 @@
|
|||||||
|
{
|
||||||
|
"Version": 1,
|
||||||
|
"WorkspaceRootPath": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\",
|
||||||
|
"Documents": [
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Main.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|solutionrelative:Main.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\RBTree.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|solutionrelative:RBTree.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Set.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|solutionrelative:Set.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Map.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|solutionrelative:Map.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"DocumentGroupContainers": [
|
||||||
|
{
|
||||||
|
"Orientation": 0,
|
||||||
|
"VerticalTabListWidth": 256,
|
||||||
|
"DocumentGroups": [
|
||||||
|
{
|
||||||
|
"DockedWidth": 267,
|
||||||
|
"SelectedChildIndex": 3,
|
||||||
|
"Children": [
|
||||||
|
{
|
||||||
|
"$type": "Bookmark",
|
||||||
|
"Name": "ST:128:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Bookmark",
|
||||||
|
"Name": "ST:129:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Bookmark",
|
||||||
|
"Name": "ST:128:0:{1fc202d4-d401-403c-9834-5b218574bb67}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 0,
|
||||||
|
"Title": "Main.cpp",
|
||||||
|
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Main.cpp",
|
||||||
|
"RelativeDocumentMoniker": "Main.cpp",
|
||||||
|
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Main.cpp*",
|
||||||
|
"RelativeToolTip": "Main.cpp*",
|
||||||
|
"ViewState": "AgIAAF4BAAAAAAAAAAAswHEBAAABAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||||
|
"WhenOpened": "2024-09-23T15:54:15.721Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 1,
|
||||||
|
"Title": "RBTree.hpp",
|
||||||
|
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\RBTree.hpp",
|
||||||
|
"RelativeDocumentMoniker": "RBTree.hpp",
|
||||||
|
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\RBTree.hpp",
|
||||||
|
"RelativeToolTip": "RBTree.hpp",
|
||||||
|
"ViewState": "AgIAANACAAAAAAAAAAAswOMCAAABAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2024-09-23T15:54:05.493Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 2,
|
||||||
|
"Title": "Set.hpp",
|
||||||
|
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Set.hpp",
|
||||||
|
"RelativeDocumentMoniker": "Set.hpp",
|
||||||
|
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Set.hpp",
|
||||||
|
"RelativeToolTip": "Set.hpp",
|
||||||
|
"ViewState": "AgIAAC4AAAAAAAAAAAAswDYAAAAjAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2024-09-23T15:53:53.08Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 3,
|
||||||
|
"Title": "Map.hpp",
|
||||||
|
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Map.hpp",
|
||||||
|
"RelativeDocumentMoniker": "Map.hpp",
|
||||||
|
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Map.hpp",
|
||||||
|
"RelativeToolTip": "Map.hpp",
|
||||||
|
"ViewState": "AgIAAC4AAAAAAAAAAAAswEEAAAABAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2024-09-23T15:53:43.888Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
100
Windows_Set_Map/.vs/Windows_Set_Map/v17/DocumentLayout.json
Normal file
100
Windows_Set_Map/.vs/Windows_Set_Map/v17/DocumentLayout.json
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
{
|
||||||
|
"Version": 1,
|
||||||
|
"WorkspaceRootPath": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\",
|
||||||
|
"Documents": [
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Main.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|solutionrelative:Main.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\RBTree.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|solutionrelative:RBTree.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Set.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|solutionrelative:Set.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Map.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{2827E392-69FE-4ABC-84E6-BF5E25017C39}|Windows_Set_Map.vcxproj|solutionrelative:Map.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"DocumentGroupContainers": [
|
||||||
|
{
|
||||||
|
"Orientation": 0,
|
||||||
|
"VerticalTabListWidth": 256,
|
||||||
|
"DocumentGroups": [
|
||||||
|
{
|
||||||
|
"DockedWidth": 267,
|
||||||
|
"SelectedChildIndex": 3,
|
||||||
|
"Children": [
|
||||||
|
{
|
||||||
|
"$type": "Bookmark",
|
||||||
|
"Name": "ST:128:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Bookmark",
|
||||||
|
"Name": "ST:129:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Bookmark",
|
||||||
|
"Name": "ST:128:0:{1fc202d4-d401-403c-9834-5b218574bb67}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 0,
|
||||||
|
"Title": "Main.cpp",
|
||||||
|
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Main.cpp",
|
||||||
|
"RelativeDocumentMoniker": "Main.cpp",
|
||||||
|
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Main.cpp",
|
||||||
|
"RelativeToolTip": "Main.cpp",
|
||||||
|
"ViewState": "AgIAAF4BAAAAAAAAAAAswGgBAAATAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||||
|
"WhenOpened": "2024-09-23T15:54:15.721Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 1,
|
||||||
|
"Title": "RBTree.hpp",
|
||||||
|
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\RBTree.hpp",
|
||||||
|
"RelativeDocumentMoniker": "RBTree.hpp",
|
||||||
|
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\RBTree.hpp",
|
||||||
|
"RelativeToolTip": "RBTree.hpp",
|
||||||
|
"ViewState": "AgIAANACAAAAAAAAAAAswOMCAAABAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2024-09-23T15:54:05.493Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 2,
|
||||||
|
"Title": "Set.hpp",
|
||||||
|
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Set.hpp",
|
||||||
|
"RelativeDocumentMoniker": "Set.hpp",
|
||||||
|
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Set.hpp",
|
||||||
|
"RelativeToolTip": "Set.hpp",
|
||||||
|
"ViewState": "AgIAAC4AAAAAAAAAAAAswDYAAAAjAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2024-09-23T15:53:53.08Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 3,
|
||||||
|
"Title": "Map.hpp",
|
||||||
|
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Map.hpp",
|
||||||
|
"RelativeDocumentMoniker": "Map.hpp",
|
||||||
|
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\9_Set_Map\\Windows_Set_Map\\Map.hpp",
|
||||||
|
"RelativeToolTip": "Map.hpp",
|
||||||
|
"ViewState": "AgIAAC4AAAAAAAAAAAAswEEAAAABAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2024-09-23T15:53:43.888Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
370
Windows_Set_Map/Main.cpp
Normal file
370
Windows_Set_Map/Main.cpp
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <set>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "Set.hpp"
|
||||||
|
#include "Map.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Lenyiin;
|
||||||
|
|
||||||
|
// 序列式容器: vector/list/string/deque/array/forward_list
|
||||||
|
// 关联式容器: set/multiset/map/multimap/unordered_set/unordered_multiset/unordered_map/unordered_multimap
|
||||||
|
|
||||||
|
void test_set()
|
||||||
|
{
|
||||||
|
set<int> s1; // set默认排序为从小到大 set底层是搜索树
|
||||||
|
s1.insert(10);
|
||||||
|
s1.insert(20);
|
||||||
|
s1.insert(5);
|
||||||
|
s1.insert(2);
|
||||||
|
s1.insert(1);
|
||||||
|
s1.insert(8);
|
||||||
|
s1.insert(14);
|
||||||
|
s1.insert(44);
|
||||||
|
s1.insert(23);
|
||||||
|
s1.insert(0);
|
||||||
|
s1.insert(2);
|
||||||
|
s1.insert(1);
|
||||||
|
s1.insert(8);
|
||||||
|
s1.insert(14);
|
||||||
|
|
||||||
|
// 排序 + 去重
|
||||||
|
set<int>::iterator it = s1.begin();
|
||||||
|
while (it != s1.end())
|
||||||
|
{
|
||||||
|
//*it = 100; // set中的元素是只读的,不能修改
|
||||||
|
cout << *it << " ";
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 范围for
|
||||||
|
for (auto e : s1)
|
||||||
|
{
|
||||||
|
cout << e << " ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 拷贝构造 底层默认是一个深拷贝
|
||||||
|
set<int> s2(s1);
|
||||||
|
for (auto e : s2)
|
||||||
|
{
|
||||||
|
cout << e << " ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
// find()是成员函数,只能用于set/multiset/map/multimap
|
||||||
|
// set<int>::iterator pos = s2.find(5);
|
||||||
|
auto pos = s2.find(5);
|
||||||
|
|
||||||
|
// find()是泛型算法,可以用于所有容器
|
||||||
|
// s.find() O(logN) s.begin() O(1) s.end() O(1)
|
||||||
|
// find(s.begin(), s.end(), 5) O(N) 效率会低不少
|
||||||
|
// auto pos = find(s2.begin(), s2.end(), 5);
|
||||||
|
|
||||||
|
if (pos != s2.end())
|
||||||
|
{
|
||||||
|
s2.erase(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto e : s2)
|
||||||
|
{
|
||||||
|
cout << e << " ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 或者直接删
|
||||||
|
s2.erase(8);
|
||||||
|
s2.erase(80); // 和迭代器的区别在于:删除不存在的元素,不会报错
|
||||||
|
for (auto e : s2)
|
||||||
|
{
|
||||||
|
cout << e << " ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_map1()
|
||||||
|
{
|
||||||
|
map<int, int> m1;
|
||||||
|
m1.insert(pair<int, int>(1, 1)); // pair是一个模板类,可以用来创建pair对象
|
||||||
|
m1.insert(pair<int, int>(3, 3));
|
||||||
|
m1.insert(pair<int, int>(2, 2));
|
||||||
|
m1.insert(pair<int, int>(5, 5));
|
||||||
|
m1.insert(pair<int, int>(6, 6));
|
||||||
|
m1.insert(pair<int, int>(4, 4)); // pair构造函数,构造一个匿名对象,然后插入到map中
|
||||||
|
|
||||||
|
// 日常大家喜欢用make_pair()来构造pair对象,因为他不用声明模板参数,编译器自动推
|
||||||
|
m1.insert(make_pair(7, 7)); // 函数模板构造一个pair对象
|
||||||
|
|
||||||
|
map<int, int>::iterator it = m1.begin();
|
||||||
|
while (it != m1.end())
|
||||||
|
{
|
||||||
|
// cout << *it << " "; // C++不支持返回两个数
|
||||||
|
cout << (*it).first << " " << (*it).second << endl; // operator*()返回的是节点中值的引用
|
||||||
|
cout << it->first << " " << it->second << endl; // operator->()返回的是节点的指针 也就是pair<k, v>的指针
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 范围for
|
||||||
|
for (auto& e : m1)
|
||||||
|
{
|
||||||
|
cout << e.first << " " << e.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_map2()
|
||||||
|
{
|
||||||
|
std::map<std::string, std::string> dirt;
|
||||||
|
dirt.insert(pair<std::string, std::string>("sort", "排序"));
|
||||||
|
dirt.insert(make_pair("string", "字符串"));
|
||||||
|
dirt.insert(make_pair("left", "左边")); // 按照ASCII码排序
|
||||||
|
|
||||||
|
std::map<std::string, std::string>::iterator it = dirt.begin();
|
||||||
|
while (it != dirt.end())
|
||||||
|
{
|
||||||
|
cout << it->first << " " << it->second << endl;
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_map3()
|
||||||
|
{
|
||||||
|
// 统计单词出现的次数
|
||||||
|
string strArr[] = { "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果",
|
||||||
|
"西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉",
|
||||||
|
"西瓜", "樱桃", "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果",
|
||||||
|
"西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉" };
|
||||||
|
map<string, int> countMap;
|
||||||
|
|
||||||
|
// 第一种方法
|
||||||
|
for (auto& str : strArr)
|
||||||
|
{
|
||||||
|
map<string, int>::iterator pos = countMap.find(str);
|
||||||
|
if (pos != countMap.end())
|
||||||
|
{
|
||||||
|
pos->second++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
countMap.insert(make_pair(str, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& e : countMap)
|
||||||
|
{
|
||||||
|
cout << e.first << " " << e.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 第二种方法
|
||||||
|
for (auto& str : strArr)
|
||||||
|
{
|
||||||
|
pair<map<string, int>::iterator, bool> ret = countMap.insert(make_pair(str, 1));
|
||||||
|
if (ret.second == false) // 插入失败,说明已经存在
|
||||||
|
{
|
||||||
|
ret.first->second++; // 迭代器指向的是插入的元素
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& e : countMap)
|
||||||
|
{
|
||||||
|
cout << e.first << " " << e.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 第三种方法
|
||||||
|
for (auto& str : strArr)
|
||||||
|
{
|
||||||
|
// 1、如果水果不在map中,则[]会插入pair<str, 0>, 返回映射对象(次数)的引用进行++
|
||||||
|
// 2、如果水果在map中,则[]会返回水果对应的映射对象(次数)的引用,对它进行++
|
||||||
|
countMap[str]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
countMap["葡萄"]; // 插入 一般不这么用
|
||||||
|
countMap["葡萄"] = 100; // 修改
|
||||||
|
cout << countMap["葡萄"] << endl; // 查找
|
||||||
|
countMap["哈密瓜"] = 5; // 插入 + 修改
|
||||||
|
|
||||||
|
// 一般使用operator[]去
|
||||||
|
// 1、插入 + 修改
|
||||||
|
// 2、修改
|
||||||
|
// 一般不会用他去做查找,因为如果key不在,会插入数据。
|
||||||
|
|
||||||
|
for (auto& e : countMap)
|
||||||
|
{
|
||||||
|
cout << e.first << " " << e.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_multi()
|
||||||
|
{
|
||||||
|
// multiset根set的区别就是允许键值冗余
|
||||||
|
multiset<int> s1; // 使用和set一样,只是multiset可以存放重复的元素
|
||||||
|
s1.insert(10);
|
||||||
|
s1.insert(20);
|
||||||
|
s1.insert(5);
|
||||||
|
s1.insert(2);
|
||||||
|
s1.insert(1);
|
||||||
|
s1.insert(8);
|
||||||
|
s1.insert(8);
|
||||||
|
s1.insert(14);
|
||||||
|
s1.insert(44);
|
||||||
|
s1.insert(23);
|
||||||
|
s1.insert(0);
|
||||||
|
s1.insert(2);
|
||||||
|
s1.insert(1);
|
||||||
|
s1.insert(8);
|
||||||
|
s1.insert(8);
|
||||||
|
s1.insert(14);
|
||||||
|
|
||||||
|
for (auto e : s1)
|
||||||
|
{
|
||||||
|
cout << e << " ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
auto pos = s1.find(8); // 查找到的是重复元素的第一个元素地址
|
||||||
|
cout << *pos << endl;
|
||||||
|
pos++;
|
||||||
|
cout << *pos << endl;
|
||||||
|
pos++;
|
||||||
|
cout << *pos << endl;
|
||||||
|
pos++;
|
||||||
|
cout << *pos << endl;
|
||||||
|
pos++;
|
||||||
|
cout << *pos << endl;
|
||||||
|
|
||||||
|
// multimap和map的区别和上面是一样的
|
||||||
|
multimap<string, int> mm;
|
||||||
|
mm.insert(make_pair("苹果", 1));
|
||||||
|
mm.insert(make_pair("苹果", 1));
|
||||||
|
mm.insert(make_pair("苹果", 3));
|
||||||
|
mm.insert(make_pair("西瓜", 2));
|
||||||
|
mm.insert(make_pair("西瓜", 1));
|
||||||
|
|
||||||
|
for (auto& e : mm)
|
||||||
|
{
|
||||||
|
cout << e.first << " " << e.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自己实现的 Set Map 测试
|
||||||
|
void test_Set()
|
||||||
|
{
|
||||||
|
Set<int> s;
|
||||||
|
s.Insert(3);
|
||||||
|
s.Insert(4);
|
||||||
|
s.Insert(1);
|
||||||
|
s.Insert(2);
|
||||||
|
s.Insert(2);
|
||||||
|
s.Insert(5);
|
||||||
|
|
||||||
|
// 迭代器遍历
|
||||||
|
Set<int>::iterator it = s.begin();
|
||||||
|
while (it != s.end())
|
||||||
|
{
|
||||||
|
cout << *it << " ";
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
s.Erase(4);
|
||||||
|
|
||||||
|
// for
|
||||||
|
for (const auto& k : s)
|
||||||
|
{
|
||||||
|
cout << k << " ";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
cout << "IsRBTree? " << (s.IsRBTree() ? "true" : "false") << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Map1()
|
||||||
|
{
|
||||||
|
// int a[] = {16, 3, 7, 11, 9, 26, 18, 14, 15};
|
||||||
|
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
|
||||||
|
Map<int, int> m;
|
||||||
|
for (const auto& e : a)
|
||||||
|
{
|
||||||
|
m.Insert(make_pair(e, e));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 迭代器遍历
|
||||||
|
Map<int, int>::iterator it = m.begin();
|
||||||
|
while (it != m.end())
|
||||||
|
{
|
||||||
|
cout << it->first << ":" << it->second << endl;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
m.Erase(4);
|
||||||
|
|
||||||
|
// 范围for遍历 for_each 底层也是调用的迭代器实现的遍历
|
||||||
|
for (const auto& kv : m)
|
||||||
|
{
|
||||||
|
cout << kv.first << ":" << kv.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
cout << "IsRBTree? " << (m.IsRBTree() ? "true" : "false") << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Map2()
|
||||||
|
{
|
||||||
|
// 统计单词出现的次数
|
||||||
|
string strArr[] = { "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果",
|
||||||
|
"西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉",
|
||||||
|
"西瓜", "樱桃", "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果",
|
||||||
|
"西瓜", "苹果", "西瓜", "香蕉", "西瓜", "樱桃", "西瓜", "苹果", "西瓜", "苹果", "西瓜", "香蕉" };
|
||||||
|
Map<string, int> countMap;
|
||||||
|
for (auto& str : strArr)
|
||||||
|
{
|
||||||
|
countMap[str]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 迭代器遍历
|
||||||
|
Map<string, int>::iterator it = countMap.begin();
|
||||||
|
while (it != countMap.end())
|
||||||
|
{
|
||||||
|
cout << it->first << ":" << it->second << endl;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
countMap.Erase("苹果");
|
||||||
|
|
||||||
|
for (const auto& kv : countMap)
|
||||||
|
{
|
||||||
|
cout << kv.first << ":" << kv.second << endl;
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
cout << "IsRBTree? " << (countMap.IsRBTree() ? "true" : "false") << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// test_set();
|
||||||
|
// test_map1();
|
||||||
|
// test_map2();
|
||||||
|
// test_map3();
|
||||||
|
// test_multi();
|
||||||
|
|
||||||
|
test_Set();
|
||||||
|
test_Map1();
|
||||||
|
test_Map2();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
66
Windows_Set_Map/Map.hpp
Normal file
66
Windows_Set_Map/Map.hpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RBTree.hpp"
|
||||||
|
|
||||||
|
namespace Lenyiin
|
||||||
|
{
|
||||||
|
template <class K, class V>
|
||||||
|
class Map
|
||||||
|
{
|
||||||
|
struct MapKeyOfT
|
||||||
|
{
|
||||||
|
const K& operator()(const std::pair<K, V>& kv)
|
||||||
|
{
|
||||||
|
return kv.first;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename RBTree<K, std::pair<K, V>, MapKeyOfT>::iterator iterator;
|
||||||
|
typedef typename RBTree<K, std::pair<K, V>, MapKeyOfT>::const_iterator const_iterator;
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return _tree.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return _tree.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
return _tree.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return _tree.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, bool> Insert(const std::pair<K, V>& kv)
|
||||||
|
{
|
||||||
|
return _tree.Insert(kv);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Erase(const K& key)
|
||||||
|
{
|
||||||
|
return _tree.Erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
V& operator[](const K& key)
|
||||||
|
{
|
||||||
|
std::pair<iterator, bool> ret = _tree.Insert(std::make_pair(key, V()));
|
||||||
|
return ret.first->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsRBTree()
|
||||||
|
{
|
||||||
|
return _tree.IsRBTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RBTree<K, std::pair<K, V>, MapKeyOfT> _tree;
|
||||||
|
};
|
||||||
|
}
|
740
Windows_Set_Map/RBTree.hpp
Normal file
740
Windows_Set_Map/RBTree.hpp
Normal file
@ -0,0 +1,740 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace Lenyiin
|
||||||
|
{
|
||||||
|
enum Colour
|
||||||
|
{
|
||||||
|
RED,
|
||||||
|
BLACK
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct RBTreeNode
|
||||||
|
{
|
||||||
|
RBTreeNode<T>* _left; // 左子节点
|
||||||
|
RBTreeNode<T>* _right; // 右子节点
|
||||||
|
RBTreeNode<T>* _parent; // 父节点
|
||||||
|
|
||||||
|
T _data; // 节点存储的数据
|
||||||
|
Colour _colour; // 节点的颜色(红色或黑色)
|
||||||
|
|
||||||
|
// 节点的构造函数,默认为红色节点
|
||||||
|
RBTreeNode(const T& data)
|
||||||
|
: _left(nullptr), _right(nullptr), _parent(nullptr), _data(data), _colour(RED)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, class Ref, class Ptr>
|
||||||
|
struct __TreeIterator
|
||||||
|
{
|
||||||
|
typedef RBTreeNode<T> Node;
|
||||||
|
typedef __TreeIterator<T, Ref, Ptr> Self;
|
||||||
|
Node* _node; // 当前迭代器指向的节点
|
||||||
|
|
||||||
|
// 构造函数
|
||||||
|
__TreeIterator(Node* node)
|
||||||
|
: _node(node)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解引用操作符
|
||||||
|
Ref operator*()
|
||||||
|
{
|
||||||
|
return _node->_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 访问成员操作符
|
||||||
|
Ptr operator->()
|
||||||
|
{
|
||||||
|
return &_node->_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 前置递增运算符
|
||||||
|
Self& operator++()
|
||||||
|
{
|
||||||
|
// 1. 如果右不为空, 中序的下一个就是右子树的最左节点
|
||||||
|
if (_node->_right)
|
||||||
|
{
|
||||||
|
Node* subLeft = _node->_right;
|
||||||
|
while (subLeft->_left)
|
||||||
|
{
|
||||||
|
subLeft = subLeft->_left;
|
||||||
|
}
|
||||||
|
_node = subLeft;
|
||||||
|
}
|
||||||
|
// 2. 如果右为空, 表示 _node 所在的子树已经完成, 下一个节点在他祖先中去找, 沿着路径往上找孩子使它的左的那个祖先
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Node* cur = _node;
|
||||||
|
Node* parent = cur->_parent;
|
||||||
|
while (parent && cur == parent->_right)
|
||||||
|
{
|
||||||
|
cur = parent;
|
||||||
|
parent = cur->_parent;
|
||||||
|
}
|
||||||
|
_node = parent;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 后置递增运算符
|
||||||
|
Self operator++(int)
|
||||||
|
{
|
||||||
|
Node* tmp = _node;
|
||||||
|
++(*this);
|
||||||
|
return Self(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 前置递减运算符
|
||||||
|
Self& operator--()
|
||||||
|
{
|
||||||
|
// 1. 如果左不为空, 中序的上一个就是左树的最右节点
|
||||||
|
if (_node->_left)
|
||||||
|
{
|
||||||
|
Node* subRight = _node->left;
|
||||||
|
while (subRight->_right)
|
||||||
|
{
|
||||||
|
subRight = subRight->_right;
|
||||||
|
}
|
||||||
|
_node = subRight;
|
||||||
|
}
|
||||||
|
// 2. 如果左为空, 表示 _node 所在的子树已经完成, 上一个节点在他祖先中去找, 沿着路径往上找孩子是它的右的那个祖先
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Node* cur = _node;
|
||||||
|
Node* parent = cur->_parent;
|
||||||
|
while (parent && cur == parent->_left)
|
||||||
|
{
|
||||||
|
cur = parent;
|
||||||
|
parent = cur->_parent;
|
||||||
|
}
|
||||||
|
_node = parent;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 后置递减运算符
|
||||||
|
Self operator--(int)
|
||||||
|
{
|
||||||
|
Node* tmp = _node;
|
||||||
|
--(*this);
|
||||||
|
return Self(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Self& n)
|
||||||
|
{
|
||||||
|
return _node != n._node;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Self& n)
|
||||||
|
{
|
||||||
|
return _node == n._node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class K, class T, class KOfT>
|
||||||
|
class RBTree
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef RBTreeNode<T> Node;
|
||||||
|
|
||||||
|
// 左单旋
|
||||||
|
void RotateL(Node* parent)
|
||||||
|
{
|
||||||
|
Node* ppNode = parent->_parent;
|
||||||
|
Node* subR = parent->_right;
|
||||||
|
Node* subRL = subR->_left;
|
||||||
|
|
||||||
|
parent->_right = subRL;
|
||||||
|
if (subRL)
|
||||||
|
{
|
||||||
|
subRL->_parent = parent;
|
||||||
|
}
|
||||||
|
subR->_left = parent;
|
||||||
|
parent->_parent = subR;
|
||||||
|
|
||||||
|
// 1. 原来 parent 是这棵树的根, 现在 subR 是根
|
||||||
|
if (_root == parent)
|
||||||
|
{
|
||||||
|
_root = subR;
|
||||||
|
subR->_parent = nullptr;
|
||||||
|
}
|
||||||
|
// 2. parent 为根的树只是整棵树中的子树, 改变链接关系, 那么 subR 要顶替他的位置
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ppNode->_left == parent)
|
||||||
|
{
|
||||||
|
ppNode->_left = subR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ppNode->_right = subR;
|
||||||
|
}
|
||||||
|
subR->_parent = ppNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右单旋
|
||||||
|
void RotateR(Node* parent)
|
||||||
|
{
|
||||||
|
Node* ppNode = parent->_parent;
|
||||||
|
Node* subL = parent->_left;
|
||||||
|
Node* subLR = subL->_right;
|
||||||
|
|
||||||
|
parent->_left = subLR;
|
||||||
|
if (subLR)
|
||||||
|
{
|
||||||
|
subLR->_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除整个红黑树
|
||||||
|
void DeleteTree(Node* root)
|
||||||
|
{
|
||||||
|
if (root == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归删除左子树
|
||||||
|
DeleteTree(root->_left);
|
||||||
|
// 递归删除右子树
|
||||||
|
DeleteTree(root->_right);
|
||||||
|
|
||||||
|
// 删除当前节点
|
||||||
|
delete root;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef __TreeIterator<T, T&, T*> iterator;
|
||||||
|
typedef __TreeIterator<T, const T&, const T*> const_iterator;
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
Node* cur = _root;
|
||||||
|
while (cur && cur->_left)
|
||||||
|
{
|
||||||
|
cur = cur->_left;
|
||||||
|
}
|
||||||
|
return iterator(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return iterator(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
Node* cur = _root;
|
||||||
|
while (cur && cur->_left)
|
||||||
|
{
|
||||||
|
cur = cur->_left;
|
||||||
|
}
|
||||||
|
return const_iterator(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return const_iterator(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
RBTree(Node* root = nullptr)
|
||||||
|
: _root(root)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~RBTree()
|
||||||
|
{
|
||||||
|
DeleteTree(_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入
|
||||||
|
// 1. 空树。插入结点做根,把他变黑。
|
||||||
|
// 2. 插入红色节点,他的父亲是黑色的,结束。
|
||||||
|
// 3. 插入红色节点,他的父亲是红色的,可以推断他的祖父存在且一定为黑色。关键看叔叔
|
||||||
|
// a. 如果叔叔存在且为红,把父亲和叔叔变黑,祖父变红,继续往上处理。
|
||||||
|
// b. 如果叔叔存在且为黑,或者不存在。旋转(单旋 or 双旋)+ 变色
|
||||||
|
std::pair<iterator, bool> Insert(const T& data)
|
||||||
|
{
|
||||||
|
// 按照搜索树的规则进行插入
|
||||||
|
// 如果树为空,新节点直接作为根节点
|
||||||
|
if (_root == nullptr)
|
||||||
|
{
|
||||||
|
_root = new Node(data);
|
||||||
|
_root->_colour = BLACK; // 根节点是黑色的
|
||||||
|
return std::make_pair(iterator(_root), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入时使用比较器来比较键的大小,以支持不同的数据类型
|
||||||
|
KOfT koft;
|
||||||
|
Node* parent = nullptr;
|
||||||
|
Node* cur = _root;
|
||||||
|
while (cur)
|
||||||
|
{
|
||||||
|
if (koft(cur->_data) > koft(data))
|
||||||
|
{
|
||||||
|
parent = cur;
|
||||||
|
cur = cur->_left;
|
||||||
|
}
|
||||||
|
else if (koft(cur->_data) < koft(data))
|
||||||
|
{
|
||||||
|
parent = cur;
|
||||||
|
cur = cur->_right;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 如果键已经存在, 插入无效, 返回 false, 并且返回该键的迭代器
|
||||||
|
return std::make_pair(iterator(cur), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到位置, 根据父节点插入新节点
|
||||||
|
cur = new Node(data);
|
||||||
|
Node* newnode = cur;
|
||||||
|
if (koft(parent->_data) > koft(cur->_data))
|
||||||
|
{
|
||||||
|
parent->_left = cur;
|
||||||
|
cur->_parent = parent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent->_right = cur;
|
||||||
|
cur->_parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入后需要修复红黑树的性质
|
||||||
|
InsertFixUp(parent, cur);
|
||||||
|
|
||||||
|
return std::make_pair(iterator(newnode), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InsertFixUp(Node* parent, Node* cur)
|
||||||
|
{
|
||||||
|
// 调整结点颜色
|
||||||
|
// 新结点给红的还是黑的? 红色
|
||||||
|
// 1. 空树。插入结点做根, 把他变黑。
|
||||||
|
// 2. 插入红色节点, 他的父亲是黑色的, 结束。
|
||||||
|
// 3. 插入红色节点, 他的父亲是红色的, 可以推断他的祖父存在且一定为黑色。关键看叔叔
|
||||||
|
// a. 如果叔叔存在且为红, 把父亲和叔叔变黑, 祖父变红, 继续往上处理。
|
||||||
|
// b. 如果叔叔存在且为黑, 或者不存在。旋转(单旋 or 双旋)+ 变色
|
||||||
|
while (parent && parent->_colour == RED)
|
||||||
|
{
|
||||||
|
// 关键看叔叔
|
||||||
|
Node* grandfather = parent->_parent;
|
||||||
|
// 父节点是祖父节点的左子节点
|
||||||
|
if (grandfather->_left == parent)
|
||||||
|
{
|
||||||
|
Node* uncle = grandfather->_right;
|
||||||
|
|
||||||
|
// 情况1: uncle 存在, 且为红
|
||||||
|
if (uncle && uncle->_colour == RED)
|
||||||
|
{
|
||||||
|
parent->_colour = uncle->_colour = BLACK;
|
||||||
|
grandfather->_colour = RED;
|
||||||
|
|
||||||
|
// 继续向上处理
|
||||||
|
cur = grandfather;
|
||||||
|
parent = cur->_parent;
|
||||||
|
}
|
||||||
|
// 情况 2 or 情况 3 : uncle 不存在 or uncle 存在且为黑
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 情况 3 : 双旋 -> 变单旋
|
||||||
|
if (cur == parent->_right)
|
||||||
|
{
|
||||||
|
RotateL(parent);
|
||||||
|
std::swap(parent, cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第二种情况 (ps: 有可能是第三种情况变过来的)
|
||||||
|
RotateR(grandfather);
|
||||||
|
grandfather->_colour = RED;
|
||||||
|
parent->_colour = BLACK;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 父节点是祖父节点的右子节点
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Node* uncle = grandfather->_left;
|
||||||
|
|
||||||
|
// 情况1: uncle 存在, 且为红
|
||||||
|
if (uncle && uncle->_colour == RED)
|
||||||
|
{
|
||||||
|
parent->_colour = uncle->_colour = BLACK;
|
||||||
|
grandfather->_colour = RED;
|
||||||
|
|
||||||
|
// 继续向上调整
|
||||||
|
cur = grandfather;
|
||||||
|
parent = cur->_parent;
|
||||||
|
}
|
||||||
|
// 情况 2 or 情况 3 : uncle 不存在 or uncle 存在且为黑
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 情况 3 : 双旋 -> 变单旋
|
||||||
|
if (cur == parent->_left)
|
||||||
|
{
|
||||||
|
RotateR(parent);
|
||||||
|
std::swap(parent, cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第二种情况 (ps: 有可能是第三种情况变过来的)
|
||||||
|
RotateL(grandfather);
|
||||||
|
grandfather->_colour = RED;
|
||||||
|
parent->_colour = BLACK;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保证根节点为黑
|
||||||
|
_root->_colour = BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除操作
|
||||||
|
bool Erase(const K& key)
|
||||||
|
{
|
||||||
|
Node* nodeToDelete = _root;
|
||||||
|
KOfT koft;
|
||||||
|
|
||||||
|
// 1. 寻找要删除的节点
|
||||||
|
while (nodeToDelete)
|
||||||
|
{
|
||||||
|
if (koft(nodeToDelete->_data) > key)
|
||||||
|
{
|
||||||
|
nodeToDelete = nodeToDelete->_left;
|
||||||
|
}
|
||||||
|
else if (koft(nodeToDelete->_data) < key)
|
||||||
|
{
|
||||||
|
nodeToDelete = nodeToDelete->_right;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break; // 找到了要删除的节点
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 节点若不存在, 直接返回 false
|
||||||
|
if (nodeToDelete == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行删除操作
|
||||||
|
Node* parent, * child;
|
||||||
|
// 保存原节点的颜色,以便后续调整
|
||||||
|
Colour originalColour = nodeToDelete->_colour;
|
||||||
|
|
||||||
|
// 2. 处理删除节点的各种情况
|
||||||
|
if (nodeToDelete->_left == nullptr)
|
||||||
|
{
|
||||||
|
// 情况 1:没有左子节点
|
||||||
|
child = nodeToDelete->_right;
|
||||||
|
parent = nodeToDelete->_parent;
|
||||||
|
Transplant(nodeToDelete, nodeToDelete->_right);
|
||||||
|
}
|
||||||
|
else if (nodeToDelete->_right == nullptr)
|
||||||
|
{
|
||||||
|
// 情况 2:没有右子节点
|
||||||
|
child = nodeToDelete->_left;
|
||||||
|
parent = nodeToDelete->_parent;
|
||||||
|
Transplant(nodeToDelete, nodeToDelete->_left);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 情况 3:有两个子节点
|
||||||
|
// 找到右子树中的最小节点(后继节点)
|
||||||
|
Node* successor = Minimum(nodeToDelete->_right);
|
||||||
|
originalColour = successor->_colour;
|
||||||
|
child = successor->_right;
|
||||||
|
if (successor->_parent == nodeToDelete)
|
||||||
|
{
|
||||||
|
parent = successor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 后继节点有右子节点,用它的右子节点替换它
|
||||||
|
Transplant(successor, successor->_right);
|
||||||
|
successor->_right = nodeToDelete->_right;
|
||||||
|
successor->_right->_parent = successor;
|
||||||
|
parent = successor->_parent;
|
||||||
|
}
|
||||||
|
// 用后继节点替换删除节点
|
||||||
|
Transplant(nodeToDelete, successor);
|
||||||
|
successor->_left = nodeToDelete->_left;
|
||||||
|
successor->_left->_parent = successor;
|
||||||
|
successor->_colour = nodeToDelete->_colour; // 保持颜色不变
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除节点
|
||||||
|
delete nodeToDelete;
|
||||||
|
|
||||||
|
// 3. 修复红黑树的性质
|
||||||
|
// 如果删除的节点是黑色, 需要进行调整
|
||||||
|
if (originalColour == BLACK)
|
||||||
|
{
|
||||||
|
EraseFixUp(child, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* Minimum(Node* node)
|
||||||
|
{
|
||||||
|
while (node->_left != nullptr)
|
||||||
|
{
|
||||||
|
node = node->_left; // 一直向左走,直到找到最左节点
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transplant(Node* u, Node* v)
|
||||||
|
{
|
||||||
|
// 如果u是根节点,v成为新的根节点
|
||||||
|
if (u->_parent == nullptr)
|
||||||
|
{
|
||||||
|
_root = v;
|
||||||
|
}
|
||||||
|
// u是左子节点,用v替换它
|
||||||
|
else if (u == u->_parent->_left)
|
||||||
|
{
|
||||||
|
u->_parent->_left = v;
|
||||||
|
}
|
||||||
|
// u是右子节点,用v替换它
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u->_parent->_right = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 连接v与u的父节点
|
||||||
|
if (v != nullptr)
|
||||||
|
{
|
||||||
|
v->_parent = u->_parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EraseFixUp(Node* child, Node* parent)
|
||||||
|
{
|
||||||
|
while (child != _root && (child == nullptr || child->_colour == BLACK))
|
||||||
|
{
|
||||||
|
if (child == parent->_left)
|
||||||
|
{
|
||||||
|
Node* brother = parent->_right;
|
||||||
|
// 情况1: child 的兄弟节点 brother 是红色的
|
||||||
|
if (brother->_colour == RED)
|
||||||
|
{
|
||||||
|
brother->_colour = BLACK;
|
||||||
|
parent->_colour = RED;
|
||||||
|
RotateL(parent);
|
||||||
|
brother = parent->_right;
|
||||||
|
}
|
||||||
|
// 情况2: child 的兄弟节点 brother 是黑色的, 且 brother 的两个节点都是黑色的
|
||||||
|
if ((brother->_left == nullptr || brother->_left->_colour == BLACK) &&
|
||||||
|
(brother->_right == nullptr || brother->_right->_colour == BLACK))
|
||||||
|
{
|
||||||
|
brother->_colour = RED;
|
||||||
|
child = parent;
|
||||||
|
parent = child->_parent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 情况3: brother 是黑色的, 并且 brother 的左子节点是红色, 右子节点是黑色
|
||||||
|
if (brother->_right == nullptr || brother->_right->_colour == BLACK)
|
||||||
|
{
|
||||||
|
if (brother->_left)
|
||||||
|
{
|
||||||
|
brother->_left->_colour = BLACK;
|
||||||
|
}
|
||||||
|
brother->_colour = RED;
|
||||||
|
RotateR(brother);
|
||||||
|
brother = parent->_right;
|
||||||
|
}
|
||||||
|
// 情况4: brother 是黑色的, 并且 brother 的右子节点是红色
|
||||||
|
if (brother)
|
||||||
|
{
|
||||||
|
brother->_colour = parent->_colour;
|
||||||
|
parent->_colour = BLACK;
|
||||||
|
if (brother->_right)
|
||||||
|
{
|
||||||
|
brother->_right->_colour = BLACK;
|
||||||
|
}
|
||||||
|
RotateL(parent);
|
||||||
|
}
|
||||||
|
child = _root;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Node* brother = parent->_left;
|
||||||
|
// 情况1: child 的兄弟节点 brother 是红色的
|
||||||
|
if (brother->_colour == RED)
|
||||||
|
{
|
||||||
|
brother->_colour = BLACK;
|
||||||
|
parent->_colour = RED;
|
||||||
|
RotateR(parent);
|
||||||
|
brother = parent->_left;
|
||||||
|
}
|
||||||
|
// 情况2: child 的兄弟节点 parent 是黑色的, 且 brother 的两个节点都是黑色的
|
||||||
|
if ((brother->_left == nullptr || brother->_left->_colour == BLACK) &&
|
||||||
|
(brother->_right == nullptr || brother->_right->_colour == BLACK))
|
||||||
|
{
|
||||||
|
brother->_colour = RED;
|
||||||
|
child = parent;
|
||||||
|
parent = child->_parent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 情况3: brother 是黑色的, 并且 brother 的右子节点是红色, 左子节点是黑色
|
||||||
|
if (brother->_left == nullptr || brother->_left->_colour == BLACK)
|
||||||
|
{
|
||||||
|
if (brother->_right)
|
||||||
|
{
|
||||||
|
brother->_right->_colour = BLACK;
|
||||||
|
}
|
||||||
|
brother->_colour = RED;
|
||||||
|
RotateL(brother);
|
||||||
|
brother = parent->_left;
|
||||||
|
}
|
||||||
|
// 情况4: brother 是黑色的, 并且 brother 的左子节点是红色
|
||||||
|
if (brother)
|
||||||
|
{
|
||||||
|
brother->_colour = parent->_colour;
|
||||||
|
parent->_colour = BLACK;
|
||||||
|
if (brother->_left)
|
||||||
|
{
|
||||||
|
brother->_left->_colour = BLACK;
|
||||||
|
}
|
||||||
|
RotateR(parent);
|
||||||
|
}
|
||||||
|
child = _root;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
child->_colour = BLACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找节点
|
||||||
|
iterator& Find(const K& key)
|
||||||
|
{
|
||||||
|
KOfT koft;
|
||||||
|
Node* cur = _root;
|
||||||
|
while (cur)
|
||||||
|
{
|
||||||
|
if (koft(cur->_data) > key)
|
||||||
|
{
|
||||||
|
cur = cur->_left;
|
||||||
|
}
|
||||||
|
else if (koft(cur->_data) < key)
|
||||||
|
{
|
||||||
|
cur = cur->_right;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return iterator(cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iterator(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否是红黑树
|
||||||
|
bool IsRBTree()
|
||||||
|
{
|
||||||
|
Node* root = _root;
|
||||||
|
|
||||||
|
// 空树也是红黑树
|
||||||
|
if (root == nullptr)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 判断跟是否是黑色的
|
||||||
|
if (root->_colour != BLACK)
|
||||||
|
{
|
||||||
|
std::cout << "根节点不是黑色" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取任意一条路径上黑色节点的数量
|
||||||
|
size_t blackCount = 0;
|
||||||
|
Node* cur = _root;
|
||||||
|
while (cur)
|
||||||
|
{
|
||||||
|
if (cur->_colour == BLACK)
|
||||||
|
{
|
||||||
|
blackCount++;
|
||||||
|
}
|
||||||
|
cur = cur->_left;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否满足红黑树的性质, k 用来记录路径中黑色节点的个数
|
||||||
|
size_t k = 0;
|
||||||
|
return _IsRBTree(_root, k, blackCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _IsRBTree(Node* root, size_t k, size_t blackCount)
|
||||||
|
{
|
||||||
|
// 走到 nullptr 之后, 判断 k 和 blackCount 是否相等
|
||||||
|
if (root == nullptr)
|
||||||
|
{
|
||||||
|
// 最终黑色节点个数
|
||||||
|
if (blackCount != k)
|
||||||
|
{
|
||||||
|
std::cout << "违反性质四: 每条路径中黑色节点的个数必须相等" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统计黑色节点个数
|
||||||
|
if (root->_colour == BLACK)
|
||||||
|
{
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测当前节点与其父亲节点是否都为红色
|
||||||
|
Node* parent = root->_parent;
|
||||||
|
if (parent && parent->_colour == RED && root->_colour == RED)
|
||||||
|
{
|
||||||
|
std::cout << "违反了性质三: 红色节点的孩子必须是黑色" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _IsRBTree(root->_left, k, blackCount) && _IsRBTree(root->_right, k, blackCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Node* _root;
|
||||||
|
};
|
||||||
|
}
|
66
Windows_Set_Map/Set.hpp
Normal file
66
Windows_Set_Map/Set.hpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RBTree.hpp"
|
||||||
|
|
||||||
|
namespace Lenyiin
|
||||||
|
{
|
||||||
|
template <class K>
|
||||||
|
class Set
|
||||||
|
{
|
||||||
|
struct SetKeyOfT
|
||||||
|
{
|
||||||
|
const K& operator()(const K& k)
|
||||||
|
{
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
// 这里RBTree<K, K, SetKeyOfT>::iterator还没有实例化, 系统找不到, typename告诉编译器现在先不着急找
|
||||||
|
typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;
|
||||||
|
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return _tree.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return _tree.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
return _tree.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return _tree.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, bool> Insert(const K& key)
|
||||||
|
{
|
||||||
|
return _tree.Insert(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Erase(const K& key)
|
||||||
|
{
|
||||||
|
return _tree.Erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator& Find(const K& key)
|
||||||
|
{
|
||||||
|
return _tree.Find(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsRBTree()
|
||||||
|
{
|
||||||
|
return _tree.IsRBTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RBTree<K, K, SetKeyOfT> _tree;
|
||||||
|
};
|
||||||
|
}
|
31
Windows_Set_Map/Windows_Set_Map.sln
Normal file
31
Windows_Set_Map/Windows_Set_Map.sln
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.11.35312.102
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Windows_Set_Map", "Windows_Set_Map.vcxproj", "{2827E392-69FE-4ABC-84E6-BF5E25017C39}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{2827E392-69FE-4ABC-84E6-BF5E25017C39}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{2827E392-69FE-4ABC-84E6-BF5E25017C39}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{2827E392-69FE-4ABC-84E6-BF5E25017C39}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{2827E392-69FE-4ABC-84E6-BF5E25017C39}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{2827E392-69FE-4ABC-84E6-BF5E25017C39}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{2827E392-69FE-4ABC-84E6-BF5E25017C39}.Release|x64.Build.0 = Release|x64
|
||||||
|
{2827E392-69FE-4ABC-84E6-BF5E25017C39}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{2827E392-69FE-4ABC-84E6-BF5E25017C39}.Release|x86.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {62904B4D-74CC-43CF-A22A-ED012FF3C1CF}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
140
Windows_Set_Map/Windows_Set_Map.vcxproj
Normal file
140
Windows_Set_Map/Windows_Set_Map.vcxproj
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>17.0</VCProjectVersion>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<ProjectGuid>{2827e392-69fe-4abc-84e6-bf5e25017c39}</ProjectGuid>
|
||||||
|
<RootNamespace>WindowsSetMap</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="Map.hpp" />
|
||||||
|
<ClInclude Include="RBTree.hpp" />
|
||||||
|
<ClInclude Include="Set.hpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Main.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
33
Windows_Set_Map/Windows_Set_Map.vcxproj.filters
Normal file
33
Windows_Set_Map/Windows_Set_Map.vcxproj.filters
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="源文件">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="头文件">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="资源文件">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="Map.hpp">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Set.hpp">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="RBTree.hpp">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Main.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
4
Windows_Set_Map/Windows_Set_Map.vcxproj.user
Normal file
4
Windows_Set_Map/Windows_Set_Map.vcxproj.user
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup />
|
||||||
|
</Project>
|
BIN
Windows_Set_Map/Windows_Set_Map/x64/Debug/Main.obj
Normal file
BIN
Windows_Set_Map/Windows_Set_Map/x64/Debug/Main.obj
Normal file
Binary file not shown.
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project>
|
||||||
|
<ProjectOutputs>
|
||||||
|
<ProjectOutput>
|
||||||
|
<FullPath>E:\Git 仓库\公开仓库\9_Set_Map\Windows_Set_Map\x64\Debug\Windows_Set_Map.exe</FullPath>
|
||||||
|
</ProjectOutput>
|
||||||
|
</ProjectOutputs>
|
||||||
|
<ContentFiles />
|
||||||
|
<SatelliteDlls />
|
||||||
|
<NonRecipeFileRefs />
|
||||||
|
</Project>
|
BIN
Windows_Set_Map/Windows_Set_Map/x64/Debug/Windows_Set_Map.ilk
Normal file
BIN
Windows_Set_Map/Windows_Set_Map/x64/Debug/Windows_Set_Map.ilk
Normal file
Binary file not shown.
@ -0,0 +1,2 @@
|
|||||||
|
Main.cpp
|
||||||
|
Windows_Set_Map.vcxproj -> E:\Git 仓库\公开仓库\9_Set_Map\Windows_Set_Map\x64\Debug\Windows_Set_Map.exe
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
E:\Git 仓库\公开仓库\9_Set_Map\Windows_Set_Map\Main.cpp;E:\Git 仓库\公开仓库\9_Set_Map\Windows_Set_Map\Windows_Set_Map\x64\Debug\Main.obj
|
@ -0,0 +1,2 @@
|
|||||||
|
PlatformToolSet=v143:VCToolArchitecture=Native64Bit:VCToolsVersion=14.41.34120:TargetPlatformVersion=10.0.22000.0:
|
||||||
|
Debug|x64|E:\Git 仓库\公开仓库\9_Set_Map\Windows_Set_Map\|
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
|||||||
|
^E:\GIT 仓库\公开仓库\9_SET_MAP\WINDOWS_SET_MAP\WINDOWS_SET_MAP\X64\DEBUG\MAIN.OBJ
|
||||||
|
E:\Git 仓库\公开仓库\9_Set_Map\Windows_Set_Map\Windows_Set_Map\x64\Debug\Windows_Set_Map.ilk
|
Binary file not shown.
BIN
Windows_Set_Map/Windows_Set_Map/x64/Debug/vc143.idb
Normal file
BIN
Windows_Set_Map/Windows_Set_Map/x64/Debug/vc143.idb
Normal file
Binary file not shown.
BIN
Windows_Set_Map/Windows_Set_Map/x64/Debug/vc143.pdb
Normal file
BIN
Windows_Set_Map/Windows_Set_Map/x64/Debug/vc143.pdb
Normal file
Binary file not shown.
BIN
Windows_Set_Map/x64/Debug/Windows_Set_Map.exe
Normal file
BIN
Windows_Set_Map/x64/Debug/Windows_Set_Map.exe
Normal file
Binary file not shown.
BIN
Windows_Set_Map/x64/Debug/Windows_Set_Map.pdb
Normal file
BIN
Windows_Set_Map/x64/Debug/Windows_Set_Map.pdb
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user