map与set的基本应用

map与set的使用与原理


set

这里写图片描述
一种底层为二叉搜索树中红黑树的C++标准容器,其模板参数有三个: T(存储在容器中的关键词的数据类型)、Compare((提供比较元素的函数决定元素在容器中的相对位置)、Alloc(存储管理设备)。

成员变量

这里写图片描述

成员函数

这里写图片描述
这里写图片描述

这里对set的部分函数功能进行测试说明
首先,进行基本的 添加数据、迭代器的建立与使用。

#include<iostream>
using namespace std;
#include<set>
void TestSet()
{
    set<int> s1;
    s1.insert(5);
    s1.insert(2);
    s1.insert(0);
    s1.insert(1);
    s1.insert(6);
    set<int>::iterator it1 = s1.begin();
    while (it1 != s1.end())
    {
        cout << *it1 << " ";
        ++ it1;
    }
    cout << endl;
}
int main()
{
    Test();
    return 0;
}

调试运行后结果显示为:
这里写图片描述

set中迭代器的++与–重载使用的是 中序遍历 进行移动,从而我们打印时得到一个顺序的结果,而当我们改变Compare,进行一个greater的重载并手动调用时,可实现降序的打印

typedef set<int,greater<int>> Set;
void TestSet()
{
    Set s1;
    s1.insert(5);
    s1.insert(2);
    s1.insert(0);
    s1.insert(1);
    s1.insert(6);

    Set::iterator it1 = s1.begin();
    while (it1 != s1.end())
    {
        cout << *it1 << " ";
        ++ it1;
    }
    cout << endl;
}

这里写图片描述

并且,set还具有 防冗余功能,当对6进行重复插入时

    Set s1;
    s1.insert(5);
    s1.insert(2);
    s1.insert(0);
    s1.insert(1);
    s1.insert(6);
    s1.insert(6);
    s1.insert(6);
    s1.insert(6);

这里写图片描述

仍然只有一个6被记录,这里是由于Insert的返回值为 pair类型

这里写图片描述

pair为一个具有两个模板参数的结构体

这里写图片描述
在进行插入时,若在原容器中查到了当前添加内容,则pair中第二个参数会返回false表示已经存在一个当前内容。
而我们也可以看到Insert中也存在两个重载,分别 可以进行指定位置插入并返回一个指向位置的定位器、特定区间插入,将两哥迭代器中的内容插入;

int pos = 10;
    for (int pos = 0; pos < 14; pos++)
        s1.insert(s1.end()--, pos);

这里写图片描述

Set s1;
    s1.insert(5);
    s1.insert(2);
    s1.insert(0);
    s1.insert(1);
    s1.insert(6);
    vector<int> v1;
    v1.insert(v1.begin(),99);
    v1.insert(v1.begin(), 98);
    v1.insert(v1.begin(), 97);
    s1.insert(v1.begin(), v1.end());

这里写图片描述

map

map与set有很多相同之处,因此这里着重介绍两者的差异
map存储的为一对数据K,V,而set为一个数据K。

void TestMap()
{
    map<string, int> m1;
    m1.insert(pair<string, int>("const", 0));
    m1.insert(pair<string, int>("set", 0));
    m1.insert(pair<string, int>("air", 0));
    m1.insert(pair<string, int>("map", 0));
    map<string, int>::iterator it1 = m1.begin();
    while (it1 != m1.end())
    {
        cout << it1->first << ":" << it1->second << endl;
        ++it1;
    }

}
int main()
{
    TestMap();
    return 0;
}

这里写图片描述

也因此map在使用是可以重复输入,将 多次出现的数据次数记以进第二个参数位置 ,我们可以进行一些统计工作,譬如单词出现的次数:

①使用find函数,当发现已经存在数据时进行加一

string str[] = { "one", "two", "four", "four", "two", "four", "four" };
    map<string, int> CountMap;
    for (size_t i = 0; i < sizeof(str) / sizeof(str[0]); i++)
    {
        map<string, int>::iterator it = CountMap.find(str[i]);
        if (it != CountMap.end())
            (*it).second++;
    }

当然我们在set中曾提过,Insert的返回值也为一对数据切插入失败时会在第二个数据返回false,由此进行优化:
②利用Insert的返回值

void TestMap()
{
    string str[] = { "one", "two", "four", "four", "two", "four", "four" };
    map<string, int> CountMap;
    pair<map<string, int>::iterator, bool> ret;
    for (size_t i = 0; i < sizeof(str) / sizeof(str[0]);i++)
    {
        ret = CountMap.insert(pair<string,int>((str[i]), 1));
        if (ret.second == false)
            ret.first->second++;
    }

    map<string, int>::iterator it1 = CountMap.begin();
    while (it1 != CountMap.end())
    {
        cout << it1->first << ":" << it1->second << endl;
        ++it1;
    }
}

int main()
{
    TestMap();
    return 0;
}

这里写图片描述

然而在map中,已经对这种操作进行了整理,放在了 [ ]的重载中,其底层实现与我们的第二种方法完全一致

这里写图片描述
这里写图片描述
③使用[ ]的重载

string str[] = { "one", "two", "four", "four", "two", "four", "four" };
    map<string, int> CountMap;
    for (size_t i = 0; i < sizeof(str) / sizeof(str[0]);i++)
    {
        CountMap[str[i]]++;
    }

如此也可以得到与②同样的结果


简单应用

eg:求水果出现的次数且求出前N个最多的

首先由上述map中的方法,可以进行次数统计


int main()
{
    map<string, int> map1;
    vector<map<string, int>::iterator> v;
    string strs[] = { "葡萄", "梨", "桃", "西瓜", "菠萝", "西瓜", "梨", "橘子", "香蕉", "梨", "香蕉","椰子", "梨", "苹果", "菠萝", "香蕉", "橘子", "桃子", "苹果", "桃", "橘子", "葡萄", "橘子", "荔枝", "苹果", "荔枝", "橘子" };
    for (size_t i = 0; i < sizeof(strs)/sizeof(strs[0]); i++)
    {
        map1[strs[i]]++;
    }
        return 0;
}

接下来只需要将map1中的水果根据value,即第二个参数进行排序即可,方法众多,下文使用堆排序进行处理

typedef struct Compare
{
    bool operator()(map<string, int>::iterator l, map<string, int>::iterator r)
    {
        return l->second > r->second;
    }
}Compare;


void GetTopN(map<string, int>& m, size_t n, vector<map<string, int>::iterator>& v)
{
    map<string, int> ::iterator it = m.begin();
    for (size_t i = 0; i < n; ++i)
    {
        v.push_back(it);
        it++;
    }
    make_heap(v.begin(), v.end(), Compare());
    while (it != m.end())
    {
        if (it->second > v.front()->second)
        {
            pop_heap(v.begin(), v.end(), Compare());
            v.pop_back();

            v.push_back(it);
            push_heap(v.begin(), v.end(), Compare());

        }
        it++;
    }
}

使用堆排序将前N种水果插入,最后打印vector容器中的元素即可
在主函数中调用并打印

GetBeginOfNFruits(map1, 5, v);

    for (size_t i = 0; i < v.size(); ++i)
    {
        cout << v[i]->first << "-" << v[i]->second << endl;
    }

最终结果

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值