统计单词出现个数(STL-map求解)

string strs[] = { “zhangsan”, “zhangsan”, “lisi”, “wangwu”, “lisi”, “zhaoliu”,”lisi” };
问题一:统计单词出现的次数
看到这个题,有很多思路可以解决,目前刚好在了解STLset/map中,所以就用map来解这个问题。
根据map的诸多借口可以有多种方法来解决这个问题,但是其实都是运用的map的特性。
觉得下面这些有必要了解一下:
首先map是关联容器,之前set篇说过。map的元素都通过元素键值自动排序,拥有并且独一无二的键值,因为map不允许两个元素拥有相同的键值。map的元素都是pair类型。同时拥有键值(key)和实值(value)。pair的第一个元素是键值,第二个元素是实值。另外map的底层是由RB-tree为底层机制,因此map对插入,删除,查找能保证log(N)的时间复杂度。对于海量的数据的插入和查询,map是一个不错的选择。
map形式如下:

template < class Key,                                    // map::key_type
          class T,                                       // map::mapped_type
           class Compare = less<Key>,
           // map::key_compare 这里可以看到缺省采用的是递增排序(升序)
           class Alloc = allocator<pair<const Key,T> >    // map::allocator_type
           > class map;

map::insert()形式如下:
这里写图片描述

而pair的定义如下:

template<class TI,class T2>
struct pair
{
     typedef TI first_type;
     typedef T2 second_type;
     T1 first;
     T2 second;
     pair():first_type(T1()),second_type(T2()){}
     pair(const T1& a,const T2& b):first(a),second(b){}
}

可以将单词当作键值,次数当作实值
方法一:插入单词前先就行判断,是否已经拥有,如果已经插入则直接给实值+1,如果没有则进行插入操作。

string strs[] = { "zhangsan", "zhangsan", "lisi", "wangwu", "lisi", "zhaoliu","lisi" };
     map<string, int> CountMap;
      for (size_t idx = 0; idx < sizeof(strs) / sizeof(strs[0]); ++idx)
     {
          //第一种
          map<string, int>::iterator it = CountMap.find(strs[idx]);
          if (it != CountMap.end())
          {
               it->second++;
          }
          else
          {
               CountMap.insert(pair<string, int>(strs[idx], 1));
          }
     }
 方法二:要知道如定义一个pair类型的第二个元素会返回一个false),则说明map中已经存在这个单词,给实值+1就可以     
string strs[] = { "zhangsan", "zhangsan", "lisi", "wangwu", "lisi", "zhaoliu","lisi" };
     map<string, int> CountMap;
     pair<map<string, int>::iterator, bool> ret; 
      for (size_t idx = 0; idx < sizeof(strs) / sizeof(strs[0]); ++idx)
     {
          //第二种
          ret = CountMap.insert(pair<string, int>(strs[idx], 1));
          if (ret.second == false)
          {
               ret.first->second++;
          }
     }        
 方法三:需要对map了解,直接使用库里提供的[]运算符重载。通过键值找节点,直接给给实值+1.
string strs[] = { "zhangsan", "zhangsan", "lisi", "wangwu", "lisi", "zhaoliu","lisi" };
     map<string, int> CountMap;
      for (size_t idx = 0; idx < sizeof(strs) / sizeof(strs[0]); ++idx)
     {
          CountMap[strs[idx]]++;   
     }

这里写图片描述
可以看到单词的个数已经统计出来。第三种方法就充分说明熟悉STL库的作用,想想这要是在笔试别人不需要多想直接就能得到答案,而我们还在思考应该怎么求(这也许就是差距啊)
问题二: 找出出现次数最多的三个单词
首先想的是将所有单词都插入到vector中,然后在用sort进行排序,但是仔细想想一个string类型就占很多字节,如果单词稍微多点的话,岂不是太浪费空间了?
我们可以打破惯性思维,为什么非得把单词存到vector中,为什么不把单词所在节点的迭代器放到vector中呢?然后再通过自定义比较类型比较次数从而使用sort就行排序。

vector<map<string, int>::iterator> v;
      map<string, int>::iterator CountIt = CountMap.begin();
      while (CountIt != CountMap.end())
      {
           v.push_back(CountIt);
           ++CountIt;
      }
      struct Compare
      {
           bool operator()(map<string, int>::iterator l, map<string, int>::iterator r)
           {
                return l->second > r->second;
           }
      };
      sort(v.begin(),v.end(),Compare());

测试:
这里写图片描述
完整代码入下:

#define _CRT_SECURE_NO_WARNINGS

#include<iostream>
#include<map>
#include<vector>
#include<algorithm>
#include<set>
#include<queue>
using namespace std;
int main()
{
     string strs[] = { "zhangsan", "zhangsan", "lisi", "wangwu", "lisi", "zhaoliu","lisi" };
     map<string, int> CountMap;
     pair<map<string, int>::iterator, bool> ret;
      for (size_t idx = 0; idx < sizeof(strs) / sizeof(strs[0]); ++idx)
     {
          //第一种
          /*map<string, int>::iterator it = CountMap.find(strs[idx]);
          if (it != CountMap.end())
          {
               it->second++;
          }
          else
          {
               CountMap.insert(pair<string, int>(strs[idx], 1));
          }    */

          //第二种
          /*ret = CountMap.insert(pair<string, int>(strs[idx], 1));
          if (ret.second == false)
          {
               ret.first->second++;
          }*/
           //第三种
          CountMap[strs[idx]]++;
           /*
               //operator[]定义:
                  mapped_type& operator[](const key_type& _Keyval)
           {   // find element matching _Keyval or insert with default mapped
                iterator _Where = this->lower_bound(_Keyval);
                if (_Where == this->end()
                     || this->_Getcomp()(_Keyval, this->_Key(_Where._Mynode())))

                     _Where = this->emplace_hint(_Where,
                     piecewise_construct,
                     _STD forward_as_tuple(_Keyval),
                     tuple<>());

                return (_Where->second);
           }*/
     }
      //用sort排序

      vector<map<string, int>::iterator> v;
      map<string, int>::iterator CountIt = CountMap.begin();
      while (CountIt != CountMap.end())
      {
           v.push_back(CountIt);
           ++CountIt;
      }
      struct Compare
      {
           bool operator()(map<string, int>::iterator l, map<string, int>::iterator r)
           {
                return l->second > r->second;
           }
      };
      sort(v.begin(),v.end(),Compare());
      map<string, int>::iterator it = CountMap.begin();
      system("pause");
     return 0;
}
                                                     进击的Mis_tian
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值