温故篇之STL_map,set的一些应用

【知识点】

1、Set是一种关联容器,它用于存储数据,并且能从一个数据集合中取出数据。它的每个元素的值必须唯一,而且系统会根据该值来自动将数据排序。每个元素的值不能直接被改变。【重点】内部结构采用红黑树的平衡二叉树。multiset 跟set 类似,唯一的区别是允许键值重复!!!

Map是c++的一个标准容器,她提供了很好一对一的关系,在一些程序中建立一个map可以起到事半功倍的效果,总结了一些map基本简单实用的操作!

 

2、map的功能

自动建立Key - value的对应。key 和 value可以是任意你需要的类型。

根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1000个记录,最多查找10次,1,000,000个记录,最多查找20次。

快速插入Key -Value 记录。

快速删除记录

根据Key 修改value记录。

遍历所有记录。

 

3、使用map

使用map得包含map类所在的头文件

#include <map>  //注意,STL头文件没有扩展名.h

map对象是模板类,需要关键字和存储对象两个模板参数:

std:map<int,stringpersonnel;

这样就定义了一个用int作为索引,并拥有相关联的指向string的指针.

为了使用方便,可以对模板类进行一下类型定义,

typedef map<int,CStringUDT_MAP_INT_CSTRING;

UDT_MAP_INT_CSTRING enumMap;

 

4、在map中插入元素

改变map中的条目非常简单,因为map类已经对[]操作符进行了重载

enumMap[1] ="One";

enumMap[2] ="Two";

.....

这样非常直观,但存在一个性能的问题。插入2时,先在enumMap中查找主键为2的项,没发现,然后将一个新的对象插入enumMap,键是2,

值是一个空字符串,插入完成后,将字符串赋为"Two";该方法会将每个值都赋为缺省值,然后再赋为显示的值,如果元素是类对象,则开销比较大。

我们可以用以下方法来避免开销:

  enumMap.insert(map<int,CString:: value_type(2,"Two"))

  enumMap.insert(pair<int,string>(102,"aclive"));

 

5、查找并获取map中的元素

下标操作符给出了获得一个值的最简单方法:

CString tmp =enumMap[2];

但是,只有当map中有这个键的实例时才对,否则会自动插入一个实例,值为初始化值。

我们可以使用Find()和Count()方法来发现一个键是否存在。

查找map中是否包含某个关键字条目用find()方法,传入的参数是要查找的key,在这里需要提到的是begin()和end()两个成员,

分别代表map对象中第一个条目和最后一个条目,这两个数据的类型是iterator.

int nFindKey2;//要查找的Key

//定义一个条目变量(实际是指针)

UDT_MAP_INT_CSTRING::iterator it=enumMap.find(nFindKey);

if(it== enumMap.end()) {

//没找到

}

else {

//找到

}

通过map对象的方法获取的iterator数据类型是一个std::pair对象,包括两个数据 iterator->first和 iterator->second分别代表关键字和存储的数据


 6.从map中删除元素

移除某个map中某个条目用erase()

该成员方法的定义如下:

iterator erase(iterator it);//通过一个条目对象删除

iterator erase(iterator first,iterator last)//删除一个范围

size_type erase(const Key&key);//通过关键字删除

clear()就相当于enumMap.erase(enumMap.begin(),enumMap.end());


7.map中的swap用法

Map中德swap不是一个容器中的元素交换,而是两个容器的交换;

8.map中的sort问题

Map中的元素是自动按Key升序排序,所以不能对map用sort函数;

9.  map的基本操作函数:

      C++ Maps是一种关联式容器,包含“关键字/值”对

     begin()         返回指向map头部的迭代器

     clear()        删除所有元素

     count()         返回指定元素出现的次数

     empty()         如果map为空则返回true

     end()           返回指向map末尾的迭代器

     equal_range()   返回特殊条目的迭代器对

     erase()         删除一个元素

     find()          查找一个元素

     get_allocator() 返回map的配置器

     insert()        插入元素

     key_comp()      返回比较元素key的函数

     lower_bound()   返回键值>=给定元素的第一个位置

     max_size()      返回可以容纳的最大元素个数

     rbegin()        返回一个指向map尾部的逆向迭代器

     rend()          返回一个指向map头部的逆向迭代器

     size()          返回map中元素的个数

     swap()           交换两个map

     upper_bound()    返回键值>给定元素的第一个位置

     value_comp()     返回比较元素value的函数


