C++学习笔记_20 适配器容器-priority_queue 2021-05-19

priority_queue 优先级队列
插入容器内的数据,按降序排列方式被取出
-最先取出的数据,是队列中,值最大的那个 

// C++学习笔记_20 适配器容器- priority_queue
//
#include<iostream>
#include<string>
#include<queue>
using namespace std;

class AAA
{
private:
    int x;
    int y;
public:
    AAA():x(0),y(0){}
    AAA(int a, int b) :x(a), y(b){}

    friend ostream& operator << (ostream& os, const AAA &A) 
	{
        os << "(" << A.x << ", " << A.y << ")";
        return os;
    }

    //二进制“ < ” : 没有找到接受“const AAA”类型的左操作数的运算符(或没有可接受的转换)
    //less 的 () 运算符重载函数,使用了 const 进行修饰 -- 常成员函数
    //const 修饰的成员函数,只能调用 const 修饰的成员函数
    //less 调用了 < 运算符函数,但是这里 没有使用 const 修饰
    //--》解决办法: 使用  const 修饰这个 < 运算符重载
    bool operator < (const AAA &A)  const{
        //比较 x 的大小,x 越小,AAA 越小
        return x < A.x;
    }
};

template<typename T>
class MyRule
{
public:
    //函数      :  返回值 函数名 (参数表)
    //运算符重载: 返回值 operator 运算符  (参数表)
    bool operator () (const T& a, const T& b) const
    {
        //return a > b; //一般使用 < 运算符进行比较
        return b < a;
    }
};

bool MyComp(int a, int b)
{
    return a > b;
}

bool MyCompA(const AAA &A1, const AAA& A2)
{
    //return A1 > A2; // > 符号为定义,要不要重新定义的 > 符号?
                      // 不需要, 我们可以使用 A2 < A1
                      // 其次,也是很重要的一点:我们定义了 < 符号
                      // 那么,所有的比较规则,都已经定义好了
                      // 也就是说 > , >=, <=, ==, != 都可以有 < 符号表示出来
                      // 再定义一个容易出冲突: 比如出现 A != A , A1 < A2 < A1 这种情况

    //注意 !(A1<A2) 和 A1>A2 是不等价的 !(A1<A2) 等价于 A1>=A2
    return A2 < A1;
}

