首页 > 编程语言 >【STL和泛型编程】3. set、map分析(及typename起源)

【STL和泛型编程】3. set、map分析(及typename起源)

时间:2024-02-29 10:00:24浏览次数:23  
标签:map typedef set const Key iterator STL key type

前置知识:红黑树原理 【数据结构】7.平衡搜索树(AVL树和红黑树),红黑树的平衡性有利于 search 和 insert

  • 红黑树的迭代器
    • begin() 左侧
    • end() 右侧
    • 迭代顺序 5 6 7 8 10 11 12 13 15
    • 不能使用迭代器修改 Key 的值,例如将 6 改成 50 会破坏红黑树的性质

1. RB-tree

  在g++编译器中(4.9),rbtree在 <bits/stl_tree.h> 中定义

// Key: key; Value: Key+Data; KeyOfValue: 从Value中取出Key 注意这里的Value是Key和Data结合起来传入的类
// Compare: 比较Key大小的函数
template <class Key, class Value, class KeyOfValue, class Compare, class Allocated = alloc>
class _Rb_tree {
protected:
    typedef __rb_tree_node<Value> rb_tree_node;
public:
    typedef rb_tree_node* link_type;
protected:
    size_type node_count;    // 节点元素个数
    link_type header;        // 头节点指针,包括了Value, left, right, parent
    Compare key_compare;    // key的大小比较函数
};
  • 使用案例,该rbtree的key就是value,获取key的方式就是直接返回该元素
    • rbtree._M_insert_unique(5);  插入元素(无重复)
    • rbtree._M_insert_equal(5); 插入元素(可以重复),可以使用 .count(5) 计算数量
_Rb_tree<int, int, identity<int>, less<int>, alloc> rbtree;

// identity 类重载了括号,直接返回该元素本身
template <class T>
struct identity : public unary_function<T, T> {
    const T& operator()(const T& x) const { return x; }
};

// less 重载了括号,比较大小后返回元素
template <class T>
struct less : public binary_function<T, T, bool> {
    bool operator()(const T& x, const T& y) const
    { return x<y; }
};

2. set / multiset

  • set 提供遍历操作以及迭代器 iterator,可以使用 ++ite 进行遍历,并且得到排序后的数据
  • 无法使用迭代器修改元素值,修改值会导致破坏排序
  • set insert 调用无重复插入方法,multiset insert 调用可重复插入的方法
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set {
public:
    typedef Key key_type;
    typedef Key value_type;
    typedef Compare key_compare;
    typedef Compare value_compare;
prevate:
    typedef rb_tree<key_type, value_type, identity<value_type>, key_compare, Alloc> rep_type;
    rep_type t;    // 实际存储内容的红黑树
public:
    typedef typename rep_type::const_iterator iterator;    // 从set拿迭代器拿到的是 const_iterator,避免使用者使用迭代器修改元素
    // ...
};

 2.1 typename

typedef typename rep_type::const_iterator iterator; // STL源码的写法
typedef rep_type::const_iterator iterator; // 这样存在什么问题?

  首先看类作用域下操作符 MyClass::name 调用实际上有 3 种可能:以MyClass为例子来说,MyClass::A静态数据成员,MyClass::B静态成员函数,MyClass::C嵌套类型。由于MyClass是一个完整的定义,所以编译器完全可以推断出任意一个变量究竟是什么类型的。但还有一种可能,如果是T::name呢?

class MyClass{
    static int A;    // 静态变量A
    static int B();  // 静态成员函数B
    typedef int C;   // 嵌套类型C
}

  以foo函数为例子,一眼看下去它的含义是定义了T类中iterator的指针并起名为iter;如果传入的是ContainsAType则完全没有问题。但如果传入的是ContainsAnotherType则会出现问题,因为在该类中定义了静态整形变量,如果有一个全局整形变量iter,则翻译后这里就会变成一个乘法表达式,二义性是不能被允许的,所以委员会引入了typename关键字

  模板类型实例化前,并不知道它具体是哪个类型,而使用typename 可以直接告诉编译器这是一个类型,而非成员对象。

struct ContainsAType {
    struct iterator { /* ... */ }
};

struct ContainsAnotherType {
    static int iterator;
};

template <class T>
void foo() {
    T::iterator * iter;
    // ...
}

