【C++】-- STL之用红黑树模拟实现map和set(二)

简介: 【C++】-- STL之用红黑树模拟实现map和set

三、红黑树迭代器

map和set的迭代器的实现其实本质上是红黑树迭代器的实现,迭代器的实现需要定义模板类型、模板类型引用、模板类型指针。

1.红黑树中迭代器重命名

在红黑树中重命名模板类型、模板类型引用、模板类型指针,定义为public,外部就能使用iterator了:

1. template<class K, class T, class KeyOfT>
2. class RBTree
3. {
4.  typedef RBTreeNode<T> Node;
5. 
6. public:
7.  typedef __TreeIterator<T, T&, T*> iterator;//模板类型、模板类型引用、模板类型指针
8. 
9. //红黑树函数...
10. 
11. private:
12.   Node* _root;
13. };

2.正向迭代器定义

红黑树的迭代器的本质是对节点指针进行封装,所以迭代器中只有封装红黑树节点指针这一个成员变量 。正向迭代器:

1. template<class T,class Ref,class ptr>
2. struct __TreeIterator
3. {
4.  typedef RBTreeNode<T> Node;
5.  typedef __TreeIterator<T, Ref, ptr> Self;
6. 
7.  Node* _node;//成员变量
8. 
9. };

3.迭代器构造

用节点指针构造正向迭代器:

1.  //构造函数
2.  __TreeIterator(Node* node)
3.    :_node(node)
4.  {}

4.正向迭代器重载*

Ref对正向迭代器解引用,返回节点数据引用:

1.  //* 解引用,返回节点数据
2.  Ref Operator*()
3.  {
4.    return _node->_data;
5.  }

5.正向迭代器重载->

Ptr对正向迭代器使用->,返回节点数据指针:

1.  //-> 返回节点数据地址
2.  Ptr Operator->()
3.  {
4.    return &_node->_data;
5.  }

6.正向迭代器重载==

判断节点是否相同

1.  //判断两个迭代器是否相同
2.  bool operator==(const Self& s)
3.  {
4.    return _node == s._node;//判断节点是否相同
5.  }

7.正向迭代器重载!=

判断节点是否不同

1.  //判断两个迭代器是否不同
2.  bool operator!=(const Self& s)
3.  {
4.    return _node != s._node;//判断节点是否不同
5.  }

8.正向迭代器++

①当节点的右子树不为空时,++就要走到右子树的最左节点

②当节点的右子树为空时,++就要走到节点的父亲

1.  //红黑树迭代器的++也就是红黑树的++
2.  Self operator++()
3.  {
4.    //1.右子树不为空
5.    if (_node->_right)
6.    {
7.      //下一个访问的是右树的中序第一个节点(即右子树最左节点)。
8.      Node* left = _node->_right;
9. 
10.       //找最左节点
11.       while (left->_left)
12.       {
13.         left = left->_left;
14.       }
15.       _node = left;
16.     }
17.     else//2.右子树为空,下一个访问的就是当前节点的父亲
18.     {
19.       Node* cur = _node;
20.       Node* parent = cur->_parent;
21.       while (parent && cur == parent->_right)
22.       {
23.         cur = cur->_parent;
24.         parent = parent->_parent;
25.       }
26.       _node = parent;
27.     }
28. 
29.     return *this;
30.   }
31. };

9.正向迭代器--

①当节点的左子树不为空时,++就要走到左子树的最右节点

②当节点的左子树为空时,++就要走到节点的父亲

1.  //红黑树迭代器的--也就是红黑树的--
2.  Self operator--()
3.  {
4.    //1.左子树不为空
5.    if (_node->_left)
6.    {
7.      //下一个访问的是左树的中序左后节点(即做子树最右节点)。
8.      Node* right = _node->_left;
9. 
10.       //找最右节点
11.       while (right->_right)
12.       {
13.         right = right->_right;
14.       }
15.       _node = right;
16.     }
17.     else//2.左子树为空,下一个访问的就是当前节点的父亲
18.     {
19.       Node* cur = _node;
20.       Node* parent = cur->_parent;
21.       while (parent && cur == parent->_left)
22.       {
23.         cur = cur->_parent;
24.         parent = parent->_parent;
25.       }
26.       _node = parent;
27.     }
28. 
29.     return *this;
30.   }

10.红黑树中实现迭代器

实现begin( )找最左节点,end( )最后一个节点的下一个位置

1. template<class K, class T, class KeyOfT>
2. class RBTree
3. {
4.  typedef RBTreeNode<T> Node;
5. 
6. public:
7.  typedef __TreeIterator<T, T&, T*> iterator;//模板类型、模板类型引用、模板类型指针
8. 
9. //找最左节点
10.   iterator begin()
11.   {
12.     Node* left = _root;
13.     while (left && left->_left)
14.     {
15.       left = left->_left;
16.     }
17. 
18.     return iterator(left)//返回最左节点的正向迭代器
19.   }
20. 
21.   //结束
22.   iterator end()
23.   {
24.     return iterator(nullptr);
25.   }
26. 
27. private:
28.   Node* _root;
29. };

四、set模拟实现

调用红黑树对应接口实现set,插入和查找函数返回值当中的节点指针改为迭代器:

