??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲AV无码久久精品狠狠爱浪潮 ,久久精品蜜芽亚洲国产AV,色婷婷噜噜久久国产精品12phttp://www.shnenglu.com/09212744/archive/2010/12/25/137463.html吴秦QSaylorQ?/dc:creator>吴秦QSaylorQ?/author>Sat, 25 Dec 2010 12:29:00 GMThttp://www.shnenglu.com/09212744/archive/2010/12/25/137463.htmlhttp://www.shnenglu.com/09212744/comments/137463.htmlhttp://www.shnenglu.com/09212744/archive/2010/12/25/137463.html#Feedback0http://www.shnenglu.com/09212744/comments/commentRss/137463.htmlhttp://www.shnenglu.com/09212744/services/trackbacks/137463.html在linux下面工作Q有些命令能够大大提高效率。本文就向大家介lfind、grep命oQ他哥俩可以是必会的linux命oQ我几乎每天都要用到他们。本文结构如下:

  • find命o
    • find命o的一般Ş?
    • find命o的常用选项及实?
    • find与xargs
  • grep命o
    • grep命o的一般Ş?
    • grep正则表达式元字符?基本?
    • grep命o的常用选项及实?

1、find命o

find命o是一个无处不在命令,是linux中最有用的命令之一。find命o用于Q在一个目录(及子目录Q中搜烦文gQ你可以指定一些匹配条Ӟ如按文g名、文件类型、用Lx旉x找文件。下面就通过实例来体验下find命o的强大?/p>

1.1、find命o的一般Ş?/h2>

man文档中给出的find命o的一般Ş式ؓQ?/p>

find [-H] [-L] [-P] [-D debugopts] [-Olevel] [path...] [expression]

其实[-H] [-L] [-P] [-D debugopts] [-Olevel]q几个选项q不常用Q至在我的日常工作中,没有用到q)Q上面的find命o的常用Ş式可以简化ؓQ?/p>

