zoukankan      html  css  js  c++  java
  • STL 容器适配器小结

    容器适配器(container adapter)

    注:内容主要总结自 C++ Standard Library 第二版。

    C++ 标准库还包含一些满足特殊需求而设计的容器,它们提供非常简单的接口。这些容器被归类为容器适配器,它们是由标准 STL 容器构建的。有三种标准的容器适配器:

    • stack
    • queue
    • priority_queue

    还有一种特殊的容器适配器:

    • bitset

    1.1  stack(堆栈)

    位于头文件 stack 中,定义如下:

    namespace std {
       template <class T,
                 class Container = deque<T> >
                 class stack;
    }
    • 第一个 template 参数代表元素类型
    • 带有默认值的第二个 template 参数用来定义 stack 内部用来存放元素的实际容器,默认为 deque

    核心接口

    • push ()
    • pop ()
    • top ()

    详细定义

    namespace std {
          template <class T, class Container = deque<T> >
          class stack {
            public:
              typedef typename Container::value_type value_type;
              typedef typename Container::size_type  size_type;
              typedef          Container             container_type;
              protected:
                Container c;     // container
              public:
                explicit stack(const Container& = Container());
    
                bool        empty() const             { return c.empty(); }
                size_type   size()    const           { return c.size(); }
                void push   (const value_type& x)     { c.push_back(x); }
                void        pop()                     { c.pop_back(); }
                value_type& top()                     { return c.back(); }
                const value_type& top() const         { return c.back(); }
          };
    
          template <class T, class Container>
            bool operator==(const stack<T, Container>&,
                            const stack<T, Container>&);
          template <class T, class Container>
            bool operator< (const stack<T, Container>&,
                            const stack<T, Container>&);
          ...// (other comparison operators)
    }

    从 protect 区域可以看出,类内部仅有一个 Container 类型的对象 c。仅适用该对象便可实现 stack <>。

    实际上我们也可以适用类似的方法(composition,组合)的方式,来通过 STL 容器实现自己的数据结构。

    1.2  queue(队列)

    位于头文件 queue 中,class queue 定义如下:

    namespace std {
           template <class T,
                     class Container = deque<T> >
           class queue;
    }
    • 第一个 template 参数代表元素类型
    • 带有默认值的第二个 template 参数用来定义 queue 内部用来存放元素的实际容器,默认为 deque

    核心接口

    实际上只要容器有 push_back ()、front ()、back ()、pop_front ()操作就可以作为 queue 的容器,在 queue 内部只是把这些操作转化而已: 

    • push () -- push_back ()
    • front () -- front ()
    • back () -- back ()
    • pop () -- pop_front ()

    详细定义

    namespace std {
           template <class T, class Container = deque<T> >
           class queue {
             public:
               typedef typename Container::value_type value_type;
               typedef typename Container::size_type size_type;
               typedef          Container            container_type;
             protected:
               Container c;     // container
             public:
               explicit queue(const Container& = Container());
    
               bool     empty() const              { return c.empty(); }
               size_type size() const              { return c.size(); }
               void     push(const value_type& x)  { c.push_back(x); }
               void     pop()                      { c.pop_front(); }
               value_type&      front()            { return c.front(); }
               const value_type& front()const      { return c.front(); }
               value_type&       back()            { return c.back(); }
               const value_type& back() const      { return c.back(); }
           };
    
           template <class T, class Container>
             bool operator==(const queue<T, Container>&,
                             const queue<T, Container>&);
           template <class T, class Container>
             bool operator< (const queue<T, Container>&,
                             const queue<T, Container>&);
             //(other comparison operators)
    }

    1.3  priority_queue(优先队列)

    位于头文件 queue 中,定义如下:

    namespace std {
           template <class T,
                     class Container = vector<T>,
                     class Compare = less<typename Container::value_type> >
           class priority_queue;
    }
    • 第一个 template 参数代表元素类型
    • 带有默认值的第二个 template 参数用来定义 priority_queue 内部用来存放元素的实际容器,默认为 vector
    • 带有默认值的第三个 template 参数定义“用来查找下一个最高优先级元素”的排序准则,默认以 < 作为比较标准(大顶堆)

    核心接口

    • push ()
    • top ()
    • pop ()

    只要容器支持 random-access iterator 和 front ()、push_back ()、pop_back (),就可以作为 priority_queue 的容器。由于 priority_queue 要用到 STL heap 算法,所以容器必须支持 random-access iterator。

    详细定义

    namespace std {
          template <class T, class Container = vector<T>,
                    class Compare = less<typename Container::value_type> >
          class priority_queue {
            public:
              typedef typename Container::value_type value_type;
              typedef typename Container::size_type  size_type;
              typedef          Container             container_type;
            protected:
              Compare comp; // sorting criterion
              Container c;  // container
            public:
              // constructors
            explicit priority_queue(const Compare& cmp = Compare(),
                                    const Container& cont = Container())
             : comp(cmp), c(cont) {
                make_heap(c.begin(),c.end(),comp);
            }
    
            template <class InputIterator>
            priority_queue(InputIterator first, InputIterator last,
                           const Compare& cmp = Compare(),
                           const Container& cont = Container())
             : comp(cmp), c(cont) {
                c.insert(c.end(),first,last);
                make_heap(c.begin(),c.end(),comp);
             }
    
             void push(const value_type& x); {
                c.push_back(x);
                push_heap(c.begin(),c.end(),comp);
             }
             void pop() {
                pop_heap(c.begin(),c.end(),comp);
                c.pop_back();
             }
    
             bool              empty() const { return c.empty(); }
             size_type         size() const  { return c.size(); }
             const value_type& top() const   { return c.front(); }
          };
    }

    从 protected 区域可以看出, priority_queue 类仅有成员 Container 对象和 Compare 比较函数。它的内部操作实际上转化为 STL heap 算法的操作,初始化、pop、push 等操作都在容器内部操作,随后调用 make_heap 算法建立或者调整堆。

    1.4  bitset

    定义于头文件 bitset 中:

    namespace std {
           template <size_t Bits>
           class bitset;
    }

    只有一个 template 参数用以指定 bit 的数量。注意该参数实际上是一个不带正负号的正数,而不是一个类型。

    常用接口

    operator [] 存取某特定位置的位
    test () 返回bool,标志某特定位置的位
    all 检查是否 all、any、none的位被设置为 true
    any
    none
    count 返回被设置为 true 的位的个数
    size 返回该 bitset 所能容纳的位数 
    set 设置某位为 true
    reset 设置某位为 false
    flip 设置某位为 !bit ,对该位值取非
    to_string () 转换为 string
    to_ulong () 转换为 unsigned long
    to_ullong () 转换为 unsigned long long
    #include <iostream>
    #include <bitset>
    #include <limits>
    #include <map>
    
    enum Color { red, yellow, green, blue, white, black,
        numColors };
    
    int main() {
        using namespace std;
    
        map<Color, string> mp;
        mp[red] = "red";
        mp[yellow] = "yellow";
        mp[green] = "green";
        mp[blue] = "blue";
        mp[white] = "white";
        mp[black] = "black";
    
        // create bitsetfor all bits/colors
        bitset<numColors> usedColors;
        //bitset<numColors> usedColors;使用该语句效果一样,因为枚举类型 numColors 对应的值为6
    
        // set bits for two colors
        usedColors.set(red);
        usedColors.set(blue);
    
        // print some bitset data
        cout << "bitfield of used colors: " << usedColors << endl;
        cout << "number of used colors: " << usedColors.count() << endl;
        cout << "bitfield of unused colors: " << ~usedColors << endl;
    
        // if any color is used
        if (usedColors.any()) {
            // loop over all colors
            for (int c = 0; c < numColors; ++c) {
                // if the actual color is used
                if (usedColors[(Color)c]) {
                        cout << "color: " << mp[(Color)c] << " was used!" << endl;  //此处 mp[key] 中的key必须转换为Color枚举类型,而不能期望自动转换
                }
            }
        }
    
        usedColors[red] = false;
        cout << "change red to unused: " << usedColors.test(red) << endl;
        usedColors.flip(red);
        cout << "change red to used: " << usedColors.test(red) << endl;
        usedColors.reset(red);
        cout << "change red to unused: " << usedColors.test(red) << endl;
    
        bitset<numeric_limits<unsigned short >::digits> bits(128);
    
        cout << "use numeric_limits<T>::digits : " << bits << endl;
        //cout << bitset<numeric_limits<unsigned short>::digits>(128) << endl;两者效果等同
        string s = bits.to_string();  //必须使用成员函数 to_string 而不是 std::to_string()
    
        cout << "bits to string: " << s << endl;
    
        unsigned long exchanged_val = bitset<64>(s).to_ulong();
        unsigned long val = bits.to_ulong();
        cout <<  "bitset to long: " << val << endl;
        cout << "string to bitset to unsigned long:" << exchanged_val <<endl;
    
        return 0;
    }

    输出结果:

    bitfield of used colors: 001001
    number of used colors: 2
    bitfield of unused colors: 110110
    color: red was used!
    color: blue was used!
    change red to unused: 0
    change red to used: 1
    change red to unused: 0
    use numeric_limits<T>::digits : 0000000010000000
    bits to string: 0000000010000000
    bitset to long: 128
    string to bitset to unsigned long:128

    用 bitset 表述二进制

       #include <bitset>
       #include <iostream>
       #include <string>
       #include <limits>
       using namespace std;
    
       int main()
       {
           /* print some numbers in binary representation
            */
           cout << "267 as binary short: "
                << bitset<numeric_limits<unsigned short>::digits>(267)
                << endl;
    
           cout << "267 as binary long: "
                << bitset<numeric_limits<unsigned long>::digits>(267)
                << endl;
    
           cout << "10,000,000 with 24 bits: "
                << bitset<24>(1e7) << endl;
           /* transform binary representation into integral number
            */
           cout << ""1000101011" as number: "
                << bitset<100>(string("1000101011")).to_ulong() << endl;
    }

    输出如下(取决于机器 short 和 long 的位数):

    267 as binary short:     0000000100001011
    267 as binary long:      00000000000000000000000100001011
    10,000,000 with 24 bits: 100110001001011010000000
    "1000101011" as number:  555

    操作符 << 针对bitset 的特别设计,允许将一个 bitset 打印为一个二进制串。如果需要存储为字符串,需要使用 bitset 提供的成员函数 to_string (),如:

    string s = bitset<32>(1234567).to_string();

    同样,也可以把字符串转换为一个 bitset:

    bitset<64>("10010010");

    然后调用 bitset 的成员函数 to_ullong (),使字符串转换为一个整数值:

    bitset<64>("10010010").to_ullong();
  • 相关阅读:
    Floyd最小环
    D
    C
    B
    HPU personal training
    D
    A
    简练网软考知识点整理-项目风险审计及风险评估
    简练网软考知识点整理-项目需求跟踪及需求跟踪矩阵
    简练网软考知识点整理-项目资源优化、资源平衡及资源平滑
  • 原文地址:https://www.cnblogs.com/icky1024/p/STL-containeradapter.html
Copyright © 2011-2022 走看看