bitset容器 集合 映射 再论迭代器

7.7 bitset容器

bitset可以看做是二进制位的容器,并提供了的相关操作函数。

7.7.1常用函数

(1)构造、赋值函数

bitset()

bitset(const bitset&):复制构造函数。

bitset(unsigned long val):由无符号长整型数构建位容器。

bitset(const string& str,size_t pos=0,size_t n=-1):由字符串创建位容器,

bitset& operator=(const bitset&):赋值操作。

(2)逻辑运算操作(与、或、非)。

bitset&operator&=(const bitset&);返回两个位容器“与”后的引用,并修改第个位容器值。

bitset& operatorl=(const bitset&);返回两个位容器“或”后的引用,并修改第个位容器值。

bitset& operator^=(const bitset&):返回两个位容器“异或”后的引用,并修改一个位容器值。

bitset& operator<<=(size_t):返回位容器左 size_t 位后的引用,并修改位容器值。

bitset& operator>>=(size_t): 返回容器右移 size_t 位后的引用,并修改位容器值。

bitset operator<<(size_t n)const: 返回位容器左 size_t 位后的备份。

bitset operator>>(size_t n)const: 返回位容器右 size_t 位后的备份。

bitset operator&(const bitset&,const bitset&):返回两个位容器“与”后的备份。

bitset operator|(const bitset&,const bitset&): 返回两个位容器“或”后的备份。

bitset operator^(const bitset&,const bitset&): 返回两个位容器“异或”后的备份。

(3)其他操作函数。

string to_String():位容器内容转化成字符串,方便显示

size_t size() const:返回位容器大小。

size_t count() const;返回设置1位个数。

bool any() const:是否有位设置1。

bool none() const:是否没有位设置 1。

bool test(size_t n) const:测试某位是否为1

bool operator[](size_t n) const: 随机访问位元素。

unsigned long to_ulong() const:若没有溢出异常,返回无符号长整型数

bitset& set():位容器所有位置 1。

bitset& flip():位容器所有位翻转。

bitset& reset():位容器所有位置0。

bitset& set(size_t n,int val=1):设置某位为1或0,默认为1。

bitset& reset(size_t n):复位某位为0。

bitset flip(size_t n):翻转某位

7.7.2 基本操作示例

例:定义为变量简单实例   bitset的初始化,位操作(次重点)

#include 

#include 

#include 

using namespace std;

int main() {

    bitset<5> s1; // 会初始化一个至少具有 5 位的内存空间,具有 5 位大小

    cout << "初始内存空间内容: " << s1.to_string() << endl;

    cout << "位容器空间 (size): " << s1.size() << "\t置 1 的个数 (count): " << s1.count() << endl;

    s1.set(2, true);//将 s1 的第 2 位设置为 1,即将第 2 位的值修改为 true

    cout << "第 2 位置 1 后 [set(2, true)]" << endl;

    cout << "内存空间内容: " << s1.to_string() << endl;

    s1[3] = 1;//将 s1 的第 3 位设置为 1

    cout << "第 3 位置 1 后 [s1[3] = 1]" << endl;

    cout << "内存空间内容: " << s1.to_string() << endl;

    s1.set();// 将 s1 的所有位设置为 1

    cout << "所有位置 1 后 [s1.set()]" << endl;

    cout << "内存空间内容: " << s1.to_string() << endl;

    bitset<16> s2(65535);//创建了一个具有 16 位的 bitset 对象 s2,初始值为长整型数 65535

//创建了一个具有 5 位的 bitset 对象 s3,使用字符串 "1111101" 的第 2 位开始的连续 5 位作为初始值

cout << "通过长整型数建立位容器: " << s2.to_string() << endl;

    bitset<5> s3(string("1111101"), 2, 5);

    cout << "通过字符申建立位容器: " << s3.to_string() << endl;



    return 0;

}

bitset容器 集合 映射 再论迭代器_第1张图片

本示主要区分&操作符的差别:

bitset& operator&=(const bitset&)返回当前位容器对象引用,因此当前位容器对象内容可能已发生了变化;

bitset operator&(const bitset&,const bitset&)返回位容器对象的备份,且传入的两个与操作位容器对象类型是 const,因此原容器内容一定不发生变化。依此类推,可知|,|=,^,^=,<<,<<=,>>,>>=的功能差别。

两个位容器对象进行各种操作,必须保证位容器大小相同,示例中容器大小均是5,所以可以进行操作。但如果 bitset<5>s1,bitset<6>s2,则s1,s2不能进行各种操作。

例:一个8位二进制数,要求高4位不变,低4 位取反

#include 

#include 

#include 

using namespace std;



int main() {

    bitset<8> b(string("11011101"));

    cout << "原位容器 b: " << b.to_string() << endl;

    for (int i = 0; i < 4; i++) {

        b.flip(i);//使用 flip(i) 函数将 b 的第 i 位翻转(即取反)

    }

    cout << "低4位翻转后,b: " << b.to_string() << endl;

    return 0;

}