今天看到map的时候想到了二维图,然后一时忘了怎么创。。。哎,居然写成了map<map<string,string>,int>;怎么说呢,这个其实并不是二位图,还是等于map<struct T,int>,so...真正的二维图:map<string,map<string,int> >;


要练手的可以做下经典题:

链接: http://acm.hdu.edu.cn/showproblem.php?pid=1263 


水果

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 7191    Accepted Submission(s): 2817


Problem Description
夏天来了~~好开心啊,呵呵,好多好多水果~~
Joe经营着一个不大的水果店.他认为生存之道就是经营最受顾客欢迎的水果.现在他想要一份水果销售情况的明细表,这样Joe就可以很容易掌握所有水果的销售情况了.
 

Input
第一行正整数N(0<N<=10)表示有N组测试数据.
每组测试数据的第一行是一个整数M(0<M<=100),表示工有M次成功的交易.其后有M行数据,每行表示一次交易,由水果名称(小写字母组成,长度不超过80),水果产地(小写字母组成,长度不超过80)和交易的水果数目(正整数,不超过100)组成.
 

Output
对于每一组测试数据,请你输出一份排版格式正确(请分析样本输出)的水果销售情况明细表.这份明细表包括所有水果的产地,名称和销售数目的信息.水果先按产地分类,产地按字母顺序排列;同一产地的水果按照名称排序,名称按字母顺序排序.
两组测试数据之间有一个空行.最后一组测试数据之后没有空行.
 

Sample Input
  
  
1 5 apple shandong 3 pineapple guangdong 1 sugarcane guangdong 1 pineapple guangdong 3 pineapple guangdong 1
 

Sample Output
  
  
guangdong |----pineapple(5) |----sugarcane(1) shandong |----apple(3)
 

Source

写了两个,真假二维图了,/汗

//注意:两组测试数据之间有一个空行.最后一组测试数据之后没有空行.

#include<cstring>
#include<string>
#include<cstdio>
#include<iostream>
#include<map>
using namespace std;

int main()
{
    int N,M;
    scanf("%d",&N);
    while(N--)
    {
        scanf("%d",&M);
        string addr,future;
        int num=0;

        map<map<string,string>,int> salesInfo;
        for(int i=0;i<M;i++)
        {
            cin>>future>>addr>>num;
            map<string,string> info;
            info[addr] = future;
            salesInfo[info] += num;
        }
        map<map<string,string>,int>::iterator iter;
        addr = "";
        for(iter = salesInfo.begin();iter!=salesInfo.end();iter++)
        {
            //cout<<"("<<iter->second<<")"<<endl;
            map<string,string> info(iter->first);
            map<string,string>::iterator itm;
            itm = info.begin();
            if(addr != (*itm).first)
            {
                addr = (*itm).first;
                cout<<addr<<endl;
            }
            cout<<"   |----"<<(*itm).second<<"("<<iter->second<<")"<<endl;

        }
        if(N) cout<<endl;
    }
    return 0;
}


二维map的应用


//真正二维map...
#include<cstring>
#include<string>
#include<cstdio>
#include<iostream>
#include<map>
using namespace std;

int main()
{
    int N,M;
    scanf("%d",&N);
    while(N--)
    {
        scanf("%d",&M);
        string addr,future;
        int num=0;

        map<string,map<string,int> > salesInfo;//这才是真的二维map
        for(int i=0;i<M;i++)
        {
            cin>>future>>addr>>num;
            salesInfo[addr][future] += num;
        }
        map<string,map<string,int> >::iterator iter;
        for(iter = salesInfo.begin();iter!=salesInfo.end();iter++)
        {
            cout<<iter->first<<endl;
            map<string,int>::iterator itm;
            for(itm = (iter->second).begin();itm != (iter->second).end();itm++)
            {
                cout<<"   |----"<<(*itm).first<<"("<<(*itm).second<<")"<<endl;
            }

        }
        if(N) cout<<endl;
    }
    return 0;
}


练的不过瘾,可以温习下下面两题


Let the Balloon Rise

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 122783    Accepted Submission(s): 48360


Problem Description
Contest time again! How excited it is to see balloons floating around. But to tell you a secret, the judges' favorite time is guessing the most popular problem. When the contest is over, they will count the balloons of each color and find the result.

This year, they decide to leave this lovely job to you. 
 

Input
Input contains multiple test cases. Each test case starts with a number N (0 < N <= 1000) -- the total number of balloons distributed. The next N lines contain one color each. The color of a balloon is a string of up to 15 lower-case letters.

