【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. }


相关文章
|
1月前
|
算法
你对Collection中Set、List、Map理解?
你对Collection中Set、List、Map理解?
64 18
你对Collection中Set、List、Map理解?
|
7天前
|
存储 算法 安全
基于红黑树的局域网上网行为控制C++ 算法解析
在当今网络环境中,局域网上网行为控制对企业和学校至关重要。本文探讨了一种基于红黑树数据结构的高效算法,用于管理用户的上网行为,如IP地址、上网时长、访问网站类别和流量使用情况。通过红黑树的自平衡特性,确保了高效的查找、插入和删除操作。文中提供了C++代码示例,展示了如何实现该算法,并强调其在网络管理中的应用价值。
|
9天前
|
编译器 C语言 C++
【c++丨STL】list模拟实现(附源码)
本文介绍了如何模拟实现C++中的`list`容器。`list`底层采用双向带头循环链表结构,相较于`vector`和`string`更为复杂。文章首先回顾了`list`的基本结构和常用接口,然后详细讲解了节点、迭代器及容器的实现过程。 最终,通过这些步骤,我们成功模拟实现了`list`容器的功能。文章最后提供了完整的代码实现,并简要总结了实现过程中的关键点。 如果你对双向链表或`list`的底层实现感兴趣,建议先掌握相关基础知识后再阅读本文,以便更好地理解内容。
15 1
|
26天前
|
存储 缓存 安全
只会“有序无序”?面试官嫌弃的List、Set、Map回答!
小米,一位热衷于技术分享的程序员,通过与朋友小林的对话,详细解析了Java面试中常见的List、Set、Map三者之间的区别,不仅涵盖了它们的基本特性,还深入探讨了各自的实现原理及应用场景,帮助面试者更好地准备相关问题。
56 20
|
22天前
|
算法 C语言 C++
【c++丨STL】list的使用
本文介绍了STL容器`list`的使用方法及其主要功能。`list`是一种双向链表结构,适用于频繁的插入和删除操作。文章详细讲解了`list`的构造函数、析构函数、赋值重载、迭代器、容量接口、元素访问接口、增删查改操作以及一些特有的操作接口如`splice`、`remove_if`、`unique`、`merge`、`sort`和`reverse`。通过示例代码,读者可以更好地理解如何使用这些接口。最后,作者总结了`list`的特点和适用场景,并预告了后续关于`list`模拟实现的文章。
42 7
|
2月前
|
存储 编译器 C语言
【c++丨STL】vector的使用
本文介绍了C++ STL中的`vector`容器,包括其基本概念、主要接口及其使用方法。`vector`是一种动态数组,能够根据需要自动调整大小,提供了丰富的操作接口,如增删查改等。文章详细解释了`vector`的构造函数、赋值运算符、容量接口、迭代器接口、元素访问接口以及一些常用的增删操作函数。最后,还展示了如何使用`vector`创建字符串数组,体现了`vector`在实际编程中的灵活性和实用性。
72 4
|
25天前
|
存储 编译器 C语言
【c++丨STL】vector模拟实现
本文深入探讨了 `vector` 的底层实现原理,并尝试模拟实现其结构及常用接口。首先介绍了 `vector` 的底层是动态顺序表,使用三个迭代器(指针)来维护数组,分别为 `start`、`finish` 和 `end_of_storage`。接着详细讲解了如何实现 `vector` 的各种构造函数、析构函数、容量接口、迭代器接口、插入和删除操作等。最后提供了完整的模拟实现代码,帮助读者更好地理解和掌握 `vector` 的实现细节。
32 0
|
2月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
65 2
|
2月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
118 5
|
2月前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
120 4