bitset容器 集合 映射 再论迭代器_第2张图片

第二种思路:原位容器(固定内容“00001111”)行异或运算,也是可行的

bitset<8>b("11011101");

bitset<8>b2(”00001111");b^=b2;    

例:编制功能类统计学生每月出勤天数。

#include

#include

#include

#include

using namespace std;

// 定义模板类 MyAttend

template

class MyAttend {

    int month;

    bitset b;

public:

    // 构造函数,初始化月份和出勤情况

    MyAttend(int month, string strAttend) : month(month), b(strAttend) {}

    // 获取月份

    int GetMonth() { return month; }

    // 获取出勤天数

    int GetattendDays() { return b.count(); }

};

// 定义学生类 Student

class Student {

    string name;

    vector > v;

public:

    // 构造函数,初始化学生姓名

    Student(string name) {

        this->name = name;

    }

    // 添加出勤记录

    void Add(MyAttend<31>& m) {

        v.push_back(m);

    }

    // 显示出勤天数

    void ShowAttendDays() {

        cout << "姓名:" << name << endl;

        cout << "月份\t出勤天数" << endl;

        for (int i = 0; i < v.size(); i++) {

        //遍历容器 v 中的元素,依次获取每个元素的月份和出勤天数信息

            MyAttend<31>& m = v.at(i);

            int month = m.GetMonth();

            int days = m.GetattendDays();

            cout << month << "\t" << days << endl;

        } }

};

int main() {

    // 创建学生对象

    Student stud1("zhang");

    // 创建两个出勤记录对象

    string s1 = "1111100111110011111001111100111";

    string s2 = "1111100111110011111001111100";

    MyAttend<31> m1(1, s1);

    MyAttend<31> m2(2, s2);

    // 添加出勤记录

    stud1.Add(m1);

    stud1.Add(m2);

    // 显示出勤天数

    stud1.ShowAttendDays();

    return 0;

}

注意:MyAttend类成员变量定义了考勤月份变量month 及一个位容器,用位表示同学每天出勤情况,1表示出勤,表示缺席。在统计出勤天数函数 GetAttendDays 中,用位函数 count统计1的个数就可。学生出勤描述类 Student 中,一个学生对应多个月份出勤统计,因此定义了姓名成员变量及出勤的向量v,它是多个月份学生出勤信息的集合。

bitset容器 集合 映射 再论迭代器_第3张图片

例:已知n个整型数组,长度都是 10,元素都在[1,20]之间,且均递增排列,无重复数据。试利用 bitset 压缩这些数组,并存人文件中。

#include

#include

#include

using namespace std;

template

class MyNum {

public:

    bitset b;//用于存储数字集合的信息

public:

    void Set(int ary[], int nSize) {//用于设置数字集合的内容

        b.reset();

        for (int i = 0; i < nSize; i++) {

            b.set(ary[i] - 1, 1);

        } }

};

int main() {

    int a[6][10] = { {1,2,3,4,5,6,7,8,9,10},

                    {1,3,4,5,6,7,8,9,10,12},

                    {2,4,6,8,10,13,15,18,19,20},

                    {1,5,6,8,9,10,12,14,18,20},

                    {3,6,7,10,14,15,16,17,18,19},

                    {1,6,8,9,10,12,15,17,18,19} };

//通过 ofstream 对象 out,打开了一个名为 "d:\data.txt" 的文件

//使用二进制模式进行写入操作

    ofstream out("d:\\data.txt", ios::binary);

    MyNum<24> m;

    for (int i = 0; i < 6; i++) {

        m.Set(a[i], 10);//将 a[i] 数组的内容传递给 Set() 函数,同时传递数组大小为 10

        out.write((char*)&m.b, sizeof(m.b));

        cout << i << "\t";

    }

    out.close();

    return 0;

}

注意:

  1. 使用 out.write() 函数,将 m.b 的内容以二进制形式写入到文件中。write() 函数接受两个参数,第一个参数是要写入的数据的起始地址,通过 (char*)&m.b 将 m.b 的地址转换为 char* 类型。第二个参数是要写入的数据的长度,通过 sizeof(m.b) 获取 m.b 的长度
  2. MyNum中定义了位容器变量 b,成员函数 Set 负责把某整型数组转化为位容器表示。
  3. 在测试 main 中,a[6][10]是待压缩整型数组。主要注意这一行的理解:out, write((char *)&m.b,3)。由于位容器大小是 24,是3 个字节,因此 write 函数第2个参数是3表明要写人文件3个字节。m.b 表明是位容器量,位容器变量在内存中是一块连续的区域,和其他基本数据类型相仿,因此可用(char *) &mb这种形式。在某些情况下,(int*)&m.b、(float*)&m,b都是可能的。

从文件读取,并复原整型变量

ifstream in("d;\ldata.txt") ;

bitset<24>b;

while(!in.eof()){

  in.read((char * )&b,3);

  for(int i=0;i<24;i++)

  {

   if(b.test(i))

     {

   cout<

7.8集合

set、multiset都是集合类差别在于set 中不允许有重复元素multiset 中允许有重复元素

7.8.1 常用函数

(1) 构造函数。

set(const Pred& comp=Pred(),const A& al=A()):创建空集合。

set(const set& x):复制构造函数。

set(const value_type * first, const value_type * last,const Pred& comp-Pred(),const A& al=A()):复制[first,last)之间元素构成新集合。

multiset(const Pred& comp=Pred(),const A& al=A()):创建空集合。

multiset(const multiset& x): 复制构造函数。

multiset(const value_type * first, const value_type * last, const Pred& comp=Pred(),const A&al=A()):复制[first,last)之间元构成新集合。

(2)大小、判断空函数。

int size()const:返回容器元素个数。

boolempty()const:判断容器是否空,若返回 true,表明容器已空。

(3)增加、删除函数

pair insert(const value_type& x):插人元素x。

iterator insert(iterator it, const value_type& x): 在选代针 it 处插人元素x.

void insert(const value type * first, const value_type * last): 插入[first, last)间元素。

iterator erase(iterator it):删除选代指针 it 处元素。

iterator erase(iterator first,iterator last): 删除[first,last)迭代指针间元素

size_type erase(const Key& key):删除元素值等于 key 的元素。

(4)遍历函数。

iterator begin();返回首元的选代器指针。

iterator end():返回尾元素后的迭代器指针,而不是尾元素的迭代器指针。

reverse_iterator rbegin():返回尾元素的向迭代器指针,用于逆向遍历容器。

reverse_iterator rend():返回首元素前的逆向选代器指针,用于逆向遍历容器

(5)操作函数。

const_iterator lower_bound(const Key& key):返回容器元素大于等于 key 的迭代指针,否则返回 end()。

const_iterator upper_bound(const Key& key):返回容器元素大于 key 的迭代指针,否则返回 end()。

int count(const Key& key)const: 返回容器中元素值等于 key 的元素个数

pair equal_range(const Key& key) const; 返回容器中元素值等于 key 的迭代指针[first,last)。

const_iterator find(const Key& key) const:查找功能,返回元素值等于 key 的迭代器指针。

void swap(set&s):交换单集合元素

void swap(multiset& s):交换多集合元素

例:三种形成集合的方法

#include 
#include 
using namespace std;

void display(multiset& s) {
    multiset::iterator it = s.begin();//函数使用迭代器 it 遍历容器中的元素
    while (it != s.end()) {
        cout << *it << "\t";
        it++;
    }
    cout << endl;
}
int main() {
    int a[] = {5, 3, 9, 3, 7, 2, 9, 31};
    multiset myset;
    //使用 for 循环将数组中的元素逐个插入到 myset 容器中
    for (int i = 0; i < sizeof(a) / sizeof(int); i++) {//sizeof(a) / sizeof(int)得到数组中元素的个数
        myset.insert(a[i]);
    }  
    cout << "通过函数 insert(T t) 添加集合:" << endl;
    display(myset);
    
    cout << "通过复制构造函数 set(const set& x) 创建集合:" << endl;
    multiset myset2(myset);//将 myset 容器的内容复制到另一个 multiset 容器 myset2 中
    display(myset2);
    
    cout << "通过构造函数 set(const value_type* first, const value_type* last) 创建集合:" << endl;
    multiset myset3(a, a + sizeof(a) / sizeof(int));//创建一个新的 multiset 容器 myset3
    display(myset3);
    
    return 0;
}
  1. 可以看出multiset 集合默认是按升序排列的,这是由于源码中 multiset 模板参数中Pred=less决定了键值是按升序排列的。
  2. multiset 允许有重复元素,如果把multiset 全部换成 set,则结果为“23579”没有重复元素且也按升序排列。

bitset容器 集合 映射 再论迭代器_第4张图片

例: equal_range,pair,count,size 用法举例

#include 

#include 

using namespace std;



int main() {

    int a[] = {5, 3, 9, 3, 7, 2, 9, 3};

    set myset(a, a + sizeof(a) / sizeof(int)); //23579 创集合 myset用数组 a 的元素初始化

    multiset mymultiset(a, a + sizeof(a) / sizeof(int)); //23335799 创多重集合 mymultiset用数组 a 的元素初始化



    pair::iterator, set::iterator> rangeset; // 用于存储集合中等于 3 的元素的迭代器范围

    pair::iterator, multiset::iterator> rangemultiset; // 用于存储多重集合中等于 3 的元素的迭代器范围



    rangeset = myset.equal_range(3); // 返回集合 myset 中元素值等于 3 的迭代器范围

    rangemultiset = mymultiset.equal_range(3); // 返回多重集合 mymultiset 中元素值等于 3 的迭代器范围



    int nCount = myset.count(3); // 计算集合 myset 中元素值等于 3 的个数

    int nMultiCount = mymultiset.count(3); // 计算多重集合 mymultiset 中元素值等于 3 的个数



    cout << "set(搜索值等于 3 的元素):" << endl;

    for (set::iterator te = rangeset.first; te != rangeset.second; te++) {

        cout << *te << "\t";

    }

    cout << endl;

    cout << "个数是:" << nCount << endl;

    cout << "总共元素个数是:" << myset.size() << endl;



    cout << "multiset(搜索值等于 3 的元素):" << endl;

    for (multiset::iterator it = rangemultiset.first; it != rangemultiset.second; it++) {

        cout << *it << "\t";

    }

    cout << endl;

    cout << "个数是:" << nMultiCount << endl;

    cout << "总共元素个数是:" << mymultiset.size() << endl;



    return 0;

}

size 函数返回容器中总的元素个数,是无参函数   count 是有参函数,代表键值的元素个数。

bitset容器 集合 映射 再论迭代器_第5张图片

例:编一个集合类,包括并、交、差三种主要功能,不允许有重复数据。并用学生类 Student 加以测试。

#include

#include

#include

using namespace std;



class Student{

private:

    string m_strNO;

    string m_strName;

public:

    Student(string no, string name):m_strNO(no),m_strName(name){}

    bool operator< (const Student& s) const{//以便在集合中进行排序和比较

        int mark=m_strNO.compare(s.m_strNO);

        return mark < 0 ? true : false;

    }

    string GetNO() const {return m_strNO;}  

    string GetName() const {return m_strName;}}; /



ostream& operator<< (ostream& os,const Student& s){ //使得可以直接通过 cout 输出 Student 对象

    os << s.GetNO() << "\t" << s.GetName();

    return os;

}



template, class A=allocator >

class MySet : public set{// T 表示集合中元素的类型,Pred 表示元素的比较函数,默认为 less,A 表示分配器

public:

    MySet(const T* first, const T* last) : set(first, last){}//通过指针范围初始化集合

    void add(MySet& second){//将另一个 MySet 对象中的元素添加到当前集合

        typename set::iterator te;

        te = second.begin();

        while(te != second.end()){

            set::insert(*te);

            te++;

        }

    }

    void Intersection(MySet& second){//计算当前集合与另一个 MySet 对象的交集

        set mid;

        typename set::iterator te;

        te = set::begin();

        while(te != set::end()){

            if(second.find(*te) != second.end()){

                mid.insert(*te);

            }

            te++;

        }

        set::swap(mid);

    }

    void Difference(MySet& second){//计算当前集合与另一个 MySet 对象的差集

        set mid;

        typename set::iterator te;

        te = set::begin();

        while(te != set::end()){

            if(second.find(*te) == second.end()){

                mid.insert(*te);

            }

            te++;

        }

        set::swap(mid);

    }

    void Show(){//输出当前集合中的元素

        typename set::iterator te;

        te = set::begin();

        while(te != set::end()){

            cout << *te << endl;

            te++;

        }

    }

};



int main(){

    Student s[2] = {

        {Student("1001", "zhangsan")},

        {Student("1002", "lisi")}

    };

    Student t[3] = {

        {Student("1001", "zhangsan")},

        {Student("1003", "wangwu")},

        {Student("1004", "zhaoliu")}

    };

    MySet m1(s, s+2);

    MySet m2(t, t+3);

    cout << "原始 m1 集合:" << endl;

    m1.Show();

    cout << "原始 m2 集合:" << endl;

    m2.Show();

    cout << "m1 并 m2 为:" << endl;

    m1.add(m2);

    m1.Show();

    return 0;

}

注意:

  1. void add 的成员函数,并运算是通过系统提供的insert;它接受一个 MySet 对象 second 作为参数。函数的目的是将 second 集合中的元素添加到当前集合中。函数内部使用迭代器 te 遍历 second 集合,逐个将元素插入到当前集合中。
  2. Void Intersection 的成员函数,它接受一个 MySet 对象 second 作为参数。函数的目的是计算当前集合与 second 集合的交集,并将交集保留在当前集合中。函数内部创建了一个临时集合 mid,然后使用迭代器 te 遍历当前集合。对于当前集合中的每个元素,如果它也存在于 second 集合中,则将其插入到临时集合 mid 中。最后,使用 swap 函数交换临时集合 mid 和当前集合的内容,从而更新当前集合为交集。
  3. 必须重载 Student类中的 operator<运算符保证集合按照学号升序排列,也就是说除基本数据类型(int,float 等)外,集合中元素是类对象的,必须重类中的 operator<运算符。

bitset容器 集合 映射 再论迭代器_第6张图片

7.9 映射

常用的映射类是 map、multimap。在前述的各个容器中,仅保存着一样东西,但是在射中将会得到两样东西:关键字以及作为对关键字进行查询得到的结果值,即一对。map单映射中,Key 与 Value 是一对一的关系;

multimap 多映射中,Key与 Value 可以是一对多的关系。

pair第一个元素为key,第二个元素为value。Map也是以红黑树为底层实现机制。

7.9.1 常用函数

(1)构造函数

map(const Pred& comp=Pred(),const A& alA()):创建空映射

map(const map& x):复制构造函数。

map(const value_type * first, const value_type * last,const Pred&. comp-Pred() ,

const A&al=A()):复制[first,last)之间元素构成新映射。

multimap(const Pred& comp=Pred(),const A& al=A()): 创建空映射

multimap(const multimap& x):复制构造函数。

multimap(const value_type * first, const value_type * last, const Pred&. comp一Pred(),const A& al=A()):复制[first,last)之间元素构成新映射。

(2)大小、判断空函数。

int size() const:返回容器元素个数

bool empty()const:判断容器是否空,若返回 true,表明容器已空。

(3)增加、删除函数。

iterator insert(const value_type& x):插入元素 x

iterator insert(iterator it,const value_type& x);在迭代指针it 处插人元素x。

void insert(const value_type * first, const value type * last): 插入[first,last)间元素

iterator erase(iterator it):删除选代指针it 处元案。

iterator erase(iterator first,iterator last):删除[first,last)迭代指针间元素。

size_type erase(const Key& key):删除键值等于 key 的元案。

(4)遍历函数。

iterator begin(): 返回首元的迭代器指针。

iterator end():返回尾元素后的迭代器指针,而不是尾元素的迭代器指针。

reverse_iterator rbegin():返回尾元素的逆向选代器指针,用于逆向遍历容器

reverse_iterator rend():返回首元素前的逆向迭代器指针,用于逆向遍历容器

(5)操作函数。

const_iterator lower_bound(const Key& key):返回键值大于等于 key 的选代指

针,否则返回 end()。

const_iterator upper_bound(const Key& key):返回键值大于 key 的选代指针否则返回 end()。

int count(const Key& key) const:返回容器中键值等于 key 的元素个数。pair equal range(const Key& key) const; 返容器中键值等于 key 的选代指针[first,last)。const_iterator find(const Key& key)const;查找能,返回键值等于 key 的选代器

指针。

·void swap(map& s):交换单映射元素。

·void swap(multimap& s):交换多映射元素

(6)特殊函数。

reference operator](const Key& k);仅用在单映射 map类中可以以数组的形式给映射添加键-值对,并可返回值的引用。

7.9.2 基本操作示例

例: 两种常用的形成映射方法

#include 

#include 

#include 



using namespace std;

//遍历并显示 map 中的键值对

void Display(map& m) {

    map::iterator te = m.begin();

    while (te != m.end()) {//函数内部使用迭代器 te 来遍历 map

        cout << (*te).first << "\t" << (*te).second << endl;//分别获取键和值

        te++;

    }

}

int main() {

    map mymap;

    pair s1(1, "zhangsan");

    pair s2(3, "lisi");

    pair s3(6, "wangwu");

    pair s4(5, "zhaoliu");

    pair s5(1, "zhangsan");

    mymap.insert(s1);//键值对被插入到 mymap 中

    mymap.insert(s2);

    mymap.insert(s3);

    mymap.insert(s4);

    mymap.insert(s5);

    

    cout << "通过insert函数创建:" << endl;

    Display(mymap);



    cout << "通过复制构造函数创建:" << endl;

    map mymap2(mymap);

    Display(mymap2);

    

    return 0;

}

bitset容器 集合 映射 再论迭代器_第7张图片

1.map mymap2(mymap);

map 类型的复制构造函数被隐式地调用以创建 mymap2 对象。将 mymap 作为参数传递给 mymap2 的构造函数,从而使用 mymap 的内容创建了一个新的 map 对象 mymap2

2.可以看出 map 映射默认是按键值升序排列的,这是由于源码中 map 板参数中Pred=less决定了键值是按升序排列的

template, class Aallocator>

3.map不允许有重复键值,本例中有 5 个 pair 对象,且 s1 s5 有相同的键值,则map容器中只保留先存人的 s1对象,s5 则不能保存。如果把 map 换成 multimap,则可存s5了。

  1. 前面讲过 pair 是一个两个模板参数的板类,正好符合映射类中的“键-值”映射,,因此映射类要求保存的都是pair对象,在本示例 Display 显示函数中获得的迭代指针都是pair的(*te). first 及(*te).second 中的 first、second都是类中的成员变量。*first表示键值,*second表示映射的值

例:单映射map中operator[ ]用法(次重点)

#include 

#include 

#include 

using namespace std;

int main() {

    map mymap;

//方括号运算符将特定的日期字符串作为键,将对应的事件字符串作为值,将键值对插入到 mymap 中

    mymap["1-1"] = "元旦";

    mymap["5-1"] = "五一国际劳动节";

    mymap["7-1"] = "党的生日";

    mymap["8-1"] = "建军节";

    mymap["10-1"] = "国庆节";

//键 "1-1" 作为索引,获取其对应的值,将其赋值给字符串变量 s

    string s = mymap["1-1"];

    if (s.size() > 0) {

        cout << "1-1是:" << s << endl;

    } else {

        cout << "1-1没有登记" << endl;

    }

    

    s = mymap["6-1"];

    if (s.size() > 0) {

        cout << "6-1是:" << s << endl;

    } else {

        cout << "6-1没有登记" << endl;

    }

    return 0;

}

bitset容器 集合 映射 再论迭代器_第8张图片

例: 假设公司雇员属性有雇员姓名(没有重复)、部门名称。编制管理雇员的集合类,仅包括 (1)添加雇员功能,(2)显示功能,要求按部门名称升序排列,若部门名相同,则按姓名升序排列

#include

#include

#include

using namespace std;



class CEmployee{

private:

    string name;

    string departname;

public:

    CEmployee(string name, string departname){//初始化

        this->name = name;

        this->departname = departname;

    }

    bool operator< (const CEmployee& e) const {// 比较部门名称

        bool mark = (departname.compare(e.departname) < 0) ? true : false;

        if (departname.compare(e.departname) == 0) {//比较员工姓名 name

            mark = (name.compare(e.name) < 0) ? true : false;

        }

        return mark;

    }

    string GetName() const {

        return name;

    }

    string GetDepart() const {

        return departname;

    }

};

class CManage {

    multiset myset;//是一个多重集(multiset)类型,用于存储 CEmployee 对象

public:

//向 CManage 类的对象中添加员工对象。它接受一个 CEmployee 类型的参数 e,表示要添加的员工对象。

    bool Add(CEmployee e){

        myset.insert(e);

        return true;

    }

    void Show(){

//multiset::iterator 类型的迭代器 te,并将其初始化为 myset 的开始位置

        multiset::iterator te = myset.begin();

        while(te != myset.end()){

            const CEmployee& obj = *te;// *te 获取当前迭代器指向的 CEmployee 对象进行赋值

            cout << obj.GetDepart() << "\t" << obj.GetName() << endl;

            te++;

        }

    }

};

int main(){

    CEmployee el("zhangsan", "人力部");

    CEmployee e2("zhouqi", "装配部");

    CEmployee e3("wangwu", "制造部");

    CEmployee e4("zhaoliu", "制造部");

    CEmployee e5("lisi", "装配部");

    CEmployee e6("tianjiu", "制造部");

    

    CManage manage;

    manage.Add(el);

    manage.Add(e2);

    manage.Add(e3);

    manage.Add(e4);

    manage.Add(e5);

    manage.Add(e6);

    

    manage.Show();

    return 0;

}

bitset容器 集合 映射 再论迭代器_第9张图片

bitset容器 集合 映射 再论迭代器_第10张图片

bitset容器 集合 映射 再论迭代器_第11张图片

bitset容器 集合 映射 再论迭代器_第12张图片

bitset容器 集合 映射 再论迭代器_第13张图片

bitset容器 集合 映射 再论迭代器_第14张图片

bitset容器 集合 映射 再论迭代器_第15张图片

7.10 再论迭代器

1.插入迭代器(仅列出了构造函数,当然它们的模板参数都是容器 Cont )

   back_insert_iterator(Cont& x):容器后插选代器

   front_insert_iterator(Cont& x);容器前插选代器

   insert_iterator(Cont&x,Cont::iterator it):容器某指定位置插入迭代器

(1)插入迭代器所做的事情就是改变操作符 operator=的实现来替代赋值操作。构造函数都使用一个基本序列容器对象(vector list 等)作为其参数。

(2)back_insert_iterator 通过调用push_back 函数完成后插功能,即容器中有 push_back 函数才支持该选代器;

(3)front_insert_iterator通过调用push_front 函数完成前插功能,即容器中有 push_front 函数才支持该迭代器

(4)insert_iterator 通过调用 insert 函数完成插入操作,插入位置由 Cont::iterator it 选代指针决定,它对所有基本序列容器都适用。

(5)这两个迭代模板函数经常要用到。

back_insert_iterator back_inserter(Cont& x):返回容器x的后插迭代器指针

front_insert_iterator< Cont> front_inserter(Cont&. x):返容器的前插迭代器。

这两个函数的功能与 back_insert_iterator、front_insert_iterator 功能是一致的,只不过从编程角度来说可以少写一些代码。但要注意: back_inserter、front_inserter 是函数而back_insert_iterator,front_insert_iterator 是类

例:三个插人代器示例

#include

#include

#include

using namespace std;



void display(list& v){//接受一个引用参数 v,表示要显示的容器

//迭代器 it 初始化为 v 的开始位置(v.begin())

    for(list::iterator it=v.begin();it!=v.end();it++){

        cout<<*it<<"\t";//*it 获取当前迭代器指向的元素

    }

    cout< v;

    back_insert_iterator > backit(v);//迭代器 backit它被初始化为 v 的后插入位置

    *backit++=1;//将值 1 插入到 v 中

    *backit++=2;

    display(v);//1 2

    

   * back_inserter(v)=3;//值 3从后插入容器v中

    *back_inserter(v)=4;

    display(v);//1 2 3 4

    

    front_insert_iterator > frontit(v);//迭代器 frontit它被初始化为 v 的前插入位置

    *frontit++=5;

    *frontit++=6;

    display(v);//6 5 1 2 3 4

    

    front_inserter(v)=7;// 值 7从前插入容器v中

    front_inserter(v)=8;

    display(v);//8 7 6 5 1 2 3 4

    

    list::iterator it=v.begin();// it 遍历容器 v,将迭代器指向的位置移动到第 3 个元素处

    for(int i=0; i<3;i++){

        it++;}

//创建了一个 insert_iterator 类型的迭代器 insertit,它被初始化为 v 中迭代器 it 指向的位置

    insert_iterator > insertit(v,it);//

    *insertit++=9;//使用 *insertit++ 的方式,在迭代器指向位置之前插入值 9

    display(v);//8 7 6 9 5 1 2 3 4

    

    return 0;

}

本例是以 list 容器为示例的。由于有 push_back、push_front 函数,因此支持 backinsert_iterator、front_insert_iterator 迭代器,当然更支持 insert_iterator 迭代器

bitset容器 集合 映射 再论迭代器_第16张图片

2.逆向迭代器(仅列出了构造函数)

reverse_iterator(Ranit x);  Ranit 表示随机迭代器

reverse_bidirectional iterator(Bidit x);Bidit 表示双向选代器

逆向迭代器的主要目的是逆向遍历容器元素序列,它一般需要两个模板参数,第一个参数是迭代器类型,第二个参数是容器元素类型,比如创建一个 vector 整型元素逆向选代器为(其中假设v 表示已创建的 vector容器)

reverse_iterator::iterator, int> first(v. begin())

若容器中迭代器是随机迭代器,则应用reverse_iterator

若容器中迭代器是双向迭代器,则应用 reverse_bidirectional_iterator

例如,vector容器中代器是随机迭代器,则首选 reverse_iterator;list 容器中选代器是双向选代器,则首选 reverse bidirectional iterator

例:两个逆向迭代器展示

#include 

#include 

#include 

#include 

using namespace std;

template 

void reverse_display(reverse_iter first, reverse_iter last)

{

    while (first != last) {

        cout << *first << "\t";//while 循环遍历迭代器范围

        first++;

    }

    cout << endl;

}

int main()

{

    vector v;

    list l;

    for (int i = 1; i <= 5; i++) {//用 for 循环向这些容器中添加一些元素

        v.push_back(i); // 1 2 3 4 5

        l.push_back(i + 5); // 6 7 8 9 10

    }

    cout << "vector 元素逆向显示:" << endl;

    reverse_iterator::iterator, int >first(v.end());//first 初始化为 v 的末尾迭代器

    reverse_iterator :;iterator, int >last(v.begin());//last 初始化为 v 的起始迭代器

    reverse_display(first, last); // 5 4 3 2 1



    cout << "list 元素逆向显示:" << endl;

    reverse_bidirectional_iterator::iterator, int>first2(l.end());

reverse_bidirectional_iterator::iterator, int>last2(l.begin());

    reverse_display(first2, last2); // 10 9 8 7 6

    return 0;

}

注意:如果把对 vector 容器采用的reverse_iterator 改为 reverse_bidirectional_iterator,其他不变序结果仍然正确;但如果把 list 容器的 reverse.bidirectional_iterator 改为 reverse_iterator,则程序不能通过编译。

3.迭代器函数

有两个常用的迭代器函数

(1)advance:前移迭代器指针。

template

void advance(InIts it, Dist n);相当于InIt +=n,它是通过n步++InIt 得到最终迭代器指针的。

(2)distance:计算选代器起止指针间有多少元素。

template

ptrdiff_t diatance(InIt first, InIt last);

例: 已知整型 list 容器序列(1,2,3,4,5,6)。求:(1)元素 3 是第几个元素(2)显示 3前面第2个元素。

bitset容器 集合 映射 再论迭代器_第17张图片

#include 

#include 

#include 

#include 

using namespace std;



int main() {

    int a[] = {1, 2, 3, 4, 5, 6};

    list l(a, a + 6);//将数组中的元素复制到 list 容器 l 中

    cout << "list 容器元素:";

//copy 算法将 l 容器中的元素复制到输出流 cout 中

    copy(l.begin(), l.end(), ostream_iterator(cout, "\t"));

    cout << endl;

//使用 find 算法在 l 容器中查找值为 3 的元素,并将返回的迭代器赋值给 mid   

    list::iterator mid = find(l.begin(), l.end(), 3);

//distance 函数计算 l.begin() 到 mid 之间的距离

    cout << "元素 3 位置:" << distance(l.begin(), mid) << endl;//2

// advance 函数将迭代器 mid 向前移动 2 个位置   

    advance(mid, 2);

    cout << "元素 3 前面第2个元素是:" << *mid << endl;//5

    return 0;

}

7.11 习题 

1.、容器的成员函数rbegin()返回的反向迭代器指向的元素为(  )反向迭代器

 A. 第一个元素  B. 最后一个元素  C. 最后一个元素下一个   D. 第一个元素前一个

2.、执行完下列代码后,s1的内存空间内容为(  )

   bitset<5> s1;//创建了一个长度为5的bitset对象s1,即s1可以存储5个二进制位

   s1.set(3,true);//将s1的第4位(从右往左数,第一个位是0)设置为true

   s1[1]=1;//将s1的第2位设置为1

   A.00101     B. 10100      C. 01010    D. 10100

3、下面bitset操作后的b1.to_string()结果是?

bitset<6> b1;

b1.set(1, true);

b1[3] = 1;

A.010100  b)101000    c) 001010    d)111101 