A test case with N = 0 terminates the input and this test case is not to be processed.
 

Output
For each case, print the color of balloon for the most popular problem on a single line. It is guaranteed that there is a unique solution for each test case.
 

Sample Input
  
  
5 green red blue red red 3 pink orange pink 0
 

Sample Output
  
  
red pink
 
/题意:给N个气球,求出现最多次数的颜色,保证答案唯一,N=0 break;
//解:map<string,int> 即可


#include<map>
#include<cstring>
#include<string>
#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
    int N;
    while(scanf("%d",&N)!=EOF)
    {
        if(N==0) break;
        map<string,int> color;
        string str,MoreColor;
        int mmax = -1;
        for(int i=0;i<N;i++)
        {
            cin>>str;
            color[str]++;
            if(color[str] > mmax)
            {
                mmax = color[str];
                MoreColor = str;
            }
        }
        cout<<MoreColor<<endl;
    }
    return 0;
}



What Are You Talking About

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/204800 K (Java/Others)
Total Submission(s): 23494    Accepted Submission(s): 7875


Problem Description
Ignatius is so lucky that he met a Martian yesterday. But he didn't know the language the Martians use. The Martian gives him a history book of Mars and a dictionary when it leaves. Now Ignatius want to translate the history book into English. Can you help him?
 

Input
The problem has only one test case, the test case consists of two parts, the dictionary part and the book part. The dictionary part starts with a single line contains a string "START", this string should be ignored, then some lines follow, each line contains two strings, the first one is a word in English, the second one is the corresponding word in Martian's language. A line with a single string "END" indicates the end of the directory part, and this string should be ignored. The book part starts with a single line contains a string "START", this string should be ignored, then an article written in Martian's language. You should translate the article into English with the dictionary. If you find the word in the dictionary you should translate it and write the new word into your translation, if you can't find the word in the dictionary you do not have to translate it, and just copy the old word to your translation. Space(' '), tab('\t'), enter('\n') and all the punctuation should not be translated. A line with a single string "END" indicates the end of the book part, and that's also the end of the input. All the words are in the lowercase, and each word will contain at most 10 characters, and each line will contain at most 3000 characters.
 

Output
In this problem, you have to output the translation of the history book.
 

Sample Input
  
  
START from fiwo hello difh mars riwosf earth fnnvk like fiiwj END START difh, i'm fiwo riwosf. i fiiwj fnnvk! END
 

Sample Output
  
  
hello, i'm from mars. i like earth!
Hint
Huge input, scanf is recommended.

题意:是翻译。START--END 中间是字典翻译和需要翻译的原文; 翻译成英文,字典里没有的原样输出
//用map<string,string>做一个转换表


这里要注意是:整个book行数比较多之前我是开string[10005]数组的,结果一直RE后来我一句句输出,不存才过,之后我又存了个vector<string> 也过得了,看需求吧~


#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
#include<string>
using namespace std;

int main()
{
    string sta;
    cin>>sta;

    if(sta.compare("START") == 0)
    {
        map<string,string> dictionary;//火星文字典...
        string eng,marks;
        while(cin>>eng)
        {
            if(eng.compare("END") == 0) break;
            cin>>marks;
            dictionary[marks] = eng;
        }
        string str, essay;// 这里essay不好定长度,之前定[1005]开小了,//ACCESS_VIOLATION
        char ch[15];
        gets(ch);//吸收回车
        int cnt = 0;
        while(getline (cin, str, '\n'))
        {
            //cout<<"essay["<<cnt<<"] = "<<str<<endl;
            if(str.compare("END") == 0) break;
            if(str.compare("START") == 0) continue;

            int len = str.size();
            //str[len] = '\n';
            str.append("\n");

            //cout<<"len = "<<len<<endl;
            string tmp("");
            for(int i=0;i<=len;i++)
            {
                if(!(str[i] >= 'a' && str[i] <= 'z' || str[i] == '\''))//标点 空格 换行 标签 (只有小写字母)
                {
                    //cout<<"tmp = "<<tmp<<" ["<<str[i]<<"]"<<endl;
                    if(tmp!="" && dictionary[tmp] != "") tmp = dictionary[tmp];
                    essay += tmp + str[i];
                    tmp.clear();
                }
                else
                    tmp += str[i];
            }
            cout<<essay;
            essay.clear();
            //cout<<"essay["<<cnt<<"] = "<<essay[cnt]<<endl;
            cnt++;

        }
        //for(int i=0;i<cnt;i++)
        //{
        //    cout<<essay[i]<<endl;
        //}

    }
    return 0;
}


