c++标准库里面的容器,以前用过vector,list等,
前几天在用map的时候遇到些问题。
如果在用map<key,value>的时候如果key是一个比较复杂的结构,就需要重载他所对应的
操作符'<'.
比如我们可以简单定义map<string,string>或者map<string,int>甚至
map<pair<int,int > ,string>
但是如果是
struct node{
int start;
int end;
string str;
}
map<node,int>的话,因为默认的'<'操作符对于node结构没有定义,所以
需要重载这个操作符,否则虽然定义时不会出问题,但到了用的时候问题大大的。
typedef struct START_END_TRANS{
unsigned int start;
unsigned int end;
string str;
}START_END_TRANS;
bool operator<(START_END_TRANS Left, START_END_TRANS Right)
{
if(Left.start < Right.start)
return true;
else
{
if((Left.start == Right.end)&&(Left.end < Right.end))
return true;
else
{
if((Left.start == Right.end)&&(Left.end == Right.end)&&(Left.str.compare(Right.str) < 0))
return true;
else
return false;
}
}
}
经验:用map结构可以很简单地实现统计词频类似的工作
比如map<string,int>word_freq_map;
无需初始化等等,这需要
foreach word(from text)
{
word_freq_table[word]+=1;
}
就可以得到了,是不是很简单?!!
完整具体的使用例子参看一个老外的文章。
贴在下面:
STL: Maps
What is a Map?
The map container class provides the programmer with a convenient way to store and retrieve data pairs consisting of a key and an associated value. Each key is associated with one value. (If you want to associate a key with more than one value, look up the multimap
container class.) This is similar in some ways to what we have done elsewhere in these Web pages with a list-based table and a binary search tree-based table. It is also similar to our B-tree-based table, although that was stored on disk whereas a map is stored in main memory. Another difference is that our tables were unordered; they provided no way to sequence through the data in key order. Maps are ordered, so that you can step through the data if you like.
Maps are guaranteed to be efficient. In general, inserting a new item into a map is supposed to take O(lg(n)) time, where n is the number of items in the map. However, if you want to insert at a specific location (specified by an iterator), it takes on average O(n) time. You can also sequence through the items in a map using an iterator, in ascending order by key, probably in an efficient manner as well, though this author knows of no specific time guarantee. Note, also, that we don't necessarily know what underlying data structure is used by a map.
You need to include the map
header file to use maps. There are a lot of available class functions. Some of the most basic ones are outlined below. You cannot use random-access iterators with the map
class, but iterators can be used to traverse a map in either ascending or descending key order.
-
empty
, boolean function to report if the map is empty.
-
erase
, has several forms; one of these removes the data pair having a given key.
-
find
, does a search for a particular key, returning an iterator to the matching data pair.
-
insert
, also has several forms, the simplest of which inserts one new data pair.
-
size
, returns the number of items currently in the map.
Example
A map is ideal for storing dictionary-like data, a symbol table, etc. Our example program stores a very short dictionary of words and their meanings in a map and then allows the user to interactively look up words, in each case reporting their meanings if a match is found.
Although you can use key/value pairs that contain simple data items like integers and floats, this program uses objects as both the keys and the associated values. Each such object belongs to the class LineClass
, which is designed to contain one "line" of text data (in this case, a word or its meaning). Note that it is necessary to provide a < operator for the class used for the keys. This is because a map is ordered according to the keys. Also, you need to provide a default constructor for the class used for the associated values.
In our example, each LineClass
object contains a simple C-style string to hold the data. The default constructor places an empty string into this field (by just putting a NULL character, the character that marks the end of a C-style string, into the first location of the array of characters).
This program uses strcpy
as a quick way to copy these C-style strings. Note well that strcpy
does not check to see if the destination string has enough room for the data. This can open up one's software to a buffer overflow attack, a well-known type of security flaw. When writing professional software use a copy function that does proper bounds checking instead. Follow the above link for further information on this important topic.
To create an empty map
that can hold pairs of such objects we use the following. Note that, unlike what was done in this example, it is legal to use a different type for the key (first item in the pair) and the value (second item in the pair).
map<LineClass, LineClass> Dictionary;
|
Note that the same notation is used in specifying the type for the map when passing it as a parameter to the helping functions. For example, here is the header for one of the two helping functions:
void LoadData(map<LineClass, LineClass> & Dictionary)
|
Inside the code for this function you see the two basic methods for creating a data pair for inserting into the map. The first one was created by using the pair
constructor, with two LineClass
objects as its parameters. Note the use of the LineClass
constructor in each case to build an object from the C-style string supplied. In the second insertion, the make_pair
generic function was used to create the pair. It, too, was handed two LineClass
objects to place into the pair as the key and associated value.
Dictionary.insert(pair<LineClass, LineClass>(LineClass("hot"),
LineClass("having a high temperature")));
Dictionary.insert(make_pair(LineClass("cold"),
LineClass("having a low temperature")));
|
The code for the Lookup
function is shown below. It illustrates how to use an iterator, p, with the find
class function.
map<LineClass, LineClass>::iterator p;
LineType Meaning;
p = Dictionary.find(LineClass(Target));
if (p != Dictionary.end())
{
p->second.GetLine(Meaning);
cout << "Meaning is: " << Meaning << endl;
}
else
cout << "Word not found" << endl;
|
Note that the find
function is used to look up a key object in the map named Dictionary
. This function returns an iterator to the location where the match was found or an iterator to one past the end of the data if no match was found. Since the latter is the location given by end()
, one typically tests to see if the iterator equals Dictionary.end()
to see if no match was found. In the case where the key was found, note that the iterator returned is an iterator to a data pair, not to the value itself. The two fields of a pair are named first
and second
. These are the key and value, respectively. Thus you see in the code above p->second
to get at the data value in the pair pointed to by the iterator p
. Since that data field is an object of class LineClass
, we can in fact use the GetLine
class function on this field.
As an exercise you might want to modify the above program in various ways. For one thing, the constants, types, class declaration, and function prototypes could be placed in a header file. The class functions could be placed in a separate .cpp file. You might also want to modify the program so that it reads the word and definition data from a suitable text file. That would certainly be more reasonable for a longer list of words. For example, you might want to use the text file btree.txt that was used in an earlier program. (This file might be too long to be handled; you might have to cut it down in size.)
In general, the map
container class is quite convenient for the programmer. It is a lot easier to use it than to write all of the code needed for your own map-like data structure. However, should you need to have control over the details of data storage, the latter would be the appropriate choice.
The map
class has additional capabilities that are not covered here. There is also a multimap
container class where the keys do not have to be unique. That is, a key can be associated with more than one value. See the references for more information.
/* Filename: diction.cpp
Author: Br. David Carlson
Date: July 14, 1999
Last Revised: December 23, 2001
This interactive program creates a map (table), where each entry
is a pair containing a word and its definition. Thus the map is
a small dictionary. The program then allows the user to repeatedly
look up the meaning of words.
In the code, change CTRL z to CTRL d for Linux.
Tested with:
Microsoft Visual C++ 6.0
Microsoft Visual C++ .NET
g++ under Linux
*/
#include <iostream>
#include <map>
using namespace std;
const int LineMax = 72;
const int NULLCHAR = '\0';
typedef char LineType[LineMax];
/* To keep the example short, we will set up LineClass right here.
LineClass objects each contain a short C-style string. The idea is
that such an object contains a line of text. The class basically
provides object-oriented packaging for a C-style string.
*/
class LineClass
{
private:
LineType Info;
public:
LineClass(void);
LineClass(LineType Str);
void GetLine(LineType Line) const;
};
/* Given: Nothing.
Task: This is the default constructor. It creates a LineClass object
containing the empty string.
Return: Nothing directly, but the implicit object is created.
*/
LineClass::LineClass(void)
{
Info[0] = NULLCHAR;
}
/* Given: Nothing.
Task: This constructor creates a LineClass object containing the
string Str.
Return: Nothing directly, but the implicit object is created.
*/
LineClass::LineClass(LineType Str)
{
strcpy(Info, Str);
}
/* Given: Nothing.
Task: To get the string contained in the implicit LineClass object.
Return: Line A copy of the string contained in the implicit object.
*/
void LineClass::GetLine(LineType Line) const
{
strcpy(Line, Info);
}
/* Given: LHS A LineClass object (the left side of the comparison).
RHS A LineClass object (the right side of the comparison).
Task: To compare the strings containe in LHS and RHS.
Return: In the function name, it returns true if the LHS string is less
than the RHS string, false otherwise.
*/
bool operator<(LineClass LHS, LineClass RHS)
{
LineType Left, Right;
LHS.GetLine(Left);
RHS.GetLine(Right);
if (strcmp(Left, Right) < 0)
return true;
else
return false;
}
// Function prototypes:
void LoadData(map<LineClass, LineClass> & Dictionary);
void Lookup(LineType Target, map<LineClass, LineClass> & Dictionary);
int main(void)
{
map<LineClass, LineClass> Dictionary;
LineType Target;
LoadData(Dictionary);
// Change to CTRL d for Linux:
cout << "Enter word to look for (or CTRL z to quit): ";
cin >> Target;
while (! cin.fail())
{
Lookup(Target, Dictionary);
// Change to CTRL d for Linux:
cout << "Enter word to look for (or CTRL z to quit): ";
cin >> Target;
}
return 0;
}
/* Given: Target The word to look up.
Dictionary The map containing the dictionary data.
Task: To look up Target in the Dictionary map and print the meaning
of Target if it was found, or a "not found" message otherwise.
Return: Nothing.
*/
void Lookup(LineType Target, map<LineClass, LineClass> & Dictionary)
{
map<LineClass, LineClass>::iterator p;
LineType Meaning;
p = Dictionary.find(LineClass(Target));
if (p != Dictionary.end())
{
p->second.GetLine(Meaning);
cout << "Meaning is: " << Meaning << endl;
}
else
cout << "Word not found" << endl;
}
/* Given: Dictionary A map.
Task: To add suitable data to Dictionary.
Return: Dictionary The updated map.
*/
void LoadData(map<LineClass, LineClass> & Dictionary)
{
// Note the 2 different ways of creating a pair to insert:
Dictionary.insert(pair<LineClass, LineClass>(LineClass("hot"),
LineClass("having a high temperature")));
Dictionary.insert(make_pair(LineClass("cold"),
LineClass("having a low temperature")));
Dictionary.insert(make_pair(LineClass("jog"),
LineClass("run slowly")));
Dictionary.insert(make_pair(LineClass("intelligent"),
LineClass("smart")));
Dictionary.insert(make_pair(LineClass("register"),
LineClass("a high-speed storage location on a computer's CPU chip")));
}
分享到:
相关推荐
C++中map容器的说明和使用技巧 C++中map容器提供一个键值对容器,map与multimap的差别仅仅在于multiple允许一个键对应多个值。map容器的使用技巧包括插入数据、查找数据和修改数据、删除数据、迭代数据等。 一、...
这里我们将深入探讨`map`容器的实现方法,包括其内部结构、插入和查找操作、迭代器的使用以及一些实用的操作。 一、`map`容器的内部实现 `map`通常使用红黑树(Red-Black Tree)作为底层数据结构。红黑树是一种自...
下面我们将详细探讨SSH框架与Map容器的使用。 **1. Spring框架中的Map容器** Spring作为IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)容器,允许开发者将对象之间的...
让人们更加好的学习java,也让人们更好的理解Map容器元素的迭代。
本篇文章将深入探讨C++容器的使用经验,帮助开发者更好地理解和运用这些工具。 首先,选择合适的容器类型至关重要。C++标准STL提供序列容器如vector、string、deque和list,以及关联容器如set、multiset、map和...
Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程...
本教程将深入探讨`map`容器的基本概念、特性以及如何在实际编程中使用。 `map`容器的主要特点: 1. **键值对**:`map`中的每个元素都是一个键值对,由一个键(key)和一个关联的值(value)组成。键必须是唯一的,...
它的核心目标是展示如何在多线程环境中使用互斥量(Mutex)来保护共享资源——一个名为`mapdate`的`map`容器。`map`容器在C++中用于存储键值对,它提供了关联数组的功能。 在这个程序中,有两个线程:主线程和删除...
使用C++标准库中的MAP容器实现词频统计与排序
### 在STL的map或set容器中使用类作为key #### 概述 在C++标准模板库(STL)中,`map` 和 `set` 容器是两种非常重要的容器类型,它们提供了高效的键值对管理和有序集合的管理方式。在实际应用中,我们常常需要使用...
在这个主题中,我们将重点讨论STL容器之一——`map`的使用。`map`是一个关联容器,它可以存储键值对(key-value pairs),其中每个键都是唯一的,并且通过键来访问对应的值。 ### 1. `map`的基本概念 `map`是一个...
使用`<map>`头文件来包含`map`容器的相关定义。 2. **定义** 可以直接定义一个`map`,如`map, int> my_Map;`。如果需要重命名类型,可以使用`typedef`,例如`typedef map, int> MY_MAP; MY_MAP my_Map;`。 3. *...
在C++编程中,`std::map`是一个非常重要的关联容器,它提供了键值对(key-value pairs)的存储功能,常被用来实现字典或查找表的数据结构。`std::map`的主要特点是对每个键都唯一,且键值对中的键按照某种排序规则...
C++中的map容器
纯C实现的通用红黑树容器不好找,于是自己琢磨着实现了一个。 算法部分直接剪裁自Linux内核中的rbtree 作者主要是在此基础上封装了一个通用的容器 里面含有 test例子 以及 ...附带了一个C++里面的STL Map的benchmark
计算部分的数量 前提, 目标, 结果 前提: 学生需要掌握以下机能 • 树- 了解树的表示方法 • Map容器- 了解如何日用标准库中的map容器以及迭代器 • 递归- 了解如何构造一个递归的解决方案去解决一个问题
在C++编程中,使用STL容器如Map时,需要注意内存管理和异常安全。例如,当在迭代器遍历过程中修改map时,可能会导致迭代器失效。因此,应避免在迭代过程中执行可能导致map重新排列的操作,如插入或删除元素。此外,...
### C++容器使用经验总结 #### 一、慎重选择容器类型 在C++中,根据具体的应用场景选择合适的容器类型至关重要。以下是一些常见的容器及其特点: - **标准STL序列容器**:`vector`, `string`, `deque`, `list` - ...
// 学习map对象容器的使用 // map对象容器里面储存的元素是(key,value)形式的键值对,比如(a,1)(b,20)(c,55) // key不可以重复,value可以重复 // 常用的map接口的实现类有HashMap,LinkedHashMap和TreeMap // ...