1. #pragma once
2. #include "RBTree.h"
3. namespace delia
4. {
5.  template<class K>
6.  class set
7.  {
8.    //仿函数,获取set的key
9.    struct SetKeyOfT
10.     {
11.       const K& operator()(const K& key)
12.       {
13.         return key;
14.       }
15.     };
16.   public:
17.     typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;
18. 
19.     //迭代器开始
20.     iterator begin()
21.     {
22.       return _t.begin();
23.     }
24. 
25.     //迭代器结束
26.     iterator end()
27.     {
28.       return _t.end();
29.     }
30. 
31.     //插入函数
32.     pair<iterator,bool> insert(const K& key)
33.     {
34. 
35.       return _t.Insert(key);
36.     }
37. 
38.     //查找
39.     iterator find(const K& key)
40.     {
41.       return _t.find(key);
42.     }
43.   private:
44.     RBTree<K, K, SetKeyOfT> _t;
45.   };
46. }

五、map模拟实现

调用红黑树对应接口实现map,插入和查找函数返回值当中的节点指针改为迭代器,增加operator[ ]的重载:

1. #pragma once
2. #include "RBTree.h"
3. namespace delia
4. {
5.  template<class K, class V>
6.  class map
7.  {
8.    //仿函数,获取map的first
9.    struct MapKeyOfT
10.     {
11.       const K& operator()(const pair<const K, V>& kv)
12.       {
13.         return kv.first;
14.       }
15.     };
16.   public:
17.     typedef typename RBTree<K, K, MapKeyOfT>::iterator iterator;
18. 
19.     //迭代器开始
20.     iterator begin()
21.     {
22.       return _t.begin();
23.     }
24. 
25.     //迭代器结束
26.     iterator end()
27.     {
28.       return _t.end();
29.     }
30. 
31.     //插入
32.     pair<iterator, bool> insert(const pair<const K, V>& kv)
33.     {
34.       return _t.Insert(kv);
35.     }
36. 
37.     //重载operator[]
38.     V& operator[](const K& key)
39.     {
40.       pair<iterator, bool> ret = insert(make_pair(key, V()));
41.       iterator it = ret.first;
42.       return it->second;
43.     }
44. 
45.     //查找
46.     iterator find(const K& key)
47.     {
48.       return _t.find(key);
49.     }
50. 
51.   private:
52.     RBTree<K, pair<const K, V>, MapKeyOfT> _t;
53.   };
54. }


相关文章
|
2天前
|
存储 Java API
【数据结构】map&set详解
本文详细介绍了Java集合框架中的Set系列和Map系列集合。Set系列包括HashSet(哈希表实现,无序且元素唯一)、LinkedHashSet(保持插入顺序的HashSet)、TreeSet(红黑树实现,自动排序)。Map系列为双列集合,键值一一对应,键不可重复,值可重复。文章还介绍了HashMap、LinkedHashMap、TreeMap的具体实现与应用场景,并提供了面试题示例,如随机链表复制、宝石与石头、前K个高频单词等问题的解决方案。
14 6
【数据结构】map&set详解
|
1月前
|
存储 安全 Java
java集合框架复习----(4)Map、List、set
这篇文章是Java集合框架的复习总结,重点介绍了Map集合的特点和HashMap的使用,以及Collections工具类的使用示例,同时回顾了List、Set和Map集合的概念和特点,以及Collection工具类的作用。
java集合框架复习----(4)Map、List、set
|
1月前
|
Java
【Java集合类面试二十二】、Map和Set有什么区别?
该CSDN博客文章讨论了Map和Set的区别,但提供的内容摘要并未直接解释这两种集合类型的差异。通常,Map是一种键值对集合,提供通过键快速检索值的能力,而Set是一个不允许重复元素的集合。
|
1月前
|
存储 JavaScript 前端开发
ES6新特性(四): Set 和 Map
ES6新特性(四): Set 和 Map
|
29天前
|
存储 Java 索引
|
2天前
|
编译器 C++
C++ 类构造函数初始化列表
构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。
42 30
|
16天前
|
存储 编译器 C++
C ++初阶:类和对象(中)
C ++初阶:类和对象(中)
|
1月前
|
存储 安全 编译器
【C++】类和对象(下)
【C++】类和对象(下)
【C++】类和对象(下)
|
16天前
|
C++
C++(十六)类之间转化
在C++中,类之间的转换可以通过转换构造函数和操作符函数实现。转换构造函数是一种单参数构造函数,用于将其他类型转换为本类类型。为了防止不必要的隐式转换,可以使用`explicit`关键字来禁止这种自动转换。此外,还可以通过定义`operator`函数来进行类型转换,该函数无参数且无返回值。下面展示了如何使用这两种方式实现自定义类型的相互转换,并通过示例代码说明了`explicit`关键字的作用。
|
16天前
|
存储 设计模式 编译器
C++(十三) 类的扩展
本文详细介绍了C++中类的各种扩展特性,包括类成员存储、`sizeof`操作符的应用、类成员函数的存储方式及其背后的`this`指针机制。此外,还探讨了`const`修饰符在成员变量和函数中的作用,以及如何通过`static`关键字实现类中的资源共享。文章还介绍了单例模式的设计思路,并讨论了指向类成员(数据成员和函数成员)的指针的使用方法。最后,还讲解了指向静态成员的指针的相关概念和应用示例。通过这些内容,帮助读者更好地理解和掌握C++面向对象编程的核心概念和技术细节。