解法二:


#include<cstdio>
#include<iostream>
#include<map>
#include<vector>
#include<cstring>
#include<string>
using namespace std;

int main()
{
    string sta;
    cin>>sta;

    if(sta.compare("START") == 0)
    {
        map<string,string> dictionary;//火星文字典...
        string eng,marks;
        while(cin>>eng)
        {
            if(eng.compare("END") == 0) break;
            cin>>marks;
            dictionary[marks] = eng;
        }
        string str, essay;// 这里essay不好定长度,之前定[1005]开小了,//ACCESS_VIOLATION
        vector<string> book;//统一输出
        char ch[15];
        gets(ch);//吸收回车
        int cnt = 0;
        while(getline (cin, str, '\n'))
        {
            //cout<<"essay["<<cnt<<"] = "<<str<<endl;
            if(str.compare("END") == 0) break;
            if(str.compare("START") == 0) continue;

            int len = str.size();
            //str[len] = '\n';
            str.append("\n");

            //cout<<"len = "<<len<<endl;
            string tmp("");
            for(int i=0;i<=len;i++)
            {
                if(!(str[i] >= 'a' && str[i] <= 'z' || str[i] == '\''))//标点 空格 换行 标签 (只有小写字母)
                {
                    //cout<<"tmp = "<<tmp<<" ["<<str[i]<<"]"<<endl;
                    if(tmp!="" && dictionary[tmp] != "") tmp = dictionary[tmp];
                    essay += tmp + str[i];
                    tmp.clear();
                }
                else
                    tmp += str[i];
            }
            //cout<<essay;
            book.push_back(essay);
            essay.clear();
            //cout<<"essay["<<cnt<<"] = "<<essay[cnt]<<endl;
            cnt++;

        }
        for(vector<string>::iterator iter = book.begin();iter != book.end();iter++)
        {
            cout<<*iter;
        }

    }
    return 0;
}


另外还有更快的解法。字典树


也附一份代码


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node
{
    struct node *child[26];
    char *str;
};
struct node *root = new struct node;

void Init()
{
    for(int i =0;i <26; i++)
        root->child[i] = 0;
}
void Insert(char *c1,char *c2)
{
    int len = strlen(c2);
    struct node *cur;
    cur = root;
    for(int i =0;i <len;i ++){
        if(cur ->child[c2[i] - 'a'] != 0){
            cur = cur ->child[c2[i] - 'a'];
        }
        else{
            struct node *newnode = new struct node;
            cur ->child[c2[i] - 'a'] = newnode;
            for(int j =0; j <26; j++){
                newnode ->child[j] = 0;
            }
            newnode ->str = NULL;          //相当重要啊!!!!!
            cur = newnode;

        }
    }
    cur->str = (char *)malloc(15 * sizeof(char));
    strcpy(cur->str, c1);
}

void Print(char *c2)
{
    int len = strlen(c2);
    struct node *cur;
    cur = root;
    if(!len) return ;
    for(int i =0;i <len; i++){
        if(c2[i] < 'a' || c2[i] > 'z' || cur ->child[c2[i] - 'a'] == 0){
            printf("%s",c2);
            return ;
        }
        else{
            cur = cur ->child[c2[i] - 'a'];
        }
    }
    if(cur ->str != NULL)
        printf("%s",cur ->str);
    else
        printf("%s",c2);
}
int main()
{
    char s[15],temp[3005],c1[15],c2[15];

    Init();

    scanf("%s", temp);
    while(scanf("%s", c1) && strcmp(c1, "END")!=0){
        scanf("%s", c2);
        Insert( c1, c2);
    }

    scanf("%s", temp);
    getchar();
    while(gets(temp) && strcmp(temp,"END")!=0)
    {
        int len = strlen(temp);
        int start = -1, end = 0;
        int num = 0;
        for(int i =0; i<len; i++){
            if(temp[i] >= 'a' && temp[i] <= 'z'){
                if(start == -1){
                    start = i;
                }
                s[num++] = temp[i];
            }
            else{
                if(start > -1){
                    start = -1;
                    s[num] = '\0';
                    num = 0;
                    Print(s);
                }
                printf("%c", temp[i]);
            }
        }
        if(start > -1)
        {
            s[num] = '\0';
            Print(s);
            if(temp[len - 1] < 'a' || temp[len - 1] > 'z')
            printf("%c", temp[len - 1]);
        }
        printf("\n");
    }
    return 0;
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值