3. map / multimap

  • map 提供遍历操作以及迭代器 iterator,可以使用 ++ite 遍历排序后的数据
  • 无法使用迭代器修改 key,但允许修改 data(源码实现很巧妙,借用 pair<const Key, T> 实现)
  • map insert 调用无重复插入方法,multimap insert 调用可重复插入方法
    • insert(pair<long, string>(1, "HelloWorld"); 插入时应该插入一个pair
    • map[5] = "Hi Five";  // 插入 (5, "Hi Five")
    • map[5];  // 这个比较有趣,标准规定,如果没有 Key 5, 则创建 Key 5 和 string 的默认值
    • 在multimap 不可以使用 multimap[]进行插入
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map {
public:
    typedef Key key_type;
    typedef T data_type;
    typedef T mapped_type;
    typedef pair<const Key, T> value_type;    // value 是 const Key 和 Data 的结合
    typedef Compare key_compare;
prevate:
    typedef rb_tree<key_type, value_type, select1st<value_type>, key_compare, Alloc> rep_type;
    rep_type t;    // 实际存储内容的红黑树
public:
    typedef typename rep_type::iterator iterator;    // 因为pair中是const key, 从而实现只能修改value不能修改key
    // ...
};

 

标签:map,typedef,set,const,Key,iterator,STL,key,type
From: https://www.cnblogs.com/stux/p/18040876

相关文章

  • 神中神之【Map】遍历操作
    前言首先插入几个值方便操作'''Map<Integer,String>map=newHashMap<>();map.put(1,"A");map.put(2,"B");map.put(3,"C");//System.out.println(map);->{1=A,2=B,3=C}调用tostring'''//......
  • reset
    link考虑随机游走状的高斯消元:对于题目中的一个可重集\(S\),令\(f_S\)表示,从\(S\)开始期望多少天后走到和\(\gem\)的集合。则有两种转移,分别对应摆烂或不摆烂:(定义多重集减一个数为该集合去除一个该数,\(\min\{S\}\)为多重集中最小元素,\(S\cupT\)为两个多重集并)\[f_S......
  • 假期vue学习笔记15 求和mapstate_mapgetter
     importVuefrom'vue'importAppfrom'./App.vue'importstorefrom'./store'Vue.config.productionTip=falsenewVue({  el:'#root',  render:h=>h(App),  store,  beforeCreate(){    Vue.......
  • golang中关于map的value类型定义为函数类型时(方法值)的一点点思考
    文章的内容仅仅是自己关于map的value类型定义为函数类型时的一点点思考,如有不对的地方,请不吝赐教。学习过后才知道叫做方法值。1、起因最近在看老项目代码时,看到了一段类似于下面的定义,最开始看到的时候,对于LotMap的用法比较疑惑,为什么mapvalue定义的函数类型是func(r......
  • Openlayer加载mapboxgl矢量图层
    注意Openlayer的版本Openlayer是支持直接加载矢量图层的,如下图层会没有样式渲染<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0&q......
  • 数仓的等待视图中,为什么会有Hashjoin-nestloop
    本文分享自华为云社区《GaussDB(DWS)等待视图之Hashjoin-nestloop》,作者:Arrow0lf。1.业务场景众所周知,GaussDB(DWS)中有3种常见的join方式:HashJon/MergeJoin/NestLoop但在有一些场景中,等待视图中等待状态会显示为:HashJoin-nestloop,如下图所示。这种表示什么含义?2.基本原理......
  • STL-unordered_map,unordered_set模拟实现
    unordered_set#pragmaonce#include"28hashtable_container.h"namespacetest{//template<//classKey,//unordered_set::key_type/value_type//classHash=hash<Key>,//unordered_s......
  • STL-unordered_hashtable模拟实现
    #pragmaonce#include<vector>#include<string>#include<iostream>usingstd::cout;usingstd::endl;usingstd::pair;usingstd::make_pair;namespaceHashBucket{template<classT>structHashNode{HashNode......
  • STL-RBT_map,set模拟实现
    set#include"26RBT_container.h"namespacetest{//set通过普通迭代器使用const迭代器实现限制key不能被修改template<classK>classset{private:structsetKeyOfT//命名?返回RBT的类型T接收的set的key{constK&......
  • STL-bitset模拟实现
    #include<time.h>#include<string>#include<vector>#include<iostream>usingstd::cout;usingstd::endl;usingstd::string;namespacetest{/**位图概念*所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。......