4、执行完下列代码后,s1的内存空间内容为(B)

         bitset<5> s1;

         s1.set(4,true);

         s1.flIp(1);//翻转某位

01001     B. 10010      C. 01010    D. 10100

5、 下面代码执行后的结果为:()

map mymap; // 声明一个名为 mymap 的 map 容器,键类型为整数,值类型为字符串

mymap[60]="C"; // 将键值对 (60, "C") 插入到 mymap 中

mymap[70]="B"; // 将键值对 (70, "B") 插入到 mymap 中

mymap[80]="B+"; // 将键值对 (80, "B+") 插入到 mymap 中

mymap[90]="A"; // 将键值对 (90, "A") 插入到 mymap 中

map::iterator it1,it2; // 声明两个迭代器,用于在 map 中定位元素

it1=mymap.lower_bound(70); // 在 mymap 中查找第一个键值大于等于 70 的元素,并将其迭代器赋值给 it1

it2=mymap.upper_bound(70); // 在 mymap 中查找第一个键值大于 70 的元素,并将其迭代器赋值给 it2

cout<<(*it1).second<<" "<<(*it2).second<

A.B+ A      B. B B+     C. C B         D. B+ A

6、容器multiset的默认的排序方式是______升序_____。

7、set、map缺省的排序方式是怎样的?