void TestPriorityQueue()
{
    int arr[] = { 1, 3, 5, 7, 9, 8, 6, 4, 2, 0 };
    priority_queue<int>  iPriQue1;
    priority_queue<int>  iPriQue2(iPriQue1);

    //关于底层容器:默认 使用 vector 做底层容器
    //使用 list 作为底层容器, deque 作为底层容器 ?
    priority_queue<int, deque<int>>  iPriQue4;
    //priority_queue<int, list<int>>   iPriQue5;
    //优先级队列,需要使用树形结构,设计到找父子节点,这个需要可以随机访问的容器
    //list 不是随机访问容器,不能作为 priority_queue 的底层容器

    cout << "入队列:" << endl;
    //sizeof(arr): arr 总共占用多大空间
    //sizeof(arr[0]): 一个元素占用多大空间
    for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){
        cout << arr[i] << " ";
        iPriQue1.push(arr[i]);

        iPriQue4.push(i);
    }
    cout << endl;

    //empty(): 判空
    //size():  当前容器中元素个数
    cout << "出队列:" << endl;
    while (!iPriQue1.empty())  {//while(iPriQue1.size())
        cout << iPriQue1.top() << " ";  //注意,取队头元素和 stack 类似,而不是和 queue 类似
        //没有  front() 和  back()
        iPriQue1.pop(); //删除优先级队列第一个元素
    }
    cout << endl;

    while (!iPriQue4.empty()){
        cout << iPriQue4.top() << " ";
        iPriQue4.pop();
    }
    cout << endl << endl;

    //出队列总是从大到小出队列
    //优先级队列,会根据元素大小排序出队列 (先大后小)

    //能不能先小后大呢? ---- 必然可以
    /*
    template<class _Ty,
    class _Container = vector<_Ty>,
    class _Pr = less<typename _Container::value_type> >
    class priority_queue {};
    //优先级队列有三个模板参数:
    _Ty:   存储的元素类型
    _Container: 底层容器,默认值是 vector<_Ty>
    _Pr       : 排序规则,默认是 less<_Ty>
    */
    //less   是一个模板类 ,重载了 () 运算符   --》仿函数的类
    //使用方式:比如判断 int a, b 的大小
    int a = 10; 
    int b = 20;
    less<int>()(a, b); //判断是否  a < b
    //less           --》 模板类
    //less<int>      --》 具体类
    //less<int>()    --》 生成一个对象 (匿名对象)
    //less<int>()(a, b)  --》调用这个对象的 () 运算符重载
    //比如:class AAA --》 AAA()  生成一个 AAA类的对象
    //                --》 AAA(10,20) 生成一个 AAA 类的对象

    //我们可以自己定义仿函数,替代 less<T>
    //比如,写一个  MyRule 的类,里面重载 () 运算符,返回值和 less<T> 刚好相反
    priority_queue<int, vector<int>, MyRule<int>>  iPriQue3;
    //注意,第三个模板参数,是变量类型(具体类),不是模板类。
    // 对于模板类,需要实例化成具体类

    cout << "iPriQue3" << endl;
    cout << "入队列:" << endl;
    for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){
        cout << arr[i] << " ";
        iPriQue3.push(arr[i]);
    }
    cout << endl;

    cout << "出队列: " << endl;
    while (!iPriQue3.empty()){
        cout << iPriQue3.top() << " ";
        iPriQue3.pop();
    }
    cout << endl << endl;

    //另一种方式定义排序规则: 使用函数指针: MyComp 函数
    //MyComp 是一个函数指针变量
    //他的变量类型是: 入参是 (int, int) 返回值是 bool 的函数
    //          --- bool(*)(int,int)
    //把 MyComp 作为参数传入,作为 priority_queue 构造函数的入参
    priority_queue<int, vector<int>, bool(*)(int, int)>  iPriQue6(MyComp);

    cout << "iPriQue6" << endl;
    cout << "入队列:" << endl;
    for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){
        cout << arr[i] << " ";
        iPriQue6.push(arr[i]);
    }
    cout << endl;

    cout << "出队列: " << endl;
    while (!iPriQue6.empty()){
        cout << iPriQue6.top() << " ";
        iPriQue6.pop();
    }
    cout << endl << endl;

    priority_queue<string>  sPriQue;
    string sArr[] = { string("aaa"), string("bbb"), string("cccc") };
    sPriQue.push(sArr[2]);

    //那么:如果优先级队列中存储的是自定义对象呢
    // 比如上面的 AAA 对象
}