find [path...] [expression]

  • pathQfind命o所查找的目录\径。例如用.来表C当前目录,?来表C系l根目录
  • expressionQexpression可以分ؓ——?options [-print -exec -ok ...]?
  • -optionsQ指定find命o的常用选项Q下节详l介l?
  • -printQfind命o匹配的文g输出到标准输?
  • -execQfind命o对匹配的文g执行该参数所l出的shell命o。相应命令的形式?command' {  } \;Q注意{   }和\Q之间的I格
    find ./ -size 0 -exec rm {} \; 删除文g大小为零的文?Q还可以以这样做Qrm -i `find ./ -size 0`  ?find ./ -size 0 | xargs rm -f &Q?
    Z用ls -l命o列出所匚w到的文gQ可以把ls -l命o攑֜find命o?exec选项中:find . -type f -exec ls -l {  } \;
    ?logs目录中查找更Ҏ间在5日以前的文gq删除它们:find /logs -type f -mtime +5 -exec rm {  } \;
  • -okQ和-exec的作用相同,只不q以一U更为安全的模式来执行该参数所l出的shell命oQ在执行每一个命令之前,都会l出提示Q让用户来确定是否执行?
    find . -name "*.conf"  -mtime +5 -ok rm {  } \; 在当前目录中查找所有文件名?LOGl尾、更Ҏ间在5日以上的文gQƈ删除它们Q只不过在删除之前先l出提示

    也有hȝfind命o的结构:

    find start_directory test 
    options
    criteria_to_match
    action_to_perform_on_results

    1.2、find命o的常用选项及实?/h2>
  • -name
    按照文g名查找文件?
    find /dir -name filename  ?dir目录及其子目录下面查扑֐字ؓfilename的文?
    find . -name "*.c" 在当前目录及其子目录Q用?”表C)中查找Q何扩展名为“c”的文g
  • -perm
    按照文g权限来查找文件?
    find . -perm 755 –print 在当前目录下查找文g权限位ؓ755的文Ӟx件属d以读、写、执行,其他用户可以诅R执行的文g
  • -prune
    使用q一选项可以使find命o不在当前指定的目录中查找Q如果同时?depth选项Q那?prune被find命o忽略?
    find /apps -path "/apps/bin" -prune -o –print ?apps目录下查找文Ӟ但不希望?apps/bin目录下查?
    find /usr/sam -path "/usr/sam/dir1" -prune -o –print ?usr/sam目录下查找不在dir1子目录之内的所有文?
  • -user
    按照文g属主来查找文件?
    find ~ -user sam –print ?HOME目录中查找文件属Mؓsam的文?
  • -group
    按照文g所属的l来查找文g?
    find /apps -group gem –print ?apps目录下查扑ֱ于gem用户l的文g 
  • -mtime -n +n
    按照文g的更Ҏ间来查找文gQ?- n表示文g更改旉距现在n天以内,+ n表示文g更改旉距现在n天以前?
    find / -mtime -5 –print 在系l根目录下查找更Ҏ间在5日以内的文g
    find /var/adm -mtime +3 –print ?var/adm目录下查找更Ҏ间在3日以前的文g
  • -nogroup
    查找无有效所属组的文Ӟ卌文g所属的l在/etc/groups中不存在?
    find / –nogroup -print
  • -nouser
    查找无有效属ȝ文gQ即该文件的属主?etc/passwd中不存在?
    find /home -nouser –print
  • -newer file1 ! file2
    查找更改旉比文件file1C比文件file2旧的文g?
  • -type
    查找某一cd的文Ӟ诸如Q?
    b - 块设备文件?
    d - 目录?
    c - 字符讑֤文g?
    p - 道文g?
    l - W号链接文g?
    f - 普通文件?
    find /etc -type d –print ?etc目录下查找所有的目录
    find . ! -type d –print 在当前目录下查找除目录以外的所有类型的文g
    find /etc -type l –print ?etc目录下查找所有的W号链接文g
  • -size nQ[c] 查找文g长度为n块的文gQ带有c时表C文仉度以字节计?
    find . -size +1000000c –print 在当前目录下查找文g长度大于1 M字节的文?
    find /home/apache -size 100c –print ?home/apache目录下查找文仉度恰好ؓ100字节的文?
    find . -size +10 –print 在当前目录下查找长度过10块的文gQ一块等?12字节Q?
  • -depthQ在查找文gӞ首先查找当前目录中的文gQ然后再在其子目录中查找?
    find / -name "CON.FILE" -depth –print 它将首先匚w所有的文g然后再进入子目录中查?nbsp;
  • -mountQ在查找文g时不跨越文gpȝmount炏V?nbsp;
    find . -name "*.XC" -mount –print 从当前目录开始查找位于本文gpȝ中文件名以XCl尾的文Ӟ不进入其他文件系l)
  • -followQ如果find命o遇到W号链接文gQ就跟踪至链接所指向的文件?

    1.3、find与xargs

    在用find命o?exec选项处理匚w到的文gӞ find命o所有匹配到的文件一起传递给exec执行。但有些pȝ对能够传递给exec的命令长度有限制Q这样在find命oq行几分钟之后,׃出现溢出错误。错误信息通常是“参数列太长”或“参数列溢出”。这是xargs命o的用处所在,特别是与find命o一起用?/p>

    find命o把匹配到的文件传递给xargs命oQ而xargs命o每次只获取一部分文g而不是全部,不像-exec选项那样。这样它可以先处理最先获取的一部分文gQ然后是下一批,q如此l下厅R?/p>

    在有些系l中Q?exec选项会ؓ处理每一个匹配到的文件而发起一个相应的q程Qƈ非将匚w到的文g全部作ؓ参数一ơ执行;q样在有些情况下׃出现q程q多Q系l性能下降的问题,因而效率不高;

    而用xargs命o则只有一个进E。另外,在用xargs命oӞI竟是一ơ获取所有的参数Q还是分批取得参敎ͼ以及每一ơ获取参数的数目都会Ҏ该命令的选项及系l内怸相应的可调参数来定?/font>

    来看看xargs命o是如何同find命o一起用的Qƈl出一些例子?/p>

    find . -type f -print | xargs file 查找pȝ中的每一个普通文Ӟ然后使用xargs命o来测试它们分别属于哪cL?/p>

    find / -name "core" -print | xargs echo "" >/tmp/core.log 在整个系l中查找内存信息转储文g(core dump) Q然后把l果保存?tmp/core.log 文g中:

    find . -type f -print | xargs grep "hostname" 用grep命o在所有的普通文件中搜烦hostnameq个?/p>

    find ./ -mtime +3 -print|xargs rm -f –r 删除3天以前的所有东?Qfind . -ctime +3 -exec rm -rf {} \;Q?/p>

    find ./ -size 0 | xargs rm -f & 删除文g大小为零的文?/p>

    find命o配合使用exec和xargs可以使用户对所匚w到的文g执行几乎所有的命o?/p>

    2、grep命o

    grep (global search regular expression(RE) and print out the line,全面搜烦正则表达式ƈ把行打印出来)是一U强大的文本搜烦工具Q它能用正则表辑ּ搜烦文本Qƈ把匹配的行打印出来?/p>

    2.1、grep命o的一般选项及实?/h2>

    grep [OPTIONS] PATTERN [FILE...]
    grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]

    grep命o用于搜烦由Pattern参数指定的模式,q将每个匚w的行写入标准输出中。这些模式是h限定的正则表辑ּQ它们用ed或egrep命o样式。如果在File参数中指定了多个名称Qgrep命o显C包含匹配行的文件的名称。对 shell 有特D含义的字符 ($, *, [, |, ^, (, ), \ ) 出现?Pattern参数中时必须带双引号。如?Pattern参数不是单字W串Q通常必须用单引号整个模式括h。在诸如 [a-z], 之类的表辑ּ中,-Q减Pcml 可根据当前正在整理的序列来指定一个范围。整理序列可以定义等LcM供在字符范围中用。如果未指定M文gQgrep会假定ؓ标准输入?/p>

    2.2、grep正则表达式元字符?基本?

    ^  锚定行的开?如:'^grep'匚w所有以grep开头的行?/p>

    $  锚定行的l束 如:'grep$'匚w所有以grepl尾的行?/p>

    .   匚w一个非换行W的字符 如:'gr.p'匚wgr后接一个Q意字W,然后是p?/p>

    *  匚w零个或多个先前字W?如:'*grep'匚w所有一个或多个I格后紧跟grep的行?font size="3"> .*一L代表L字符?/p>

    [] 匚w一个指定范围内的字W,?[Gg]rep'匚wGrep和grep?/p>

    [^]  匚w一个不在指定范围内的字W,如:'[^A-FH-Z]rep'匚w不包含A-R和T-Z的一个字母开_紧跟rep的行?/p>

    \(..\)  标记匚w字符Q如Q?\(love\)'Qlove被标Cؓ1?/p>

    \<  锚定单词的开始,如:'\<grep'匚w包含以grep开头的单词的行?/p>

    \>  锚定单词的结束,?grep\>'匚w包含以grepl尾的单词的行?/p>

    x\{m\} q箋重复字符xQmơ,如:'o\{5\}'匚w包含q箋5个o的行?/p>

    x\{m,\} q箋重复字符x,臛_mơ,如:'o\{5,\}'匚w臛_q箋?个o的行?/p>

    x\{m,n\} q箋重复字符xQ至mơ,不多于nơ,如:'o\{5,10\}'匚wq箋5--10个o的行?/p>

    \w  匚w一个文字和数字字符Q也是[A-Za-z0-9]Q如Q?G\w*p'匚w以G后跟零个或多个文字或数字字符Q然后是p?/p>

    \W  w的反|Ş式,匚w一个非单词字符Q如点号句号{。\W*则可匚w多个?/p>

    \b  单词锁定W,? '\bgrep\b'只匹配grepQ即只能是grepq个单词Q两边均为空根{?/p>

    2.3、grep命o的常用选项及实?/h2>

    -?

    同时昄匚w行上下的Q行Q如Qgrep -2 pattern filename同时昄匚w行的上下2行?/p>

    -bQ?-byte-offset

    打印匚w行前面打印该行所在的块号码?/p>

    -c,--count

    只打印匹配的行数Q不昄匚w的内宏V?/p>

    -f FileQ?-file=File

    从文件中提取模板。空文g中包?个模板,所以什么都不匹配?/p>

    -hQ?-no-filename

    当搜索多个文件时Q不昄匚w文g名前~?/p>

    -iQ?-ignore-case

    忽略大小写差别?/p>

    -qQ?-quiet

    取消昄Q只q回退出状态?则表C找C匚w的行?/p>

    -lQ?-files-with-matches

    打印匚w模板的文件清单?/p>

    -LQ?-files-without-match

    打印不匹配模板的文g清单?/p>

    -nQ?-line-number

    在匹配的行前面打印行受?/p>

    -sQ?-silent

    不显C关于不存在或者无法读取文件的错误信息?/p>

    -vQ?-revert-match

    反检索,只显CZ匚w的行?/p>

    -wQ?-word-regexp

    如果被\<和\>引用Q就把表辑ּ做ؓ一个单词搜索?/p>

    -VQ?-version

    昄软g版本信息?/p>

    =====

    ls -l | grep '^a' 通过道qols -l输出的内容,只显CZa开头的行?/p>

    grep 'test' d* 昄所有以d开头的文g中包含test的行?/p>

    grep 'test' aa bb cc 昄在aaQbbQcc文g中匹配test的行?/p>

    grep '[a-z]' aa 昄所有包含每个字W串臛_?个连l小写字W的字符串的行?/p>

    grep 'w(es)t.*' aa 如果west被匹配,则esp存储到内存中Qƈ标记?Q然后搜索Q意个字符(.*)Q这些字W后面紧跟着另外一个es()Q找到就昄该行。如果用egrep或grep -EQ就不用""可行{义,直接写成'w(es)t.*'可以了?/p>

    grep -i pattern files Q不区分大小写地搜烦。默认情况区分大写

    grep -l pattern files Q只列出匚w的文件名Q?/p>

    grep -L pattern files Q列Z匚w的文件名Q?/p>

    grep -w pattern files Q只匚w整个单词Q而不是字W串的一部分(如匹配‘magic’,而不是‘magical?Q?/p>

    grep -C number pattern files Q匹配的上下文分别显C[number]行,

    grep pattern1 | pattern2 files Q显C匹?pattern1 ?pattern2 的行Q?/p>

    grep pattern1 files | grep pattern2 Q显C既匚w pattern1 又匹?pattern2 的行?/p>

     

    参考文献:

    ——借此感谢在实习公司同事们l与的帮助,

    特别是Jay、Jeff?/p>



  • ]]>C++ Internals: STL之Maphttp://www.shnenglu.com/09212744/archive/2010/06/19/118235.html吴秦QSaylorQ?/dc:creator>吴秦QSaylorQ?/author>Sat, 19 Jun 2010 04:25:00 GMThttp://www.shnenglu.com/09212744/archive/2010/06/19/118235.htmlhttp://www.shnenglu.com/09212744/comments/118235.htmlhttp://www.shnenglu.com/09212744/archive/2010/06/19/118235.html#Feedback6http://www.shnenglu.com/09212744/comments/commentRss/118235.htmlhttp://www.shnenglu.com/09212744/services/trackbacks/118235.html概述

    Map是标?strong>兌式容?/strong>Q?em>associative containerQ之一Q一个map是一个键值对序列Q即Qkey ,valueQ对。它提供Zkey?strong>快?/strong>索能力,在一个map中key值是唯一的。map提供双向q代器,x从前往后的QiteratorQ,也有从后往前的Qreverse_iteratorQ?/p>

    map要求能对keyq行<操作Q且保持按key值递增有序Q因此map上的q代器也是递增有序的。如果对于元素ƈ不需要保持有序,可以使用hash_map?/p>

    map中key值是唯一的,如果马匹中已存在一个键值对(늧,密码):("skynet",407574364)Q而我们还x入一个键值对("skynet",472687789)则会报错Q?span style="color: #ff0000;">不是报错Q准的说是Q返回插入不成功Q?/span>Q。而我们又的确惌样做Q即一个键对应多个|q运的是multimap可是实现q个功能?/p>

    下面我们用实例来深入介绍map?em>multimapQ主要内容如下:

    • 1、例子引?
    • 2、map中的cd定义
    • 3、map中的q代器和键值对
    • 4、map中的构造函C析构函数
    • 5、map中的操作Ҏ
    • 6、再议map的插入操?
    • 7、[]不仅插入
    • 8、multimap
    • 9、ȝ

    1、例子引?/strong>

    有一个服务器managerl护着接入服务器的client信息Q包括clinetId、scanRate、socketAddr{等。我们定义一个结构体保存scanRate、socketAddr信息。如下:

    typedef    int    clientId;
    typedef struct{
    int scanRate;
    string socketAddr;
    }clientInfo;

    我们用map保存q些信息QclientId为键keyQclientInfo为倹{这h们可以通过clientId快速检索到client的相关信息,我们可以q样定义Q?/p>

    map<clientId,clientInfo> clientMap;

    q样我们定义了一个clientMapQ如果我们要定义多个q样的mapQ需要多ơ写map<clientId,clientInfo> 变量名。ؓ了避免这h况,我们通常为map<clientId,clientInfo>定义个别名,如:

    typedef map<clientId,clientInfo> clientEdp;
    clientEdp clientMap;

    之后我们可以像定义clientMap一样定义map<clientId,clientInfo>对象Q这L好处q有Q如果我们需要修改map的定义,只需要在一处修改即可,避免修改不彻底造成的不一致现象?/p>

    我们q就完成了需要的map的定义,如果不定义或没有在它上面的操作的话,像定义c而没有方法一P意义不大或毫无意义。幸q的是,STL提供了这些常用操作:排序Q注Qmap是不能也不要排序的,因ؓmap本n已经排好序了Q、打印、提取子部分、移除元素、添加元素、查扑֯象,像数据库的增删Ҏ操作Q现在我们详l介l这些操作,q步引入hash_map?em>multimap?/p>

    2、map中的cd定义

    兌数组Q?em>associative arrayQ是最有用的用户定义类型之一Q经常内|在语言中用于文本处理等。一个关联数l通常也称为mapQ有时也U字典(dictionaryQ,保存一对倹{第一个值称为key、第二个UCؓ映射值mapped-value?/p>

    标准map是定义在std命名I间中的一个模板,q表CZؓ<map>。它首先定义了一l标准类型名字:

    template<class Key,class T,class Cmp=less<key>,
    class A=allocator<pair<const Key,T>>
    class std::map
    {
    public:
    //types
    typedef Key    key_type;
    typedef T    mapped_type;
    typedef pair<const Key,T>    value_type;
    typedef    Cmp    key_compare;
    typedef A    allocator_type;
    typedef    typename    A::reference    reference;
    typedef    typename    A::const_reference    const_reference;
    typedef    implementation_define1    iterator;
    typedef implementation_define2    const_iterator;
    typedef    typename    A::size_type    size_type;
    typedef    typename    A::difference_type    difference_type;
    typedef    std::reverse_iterator<iterator>    reverse_iterator;
    typedef    std::reverse_iterator<const_iterator>    const_reverse_iterator;
    //...
    }

    注意Qmap的value_type是一?key,value)对,映射值的被认为是mapped_type。因此,一个map是一个pair<const Key,mapped_type>元素的序列。从const Key可以看出Qmap中键key是不可修改的?/p>

    不得不提的是map定义中Cmp和A都是可选项。Cmp是定义在元素之间的比较方法,默认?lt;操作QA即allocator用来分配?strong>释放map总键值对所需使用的内存,没有指定的话即默认用的是STL提供的,也可以自定义allocator来管理内存的使用。多数情况,我们不指定这两个选项而用默认|q样我们定义map像下面q样Q?/p>

    map<int,clientInfo> clientMap;

    Cmp和A都缺省?通常Q实际的q代器是实现定义的,因ؓmap很像使用了树的Ş式,q些q代器通常提供树遍历的某种形式。逆向q代器是使用标准的reverse_iterator模板构造的?/p>

    3、map中的q代器和键值对

    map提供惯常的返回P代器的一l函敎ͼ如下所C:

    template<class Key,class T,class Cmp=less<key>,
    class A=allocator<pair<const Key,T>>
    class std::map
    {
    public:
    //...
    //iterators
    iterator    begin();
    const_iterator    begin()    const;
    iterator    end();
    const_iterator    end()    const;
    reverse_iterator    rbegin();
    const_reverse_iterator    rbegin()    const;
    reverse_iterator    rend();
    const_reverse_iterator    rend()    const;
    //...
    }

    map上的q代器是pair<const Key,mapped_type>元素序列上简单的q代。例如,我们可能需要打印出所有的客户端信息,像下面的E序q样。ؓ了实现这个,我们首先向《例子引入》中定义的clientEdp中插入数据,然后打印出来Q?/p>

    #include<iostream>
    #include<map>
    #include<string>
    using namespace std;
    typedef    int    clientId;
    typedef struct{
    int scanRate;
    string socketAddr;
    }clientInfo;
    int main(int argc,char** argv)
    {
    typedef map<clientId,clientInfo> clientEdp;
    typedef map<clientId,clientInfo>::const_iterator iterator;
    clientEdp clients;
    clientInfo client[100];
    char str[10];
    string strAddr("socket addr client ");
    for(int i=0;i<100;i++)
    {
    client[i].scanRate=i+1;
    //convert int to char*
    itoa(i+1,str,10);
    //concatenate strAddr and str
    client[i].socketAddr=strAddr+str;
    cout<<client[i].socketAddr<<endl;
    clients.insert(
    make_pair(i+1,client[i]));
    }
    delete str;
    for(iterator i=clients.begin();i!=clients.end();i++)
    {
    cout<<"clientId:"<<i->first<<endl;
    cout<<"scanRate:"<<i->second.scanRate<<endl;
    cout<<"socketAddr:"<<i->second.socketAddr<<endl;
    cout<<endl;
    }
    }

    一个mapq代器以key升序方式表示元素Q因此客L信息以cliendId升序的方式输出。运行结果可以证明这一点,q行l果如下所C:

    image

    ?、程序运行结?/p>

    我们以first引用键值对的keyQ以second引用mapped valueQ且不用key和mapped value是什么类型。其实pair在std的模板中是这样定义的Q?/p>

    template <class    T1,class T2>struct std::pair{
    typedef    T1    first_type;
    typedef    T2    second_type;
    T1    first;
    T2    second;
    pair():first(T1()),second(T2()){}
    pair(const T1& x,const T2& y):first(x),second(y){}
    template<class U,class V>
    pair(const pair<U,V>& p):first(p.first),second(p.second){}
    }

    即map中,key是键值对的第一个元素且mapped value是第二个元素。pair的定义可以在<utility>中找刎ͼpair提供了一个方法方便创建键值对Q?/p>

    template <class T1,class T2>pair<T1,T2>
    std::make_pair(const T1& t1,const T2& t2)
    {
    return pair<T1,T2>(t1,t2);
    }

    上面的例子中我们qCq个Ҏ来创?clientId,clientInfo)对,q作为Insert()Ҏ的参数。每个pair默认初始化每个元素的gؓ对应cd的默认倹{?/p>

    4、map中的构造函C析构函数

    mapcL常提供了构造函数和析构函数Q如下所C:

    template<class Key,class T,class Cmp=less<key>,
    class A=allocator<pair<const Key,T>>
    class std::map
    {
    //...
    //construct/copy/destroy
    explicit map(const Cmp&=Cmp(),const A&=A());
    template<class In>map(In first,In last,
    const Com&=Cmp(),const A&=A());
    map(const map&);
    ~map();
    map& operator=(const map&);
    //...
    }

    复制一个容器意味着为它的每个元素分配空_q拷贝每个元素倹{这样做是性能开销是很大的Q应该仅当需要的时候才q样做?strong>因此Qmap传的是引?/strong>?/p>

    5、map中的操作Ҏ

    前面我们已经说过Q如果map中仅定义了一些key、mapped valuecd的信息而没有操作方法,如定义个仅有字D늚cL义不大甚x无意义。由此可见map中定义操作方法非帔R要!前面的例子我们就用到了不方法,如返回P代器的方法begin()、end()Q键值对插入Ҏinsert()。下面我们对map中的操作Ҏ做个全面的介l:

    template<class Key,class T,class Cmp=less<key>,
    class A=allocator<pair<const Key,T>>
    class std::map
    {
    //...
    //map operations
    //find element with key k
    iterator find(const key_type& k);
    const_iterator find(const key_type& k) const;
    //find number of elements with key k
    size_type count() const;
    //find first element with key k
    iterator lower_bound(const key_type& k);
    const_iterator lower_bound(const key_type& k) const;
    //find first element with key greater than k
    iterator upper_bound(const key_type& k);
    const_iterator upper_bound(const key_type& k) const;
    //insert pair(key,value)
    pair<iterator,bool>insert(const value_type& val);
    iterator insert(iterator pos,const value_type& val);
    template<class In>void insert(In first,In last);
    //erase element
    void erase(iterator pos);
    size_type erase(const key_type& k);
    void erase(iterator first,iterator last);
    void clear();
    //number os elements
    size_type size() const;
    //size of largest possible map
    size_type max_size() const;
    bool empty() const{return size()==0;}
    void swap(map&);
    //...
    }

    上面q些Ҏ基本都能֐思义QPS.由此可见Q命名有多重要,我们qx要养成好的命名习惯,当然注释也必不可!Q。虽然已l非常清楚了了,但我q是惌解一下以消除不惜要的误解和更好地应用q些Ҏ?/p>

    • find(k)Ҏ单地q回键gؓk的元素的q代器;如果没有元素的键gؓkQ则q回map的end()q代器。由于map是按键key升序排列Q所有查扄复杂度只有O(logN)。因此,我们通常会这Lq个ҎQ?
      #include<iostream>
          #include<map>
          #include<string>
          using namespace std;
          typedef    int    clientId;
          typedef struct{
          int scanRate;
          string socketAddr;
          }clientInfo;
          int main(int argc,char** argv)
          {
          typedef map<clientId,clientInfo> clientEdp;
          typedef map<clientId,clientInfo>::const_iterator iterator;
          clientEdp clients;
          clientInfo client[100];
          char* str=new char[10];
          string strAddr("socket addr client ");
          for(int i=0;i<100;i++)
          {
          client[i].scanRate=i+1;
          //convert int to char*
          itoa(i+1,str,10);
          //concatenate strAddr and str
          client[i].socketAddr=strAddr+str;
          clients.insert(
          make_pair(i+1,client[i]));
          }
          delete str;
              clientId id=10;
          iterator i=clients.find(id);
          if(i!=clients.end()){
          cout<<"clientId: "<<id
          <<" exists in clients"<<endl;
          }
          else{
          cout<<"clientId: "<<id
          <<" doesn't exist in clients"<<endl;
          }
          }
    • insert()Ҏ 试图一个(Key,TQ键值对加入map。因为键时唯一的,所以仅当map中不存在键gؓk的键值对时插入才成功。该Ҏ的返回gؓpair<iterator,bool>Q如果插入成功boolgؓTRUEQiterator指向插入map中后的键值对。如下代码:
      #include<iostream>
          #include<map>
          #include<string>
          using namespace std;
          typedef    int    clientId;
          typedef struct{
          int scanRate;
          string socketAddr;
          }clientInfo;
          int main(int argc,char** argv)
          {
          typedef map<clientId,clientInfo> clientEdp;
          typedef map<clientId,clientInfo>::const_iterator iterator;
          clientEdp clients;
          clientId id=110;
          clientInfo cltInfo;
          cltInfo.scanRate=10;
          cltInfo.socketAddr="110";
          pair<clientId,clientInfo> p110(id,cltInfo);
          pair<iterator,bool> p=clients.insert(p110);
          if(p.second){
          cout<<"insert success!"<<endl;
          }
          else{
          cout<<"insert failed!"<<endl;
          }
          //i points to clients[110];
          iterator i=p.first;
          cout<<i->first<<endl;
          cout<<i->second.scanRate<<endl;
          cout<<i->second.socketAddr<<endl;
          }

    上面我们看出Q这里我们插入键值对是首先声明一个键值对pair<clientId,clientInfo> p110(id,cltInfo); 然后再插入,q个我们之前make_pairҎ不一Pmake_pairҎ用的比较多?/p>

    • erase()Ҏ用法比较单,比如像清除clientId?10的键值对Q我们只需要对clients调用eraseҎQ?span style="color: #ff8040;">clients.erase(clients.find(110));或者我们想清除clientId??0的键值对Q我们可以这栯用erase()ҎQ?span style="color: #ff8040;">clients.erase(clients.finds(1),clients.find(10));单吧Q别得意Q你q需要注意,如果find(k)q回的是end()Q这栯用erase()Ҏ则是一个严重的错误Q会对map造成破坏操作?

    6、再议map的插入操?/strong>

    前面我们介绍了利用map的插入方法insert()Q声明键值对pair或make_pair生成键值对然后我们可以L的将键值对插入map中。其实mapq提供了更方便的插入操作利用下标QsubscriptingQ[]Q操作,如下Q?/p>

    clientInfo cltInfo;
    cltInfo.scanRate=10;
    cltInfo.socketAddr="110";
    clients[110]=cltInfo;

    q样我们可以简单地键值对插入到map中了。下标操作在map中式q样定义的:

    template<class Key,class T,class Cmp=less<key>,
    class A=allocator<pair<const Key,T>>
    class std::map
    {
    //...
    //access element with key k
    mapped_type& operator[](const key_type& k);
    //...
    }

    我们来分析一下应用[]操作Q插入键值对的过E:查键k是否已经在map里。如果不Q就d上,以v作ؓ它的对应倹{如果k已经在map里,它的兌D更新成v。这里首先,查找110不在map中则创徏一个键?10的键值对Qƈ映D为默认|q里scanRate?QsocketAddr为空Q然后将映射D为cltInfo?如果110在map中已l存在的话,则只是更C110为键的映倹{?/p>

    从上面的分析可知Q如果大量这h入数据,会严重媄响效率!如果你考虑效率问题Q请使用insert操作。insertҎQ节省了三次函数调用Q一个徏立时的默认映射值的对象Q一个销毁那个时的对象和一个对映射值的赋值操作?/p>

    Note1Q?/strong>如果k已经存在map中,[]效率反而比insert的效率高Q而且更美观!如果能够兼顾q两者那岂不是很妙Q其实我们重写map中的[]操作Q首先判断k是否已经在map中,如果没有则调用insert操作Q否则调用内|的[]操作。如下列代码Q?/p>

    //////////////////////////////////////////////
    ///@param MapType-map的类型参?
    ///@param KeyArgType-键的cd参数
    ///@param ValueArgtype-映射值的cd参数
    ///@return q代器,指向键ؓk的键值对
    //////////////////////////////////////////////
    template<typename MapType,
    typename KeyArgType,
    typename ValueArgtype>
    typename MapType::iterator
    efficientAddOrUpdate(MapType& m,
    const KeyArgType& k,
    const ValueArgtype& v)
    {
    typename MapType::iterator Ib =    m.lower_bound(k);
    if(Ib != m.end()&&!(m.key_comp()(k,Ib->first))) {
    //key已经存在于map中做更新操作
    Ib->second = v;
    return Ib;
    }
    else{
    //key不存在map中做插入操作
    typedef typename MapType::value_type MVT;
    return m.insert(Ib, MVT(k, v));
    }
    }

    Note2Q?/strong>我们视乎q忽略了一点,如果映射值mapped value的类型没有默认|怎么办?q种情况请勿使用[]操作插入?/p>

    7、[]不仅插入

    通过[]操作不仅仅是插入键值对Q我们也可以通过键key索出映射值mapped value。而且我们利用[]操作可以L地统计信息,如有q样q样一些键值对Qbook-nameQcountQ对Q?/p>

    (book1,1)?book2,2)?book1,2)?book3,1)?book3,5)

    我们计算每种book的数量d。我们可以这样做Q将它们d一个map<string,int>Q?/p>

    #include<iostream>
    #include<map>
    #include<string>
    using namespace std;
    int main(int argc,char** argv)
    {
    map<string,int> bookMap;
    string book;
    int count;
    int total=0;
    while(cin>>book>>count)
    bookMap[book]+=count;
    map<string,int>::iterator i;
    for(i=bookMap.begin();i!=bookMap.end();i++)
    {
    total+=i->second;
    cout<<i->first<<'\t'<<i->second<<endl;
    }
    cout<<"total count:"<<total<<endl;
    }

    l果如下所C:Q注意按住ctrl+z键结束输入)

    image

    ?、程序运行结?/p>

    8、multimap

    前面介绍了mapQ可以说已经非常清晰了。如果允许clientId重复的话Qmap无能ؓ力了Q这时候就得multimap上场了!multimap允许键key重复Q即一个键对应多个映射倹{?/strong>其实除此之外Qmultimap跟map是很像的Q我们接下来在map的基上介lmultimap?/p>

    multimap在std中的定义跟map一样只是类名ؓmultimapQmultimap几乎有map的所有方法和cd定义?/p>

    • multimap不支持[]操作Q但map支持
    • multimap的insertҎq回的是一个P代器iteratorQ没有bool|而map|iteratorQboolQ的元素?
    • 对应equal_range()、方法:
      pair<iterator,iterator> equal_range(const key_type& k);
          pair<const_iterator,const_iterator>
          equal_range(const key_type& k) const;
          //find first element with key k
          iterator lower_bound(const key_type& k);
          const_iterator lower_bound(const key_type& k) const;
          //find first element with key greater than k
          iterator upper_bound(const key_type& k);
          const_iterator upper_bound(const key_type& k) const;
      虽然在map和multimap都有Q显然对multimap有更多的意义Qequal_range()Ҏq回一个键key对应的多个映值的上界和下界的键值对的P代器、lower_bound()Ҏq回键multimap中第一个箭为key的键值对q代器、upper_bound()Ҏq回比key大的W一个键值对q代器?

    假设我们惛_出键为key的所有映|我们可以q样做:

    #include<iostream>
    #include<map>
    #include<string>
    using namespace std;
    typedef int clientId;
    typedef struct{
    int scanRate;
    string socketAddr;
    }clientInfo;
    int main(int argc,char** argv)
    {
    typedef multimap<clientId,clientInfo> clientEdp;
    typedef multimap<clientId,clientInfo>::const_iterator iterator;
    clientEdp clients;
    clientInfo client[20];
    char* str=new char[10];
    string strAddr("socket addr client ");
    for(int i=0;i<10;i++)
    {
    client[i].scanRate=i+1;
    //convert int to char*
    itoa(i+1,str,10);
    //concatenate strAddr and str
    client[i].socketAddr=strAddr+str;
    clients.insert(
    make_pair(10,client[i]));
    }
    for(int i=10;i<20;i++)
    {
    client[i].scanRate=i+1;
    //convert int to char*
    itoa(i+1,str,10);
    //concatenate strAddr and str
    client[i].socketAddr=strAddr+str;
    clients.insert(
    make_pair(i+1,client[i]));
    }
    delete str,strAddr;
        //find elements with key 10
    iterator lb=clients.lower_bound(10);
    iterator ub=clients.upper_bound(10);
    for(iterator i=lb;i!=ub;i++)
    {
    cout<<"clientId:"<<i->first<<endl;
    cout<<"scanRate:"<<i->second.scanRate<<endl;
    cout<<"socketAddr:"<<i->second.socketAddr<<endl;
    cout<<endl;
    }
    }

    Q说明:实际上,一般是不允许clientId重复的,q里只是Z举例。)q样是不是感觉很丑呢Q事实上Q我们可以更单的q样Q?/p>

    //find elements with key 10
    pair<iterator,iterator> p=clients.equal_range(10);
    for(iterator i=p.first;i!=p.second;i++)
    {
    cout<<"clientId:"<<i->first<<endl;
    cout<<"scanRate:"<<i->second.scanRate<<endl;
    cout<<"socketAddr:"<<i->second.socketAddr<<endl;
    cout<<endl;
    }

    ȝ

    map是一cd联式容器。它的特Ҏ增加和删除节点对q代器的影响很小Q除了那个操作节点,对其他的节点都没有什么媄响。对于P代器来说Q可以修改实|而不能修改key?

    map的功能:

    • 自动建立Key Qvalue的对应。key 和value可以是Q意你需要的cd?
    • Ҏkey值快速查找记录,查找的复杂度基本是Log(N)?
    • 快速插入Key - Value 记录?
    • 快速删除记?
    • ҎKey 修改value记录?
    • 遍历所有记录?

    展望Q本文不知不觉写了不字了,但仍未深入涉及到map定义的第3个和W?个参敎ͼ使用的都是默认倹{?/p>

    template<class Key,class T,class Cmp=less<key>,
        class A=allocator<pair<const Key,T>>

    感兴者,h扄兌料or下面留言希望看到单独开介lmapW?个和W?个参数。您的支持,我的动力QPSQ在此文的原因,在与公司做项目用CmapҎȝ出来与大家共享,不过在进行个人ȝq程中,隑օ会有疏漏或不当之处,请不吝指出?/p>

    参考文献:

    ?】《The C++ Programming Language (Special Edition)?/p>

    ?】《Effective STL?/p>

    ]]> av˾þۺɫ| Ʒþþþþþþþ | 99þþƷһ | žžþþƷר| þþþþþ92| Ʒþþþþþþþ| þþһƷ99þþƷ88| 97þþþ| ھƷ˾þþþAVӰԺ| ձƷþþĻ| ҹAVëƬþ| Ʒþþþþ| þþƷа| þ99Ʒ99þ| þþþ99оƷ10| 鶹ŷۺϾþ | ŷһþþƷ| ŷһþ| þùֱ| ҹƷþӰԺ| һۺϾþ| þþƷž޾Ʒ| ƷŮþøվ| 91Ʒۿ91þþþþ| ޾Ʒרþþ| 㽶þ99| þó18վ| þ޾ƷĻ| þþһƷ99þþƷ66| þݺҹҹ2014| þþۺ㽶ۺ| žȾþƵ| þþþ޾Ʒַ| þþþ99ƷƬ| Ʒþþþþ˳| Ůþþþþjþ| þ޹Ʒһ| ҹҹþ| þþƷһӰ| þþþùɫAVѿͼƬ| ŷҹͽþþ|