set和map容器的默认排序方式是按照元素的升序进行排序。

对于set容器,它是一个有序的容器,其中的元素按照升序排列,且不允许出现重复元素。

对于map容器,它是一个键值对的有序容器,其中的键按照升序排列,且每个键对应唯一的值。

默认情况下,这些容器使用的是元素类型的<运算符来进行比较和排序。希望使用自定义的排序方式,可以通过提供自定义的比较函数或函数对象来实现。例如,可以使用std::greater或自定义的比较函数作为set或map的第二个模板参数,以便进行降序排序。

8、 hash_map和map的区别在哪里?底层实现:

构造函数hash_map需要hash函数,等于函数;map只需要比较函数(小于函数).存储结构hash_map采用hash表存储,map一般采用 红黑树(RB Tree) 实现。因此其memory数据结构是不一样的。

hash_map 使用哈希表作为底层实现,通过哈希函数将键映射到桶(bucket)中。map 使用二叉搜索树作为底层实现,保持键有序。hash_map 的查找效率通常比 map 更高,因为哈希表的查找时间复杂度接近 O(1),只需进行一次哈希计算和少量的比较操作。map 的查找效率为 O(log n),需要进行二叉搜索树的遍历和比较操作。hash_map 不保证键的顺序,存储和访问键值对的顺序是无序的。map 保持键的有序性,存储和访问键值对的顺序是按照键的比较结果进行排序的。hash_map 允许存在重复的键,但每个键只能对应一个值。map 不允许存在重复的键,每个键只能对应一个值。如果插入了相同的键,则后续的插入操作会覆盖原有键的值。hash_map 在存储大量数据时可能需要更多的内存,因为哈希表需要额外的桶来存储冲突的元素。map 的内存占用相对较小,只需要存储键和值的节点。

9、 为何map和set的插入删除效率比用其他序列容器高?

map 和 set 的插入和删除效率相对较高主要是因为它们的底层实现采用了平衡二叉搜索树(通常是红黑树)来维护元素的有序性。这种数据结构具有以下特点,使得插入和删除的效率相对较高

你可能感兴趣的:(C++STL大三上,c++,学习,数据结构,开发语言)