void TestAAA()
{
    int a[] = { 1, 2, 3, 4, 5, 6 };
    a[3];

    AAA  aArr[] = { AAA(), AAA(1, 2), AAA(2, 1), AAA(2, 2), AAA(1, 1), AAA(1, 3) };
    //也有这种写法 AAA aArr[] = { {}, {1, 2}, {2, 1}, .... } --> {1,2} 相当于 AAA(1,2)
    priority_queue<AAA>  aPriQue1;

    cout << "入队列:";
    for (int i = 0; i < sizeof(aArr) / sizeof(aArr[0]); i++){
        cout << aArr[i] << " ";

        //二进制“<”:“const AAA”不定义该运算符或到预定义运算符可接收的类型的转换
        //为什么插入 AAA 对象失败呢?
        //优先级队列,会调用 less<AAA>()(A1, A2) 来比较 两个 AAA 对象的大小
        // less 这个函数,return了  A1 < A2
        // 但是, AAA 对象,不能做小于符号比较,所以报错:“<”未定义
        //--》解决办法:重载 < 符号
        aPriQue1.push(aArr[i]);
    }
    cout << endl;

    cout << "出队列:";
    while (!aPriQue1.empty()){
        cout << aPriQue1.top() << " ";
        aPriQue1.pop();
        //根据比较规则,按照 x 的大小,从大到小输出
    }
    cout << endl << endl;

    //如果,我们想把AAA对象, 从小到大输出?
    priority_queue<AAA, vector<AAA>, bool(*)(const AAA&, const AAA&)>  aPriQue2(MyCompA);

    priority_queue<AAA, vector<AAA>, MyRule<AAA>> aPriQue3;

    cout << "aPriQue2, aPriQue3" << endl;
    cout << "入队列:";
    for (int i = 0; i < sizeof(aArr) / sizeof(aArr[0]); i++){
        cout << aArr[i] << " ";
        aPriQue2.push(aArr[i]);
        aPriQue3.push(aArr[i]);
    }
    cout << endl;

    cout << "出队列:";
    while (!aPriQue2.empty()){
        cout << aPriQue2.top() << " ";
        aPriQue2.pop();
        //根据比较规则,按照 x 的大小,从大到小输出
    }
    cout << endl;

    cout << "出队列:";
    while (!aPriQue3.empty()){
        cout << aPriQue3.top() << " ";
        aPriQue3.pop();
        //根据比较规则,按照 x 的大小,从大到小输出
    }
    cout << endl;
}

class BBB
{
private:
    int x;
public:
    friend class MyRuleB;
    BBB(int a) :x(a){}
};

class MyRuleB
{
public:
    bool operator () (const BBB &B1, const BBB &B2) const
    {
        return B1.x < B2.x;
    }
};

void  TestBBB()
{
    //BBB(1) --》 调用 BBB 的构造函数 BBB(int a) 生成一个 BBB 的对象
    //BBB 是一个类,就是一个变量类型,用于定义变量(对象)
    // int a; char b; BBB B;
    // 对象里面包含私有成员,我们定义构造函数,来初始化这些成员 BBB(int a):x(a){}
    // 那么 BBB B(1) ---> 调用构造函数 BBB(int a) 把 x 赋值为 1
    //               ---> 也就是说 B 这个对象,他的私有成员 x 的值是 1
    //     BBB(1)    ---> 直接类名后加(), 表示调用相应的构造函数,生成一个匿名对象
    // 或者说,我们可以进行赋值  BBB B = BBB(1)
    //     类似于 string("AAA"); string ss = string("Hello");

    BBB bArr[] = { BBB(1), BBB(3), BBB(2), BBB(4) };
    priority_queue<BBB, vector<BBB>, MyRuleB> bPriQue;

    //我们也可以不重载 < 符号,定义优先级队列的时候,直接传入 比较规则
    //但是这样写有个问题:比较规则需要定义成 BBB 的友元类,用于访问 BBB 的 私有成员
    //                    友元类存在安全性问题,在类中可以修改它的私有成员
    //当然,我们不想定义友元类也行,需要 写成员函数,返回 x 的值
    //  BBB::getVal(){return x;}  --> 写法比较麻烦,而且私有成员没有隐藏
    //一般情况下,还是建议重载 < 运算符 (使用 AAA 的做法)
    for (int i = 0; i < sizeof(bArr) / sizeof(bArr[0]); i++){
        bPriQue.push(bArr[i]);
    }  
}

int main()
{
    //TestPriorityQueue();
    TestAAA();
    TestBBB();
    system("pause");
	return 0;
}

//作业:
//定义 4 个优先级队列,存储string对象  {"AA", "BBBB", "CCC", "aaaa", "cc", "bbb"}
//要求:
//sPriQue1: 出队列的时候,按照字符串 ASCII 降序排列
//sPriQue2: 出队列的时候,按照字符串 ASCII 升序排列
//sPriQue3: 出队列的时候,按照字符串长度 升序排列(长度一样再比较 ASCII 升序)
//sPriQue4: 出队列的时候,按照字符串长度 降序排列(长度一样再比较 ASCII 降序)

猜你喜欢

转载自blog.csdn.net/lybc2019/article/details/117031596
今日推荐