青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

ACM___________________________

______________白白の屋
posts - 182, comments - 102, trackbacks - 0, articles - 0
<2010年8月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234

常用鏈接

留言簿(24)

隨筆分類(332)

隨筆檔案(182)

FRIENDS

搜索

積分與排名

最新隨筆

最新評論

閱讀排行榜

評論排行榜

STL 中的搜索

Posted on 2010-08-25 11:35 MiYu 閱讀(181) 評論(0)  編輯 收藏 引用 所屬分類: ACM_資料
代碼
    在一個(gè)集合中找到一個(gè)特別的條目是個(gè)很重要的問題,標(biāo)準(zhǔn)C++運(yùn)行庫提供了許多不同的搜索技術(shù)。
    在 C
++運(yùn)行庫中,指明一個(gè)集合的常用方法是通過iterator指示出區(qū)間。區(qū)間可以被寫為[first, last), 此處,*first是區(qū)間內(nèi)的第一個(gè)元素而last則指向最后一個(gè)元素的下一個(gè)。本文展示了我們?nèi)绾慰紤]一個(gè)通用問題:給定一個(gè)區(qū)間和一個(gè)準(zhǔn)則,找到指向第一個(gè)滿足準(zhǔn)則的元素的iterator。因?yàn)槲覀儗^(qū)間表示為不對稱的形式,于是避開了一個(gè)特殊情況:搜索失敗可以返回last,沒有任何 元素的區(qū)間可以寫為[i, i)。

線性搜索和它的變種

    最簡單的搜索是線性搜索,或,如Knuth所稱呼的,順序搜索:依次查看每個(gè)元素,檢查它是否為我們正在搜索的那個(gè)。如果區(qū)間中有N個(gè)元素,最壞的情況就需要N次比較。
    標(biāo)準(zhǔn)運(yùn)行庫提供了線性搜索的一些版本;兩個(gè)最重要的版本是find() (它接受一個(gè)區(qū)間和值x,并查找等價(jià)于x的元素)和find_if()(接受一個(gè)區(qū)間和判決條件p,并查找滿足p的元素)。線性搜索的其它版本是 find_first_of()(接受兩個(gè)區(qū)間,[first1,last1)和[first2,last2) ,并在[first1, last1)中查找第一個(gè)等價(jià)于[first2, last2)中任何一個(gè)元素的元素)和adjacent_find()(接受單一區(qū)間,并查找第一個(gè)等價(jià)于其后繼元素的元素)。
    舉例來說,假如,v是一個(gè)int的vector。你能用下面的代碼查找第一個(gè)0:
vector
<int>::iterator i =  find(v.begin(), v.end(), 0);  

查找第一個(gè)非0值:
vector
<int>::iterator i =  find_if(v.begin(), v.end(), not1(bind2nd(equal_to<int>(), 0)));

查找第一個(gè)小質(zhì)數(shù):
A[
4= { 2357 };
vector
<int>::iterator i =  find_first_of(v.begin(), v.end(), A+0, A+4);

找到第一個(gè)重復(fù)對:
vector
<int>::iterator i =  adjacent_find(v.begin(), v.end());

    沒有任何獨(dú)立版本以對區(qū)間進(jìn)行逆向搜索,因?yàn)槟悴恍枰耗隳苡靡粋€(gè)簡單的iterator adaptor來達(dá)到相同的效果。比如,在v中找到最后一個(gè)0,可以這么寫:
 vector
<int>::reverse_iterator i =  find(v.rbegin(), v.rend(), 0);

    線性搜索是一個(gè)簡單的算法,它的實(shí)現(xiàn)看起來沒什么可討論的。許多書(包括我的)展示了std::find()的一個(gè)簡單的實(shí)現(xiàn):
template 
<class InIter, class T>
InIter find(InIter first, InIter last, 
const T& val)
{
  
while (first != last && ! (*first == val))  ++first;
  
return first;
}

    這的確是線性搜索算法的一個(gè)忠實(shí)的實(shí)現(xiàn),滿足C
++標(biāo)準(zhǔn)的需求;第一個(gè)模板參數(shù)的名字,InIter,意味著實(shí)參只需要是非常弱的Input Iterator[注1]。它看起來可能是如此的簡單,以致于還不如在代碼中直接手寫出來。雖然如此,還是有一個(gè)令人懊惱的問題:這個(gè)實(shí)現(xiàn)沒有達(dá)到它應(yīng)該的效率。循環(huán)條件很復(fù)雜,需要為取得的每個(gè)元素作兩個(gè)測試。有條件的分支昂貴的,并且復(fù)雜的循環(huán)條件不會得到與簡單的循環(huán)條件同樣程度的優(yōu)化。
    問題的答案之一,并是被某些標(biāo)準(zhǔn)運(yùn)行庫的實(shí)作所采用[注2],是“解開”循環(huán),每次檢查4個(gè)元素。這是比較復(fù)雜的解決方法,因?yàn)閒ind()然后必須處理殘余元素(區(qū)間不會總是4的倍數(shù)),以及它還需要find()基于Iterator的種類進(jìn)行分解--“解開”只能工作于Random Access Iterator指示的區(qū)間,對一般情況還是需要使用老的實(shí)現(xiàn)。但是,“解開”是有效果的:它將對每個(gè)元素的測試的數(shù)目從2降到 
1.25。它是標(biāo)準(zhǔn)庫的實(shí)現(xiàn)人員不需要改動任何接口就能采用的技術(shù)。
    你將會在講述算法的常見書籍中看到一個(gè)不同的答案。需要對每個(gè)元素作兩次測試的原因是,如果到達(dá)區(qū)間結(jié)束還沒有找到所要找的元素,我們必須承認(rèn)已經(jīng)失敗。但是如果我們碰巧所要查找的元素總是存在,搜索絕不會失敗時(shí),會怎么樣?在那種情況下,為區(qū)間結(jié)束作的測試是多余的;會沒有任何的理由認(rèn)為搜索算法應(yīng)該首先 掌握區(qū)間結(jié)束的信息(there wouldn’t be any reason 
for the search algorithm to keep track of the end of the range in the first place)。取代std::find(),我們可以如下實(shí)現(xiàn)線性搜索算法:
template 
<class InIter, class T>
InIter unguarded_find(InIter first, 
const T& val)
{
  
while (!(*first==val)) ++first;
}

    Knuth 的線性搜索版本[注3]更接近unguarded_find()而不是std::find()。注意,unguarded_find()不是C
++標(biāo)準(zhǔn)的 一部分。它比find()危險(xiǎn),通用性上也稍差。你只能在確保有一個(gè)元素等價(jià)于val時(shí)使用它--這通常意味著你自己已經(jīng)將那個(gè)元素放在里面了,并作為區(qū) 間結(jié)束的哨兵。使用哨兵并不總是成立。(如果你正在搜索的是一個(gè)只讀區(qū)間怎么辦?)但當(dāng)它可用時(shí),unguarded_find()比標(biāo)準(zhǔn)庫中的所有東西都更快,更簡單。
二分搜索

    線性搜索很簡單,并且對于小區(qū)間,它是最好的方法。然而,如果區(qū)間越來越長,它就不再是合理的解決方案了。在最近使用XSLT的時(shí)候,我想起這個(gè)問題。我的XSLT腳本包括了一個(gè)類似于這樣的一行:
<x:value-of select="/defs/data[@key=$r]"/>
    我用來跑這個(gè)的XSLT引擎肯定是使用的線性搜索。我在一個(gè)list中搜索,并對list中的每個(gè)條目執(zhí)行了這個(gè)搜索。我的腳本是O(N2)的,它運(yùn)行需要花幾分鐘。
    如果你正在搜索一個(gè)完全一般的區(qū)間,不能比線性搜索做得更好了。你必須檢查每一個(gè)元素,否則你漏掉的可能就是你正在尋找的。但如果你要求這個(gè)區(qū)間是以某種方式組織的,你就可以做得更好了。
    比如,你可以要求區(qū)間是已排序的。如果有一個(gè)已序區(qū)間,就可以使用線性搜索的一個(gè)改良版本(當(dāng)你到達(dá)一個(gè)比所尋找的元素更大的元素時(shí),不需要繼續(xù)到區(qū)間結(jié)束就可以知道搜索已經(jīng)失敗了),但更好的方法是使用二分搜索。通過查看區(qū)間中央的元素,你就可以說出所搜索的元素在前半部分還是后半部分;重復(fù)這個(gè)分解過 程,你不需要遍歷所有元素就能找到要找的元素。線性搜索需要O(N)的比較,而二分搜索只需要O(log N)。
    標(biāo)準(zhǔn)運(yùn)行庫包含二分搜索的四個(gè)不同版本:lower_bound(),upper_bound(),equal_range()和 binary_search()。他們?nèi)慷加兄嗤男问剑航邮芤粋€(gè)區(qū)間、一個(gè)試圖查找的元素,和可選的比較函數(shù)。區(qū)間必須是根據(jù)此比較函數(shù)進(jìn)行過排序 的;如果不提供比較函數(shù),它必須是根據(jù)通常的“
<”運(yùn)算排序的。于是,舉例來說,如果你正在一個(gè)升序排序的int數(shù)組中搜索時(shí),你可以使用默認(rèn)行為。如果在一個(gè)降序排序的int數(shù)組中搜索時(shí),你可以傳入一個(gè)std::greater<int>作為比較函數(shù)。
    在四個(gè)二分搜索函數(shù)中,最沒用的一個(gè)是名字最一目了然的那個(gè):binary_search()。它所返回是簡單的yes或no:存在于區(qū)間中時(shí)返回 
true,否則為false。但光這么一個(gè)信息沒什么用;我從未遇到什么場合來使用binary_search()。如果你想搜索的元素存在,你可能想知 道它的位置;如果不存在,你可能想知道如果它存在,這個(gè)位置是哪里。
    關(guān)于元素的位置,你可以想問幾個(gè)不同的問題,而這正是二分搜索的幾個(gè)不同版本存在的原因。當(dāng)相同的元素存在好幾個(gè)拷貝時(shí),它們的區(qū)別就很重要了。舉例來說,假如你有一個(gè)int的數(shù)組,然后使用lower_bound()和upper_bound()都找尋同一個(gè)值:
int A[10= { 1235555789 };
int* first = std::lower_bound(A+0, A+105);
int* last = std::upper_bound(A+0, A+105);

    名字first和last暗示了區(qū)別:lower_bound()返回第一個(gè)你正在尋找的數(shù)值(對本例,是
&A[3]),而upper_bound ()返回最后一個(gè)你正尋找的值的下一個(gè)的iterator(對本例,是&A[7])。
    如果你搜索的值不存在,你將得到如果它存在的話,應(yīng)該位于的位置。和前面一樣,我們可以寫:
int* first = std::lower_bound(A+0, A+106);
int* last = std::upper_bound(A+0, A+106);

    first和last都將等于
&A[7],因?yàn)檫@是6在不違背排序時(shí)可以插入的唯一位置。
    實(shí)踐中,你看不到lower_bound()的調(diào)用后面立即跟一個(gè)upper_bound()。如果你同時(shí)需要這兩個(gè)信息,那正是引入最后一個(gè)二分搜索算法的原因:equal_range()返回一個(gè)pair,第一個(gè)元素是lower_bound()將要返回的值,第二個(gè)元素是upper_bound()的 返回值。
    直到此時(shí),我在討論中故意比較粗略:我說了lower_bound()和upper_bound()找一個(gè)值,但沒有正確說明它的含義。如果你寫
iterator i 
= std::lower_bound(first, last, x); 

而且搜尋成功,你保證 
*i 和 x 相等嗎?不一定!lower_bound()和upper_bound()從不對等價(jià)性進(jìn)行測試(WQ注:邏輯相等,使用operator==())。它們使用你提供的比較函數(shù):operator<()或其它一些功能象“less than”的比較函數(shù)。這意味著在*i不小于x并且x不小于*i時(shí),搜索成功(WQ注,即等值性,數(shù)學(xué)相等)。
    這個(gè)區(qū)別看起來象吹毛求疵,但它不是。假如你一些具有很多字段的復(fù)雜記錄,你使用其中的一個(gè)字段作為排序的key值(比如,人的姓)。兩個(gè)記錄可能有相同的key值,于是,即使所有其它子段都是不同的,它們哪一個(gè)也不小于另外一個(gè)。
    一旦開始想到記錄和key值,二分搜索的另外一個(gè)問題就變得很自然了:你能用二分搜索根據(jù)key來搜索記錄嗎?更具體些,假設(shè)我們定義了一個(gè)struct X:
struct X {
  
int id;
  ... 
// other fields
};

再假設(shè)有一個(gè)vector
<X>,根據(jù)元素的id進(jìn)行過排序。你如何使用二分搜索來找到一個(gè)指定id(比如148)的X?
    一個(gè)方法是創(chuàng)建一個(gè)有著指定的id啞X對象,并在二分搜索中使用它:
X dummy;
 dummy.id 
= 148;
 vector
<X>::iterator = lower_bound(v.begin(), v.end(), dummy, X_compare);

    目前而言,這是最可靠的方法。如果你關(guān)心最大程度的可移植性,它是你所應(yīng)該使用的方法。另一方面,它不是非常優(yōu)雅。你必須創(chuàng)建一個(gè)完整的X對象,雖然你需要的只是其中一個(gè)字段;其它字段不得不被初始化為默認(rèn)值或隨機(jī)值。那個(gè)初始化可能是不方便的,昂貴的,或有時(shí)甚至不可能的。
    可能直接將id傳給lower_bound()嗎?也許,通過傳入一個(gè)異質(zhì)比較函數(shù),它接受一個(gè)X和一個(gè)id?這個(gè)問題沒有一個(gè)簡單的答案。C
++標(biāo)準(zhǔn)沒有 完全說清楚是否允許這樣的異質(zhì)比較函數(shù);依我之見,對標(biāo)準(zhǔn)的最自然的讀解是不允許。在現(xiàn)今的實(shí)踐中,異質(zhì)比較函數(shù)在一些實(shí)作上可行,而在另外一些上不行。 另一方面,C++標(biāo)準(zhǔn)化委員會認(rèn)為這是一個(gè)缺陷,并且在未來版本的標(biāo)準(zhǔn)將明確是否允許異質(zhì)比較函數(shù)[注4]。
總結(jié)

C
++運(yùn)行庫還提供了其它一些形式的搜索算法。使用find()和lower_bound(),搜索只限于單個(gè)元素,但標(biāo)準(zhǔn)運(yùn)行庫還提供了serach(),它尋找整個(gè)子區(qū)間。比如,你可以在一個(gè)字符串s中搜索一個(gè)單詞:
std::
string the = "the";
std::
string::iterator i = std::search(s.begin(), s.end(), the.begin(), the.end());

返回值,i,將指向“the”在s中第一次出現(xiàn)的開始處--或,和往常一樣,如果“the”不存在將返回s.end()。還有一個(gè)變種以從尾部開始搜索:
std::find_end(s.begin(), s.end(), the.begin(), the.end());

    它返回一個(gè)iterator,指向“the”最后出現(xiàn)處的開始,而不是第一個(gè)。(如果你認(rèn)為這很奇怪,search的逆向變種叫find_end()而不是search_end(),那么你并不孤獨(dú)。)
    搜索可以被封裝入數(shù)據(jù)結(jié)構(gòu)。最明顯地,標(biāo)準(zhǔn)運(yùn)行庫的關(guān)聯(lián)容器,
set、multiset、map和multimap,被特別設(shè)計(jì)為根據(jù)key進(jìn)行搜索將很高 效[注5]。運(yùn)行庫的string類也提供了許多搜索用的成員函數(shù):find()、rfind()、find_first_of()、 find_last_of()、find_first_not_of()和find_last_not_of()。我建議避免使用它們。我發(fā)現(xiàn)這些特殊的 成員函數(shù)難以記憶,因?yàn)樗鼈儞碛腥绱硕嗟男问剑⑶医涌谛问脚c運(yùn)行庫的其它部分不同;無論如何,他們不會提供任何不能從find()、find_if ()、search()得到的功能。
    但是,如果你仍然認(rèn)為看到了一些重要的省略,你是正確的!我沒有提到hash表,因?yàn)闃?biāo)準(zhǔn)運(yùn)行庫中沒有hash表。我提到了search()的子區(qū)間匹配,但那當(dāng)然只是模式匹配的一個(gè)特例--標(biāo)準(zhǔn)運(yùn)行庫中沒有正則表達(dá)式搜索或任何類似的東西。
    C
++標(biāo)準(zhǔn)化委員會剛剛開始考慮對標(biāo)準(zhǔn)運(yùn)行庫擴(kuò)充,而hash表和正則表達(dá)式是未來版本的標(biāo)準(zhǔn)的優(yōu)先候選者。如果你認(rèn)為標(biāo)準(zhǔn)運(yùn)行庫缺少了什么,并且你想提交一份提議,那么現(xiàn)在是你應(yīng)該開始準(zhǔn)備時(shí)候了。

 

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一本不卡影院| 欧美一二三区精品| 日韩亚洲精品在线| 一区二区三区四区五区精品视频 | 亚洲一区二区影院| 亚洲精品乱码久久久久久| 欧美国产日韩精品| 亚洲一级网站| 免费永久网站黄欧美| 亚洲第一黄网| 久久天天躁狠狠躁夜夜av| 亚洲精选国产| 蜜乳av另类精品一区二区| 日韩视频在线一区二区| 一本色道久久综合亚洲精品高清| 亚洲五月婷婷| 欧美**人妖| 亚洲欧美视频在线观看视频| 国产精品视频免费观看| 亚洲欧美一区二区原创| 在线亚洲精品| 亚洲欧洲三级电影| 精品99视频| 亚洲看片免费| 香蕉乱码成人久久天堂爱免费 | 免费久久99精品国产| 国产精品美女视频网站| 欧美高清在线一区| 男人天堂欧美日韩| 国产精品二区二区三区| 欧美视频亚洲视频| 欧美午夜视频在线观看| 亚洲理论在线| 午夜精品福利一区二区蜜股av| 欧美国产综合视频| 欧美午夜大胆人体| 国产亚洲精品美女| 亚洲精品免费一区二区三区| 亚洲一区二区精品在线观看| 久久综合久色欧美综合狠狠| 亚洲春色另类小说| 欧美淫片网站| 国产欧美一区二区三区在线看蜜臀| 欧美第十八页| 久久久久综合网| 久久久亚洲欧洲日产国码αv| 久久九九免费视频| 久久综合电影一区| 亚洲三级性片| 亚洲免费在线视频| 免费成人高清| 午夜精品久久久久久99热| 欧美中文字幕| 久久狠狠婷婷| 免费在线欧美视频| 亚洲另类在线一区| 国产精品一区视频网站| 欧美日韩国产黄| 国产精品草莓在线免费观看| 一本色道久久综合亚洲精品不| 欧美日韩一区二区在线| 欧美一级淫片aaaaaaa视频| 一个色综合av| 亚洲日本免费电影| 国产女主播一区二区三区| 一本色道久久| 国产欧美短视频| 欧美日韩亚洲综合一区| 国产精品一区二区三区久久| 久热精品在线视频| 亚洲欧美另类国产| 亚洲欧美在线免费| 欧美成人午夜激情在线| 久久久久国色av免费看影院 | 亚洲色图制服丝袜| 亚洲国产裸拍裸体视频在线观看乱了中文 | 国产精品人成在线观看免费| 久久成人免费| 久久最新视频| 亚洲二区视频在线| 女人天堂亚洲aⅴ在线观看| 亚洲国产一区二区a毛片| 亚洲免费婷婷| 欧美专区在线观看一区| 一本色道久久88综合亚洲精品ⅰ| 久久国产精品一区二区三区| 亚洲激情视频网| 亚洲图片欧美一区| 欧美色综合天天久久综合精品| 亚洲国产精品悠悠久久琪琪| 亚洲国产欧美久久| 久久嫩草精品久久久久| 亚洲精品1区2区| 午夜在线成人av| 国产精品亚洲欧美| 狼人天天伊人久久| 亚洲日韩视频| 日韩系列欧美系列| 欧美国产综合| 亚洲精品久久嫩草网站秘色| 亚洲福利视频网站| 久久国产高清| 久久免费国产精品| 国产精品国产一区二区| 久久精品中文字幕一区| 午夜精品久久久久久99热软件| 亚洲精品极品| 亚洲一区二区三区四区五区黄 | 中文日韩电影网站| 久久一二三国产| 久久成人av少妇免费| 亚洲一区久久| 99re这里只有精品6| 欧美大胆a视频| 亚洲国产网站| 亚洲自拍偷拍网址| 黑人极品videos精品欧美裸| 欧美日韩一区二区在线观看视频 | 国产农村妇女精品一二区| 亚洲砖区区免费| 久久久久久欧美| 免费中文日韩| 欧美三区在线| 久久精品综合网| 欧美成人午夜免费视在线看片 | 久久久亚洲综合| 欧美成人精品三级在线观看| 亚洲一区欧美激情| 亚洲网站在线| 久久久精品日韩欧美| 1000精品久久久久久久久| 欧美专区亚洲专区| 欧美日韩精选| 欧美伊人久久| 欧美华人在线视频| 欧美成人三级在线| 国产三区精品| 亚洲黄色天堂| 欧美中文字幕不卡| 久久不射网站| 狠狠久久综合婷婷不卡| 激情一区二区三区| 在线综合亚洲欧美在线视频| 国产精品爽爽ⅴa在线观看| 免费久久精品视频| 国产日韩欧美夫妻视频在线观看| 亚洲三级电影在线观看| 国产精品日韩欧美综合| 欧美激情亚洲另类| 亚洲精品乱码久久久久久蜜桃麻豆| 欧美a级理论片| 亚洲国产日本| 欧美**字幕| 亚洲欧美在线一区二区| 国产精品视频专区| 性色av一区二区三区| 欧美mv日韩mv国产网站app| 欧美激情一区二区三区不卡| 亚洲欧洲日本一区二区三区| 欧美在线欧美在线| 夜夜精品视频一区二区| 国产精品在线看| 久久九九免费| 国产精品免费看片| 亚洲一品av免费观看| 久久九九99视频| 欧美国产日韩一区| 亚洲欧美日韩网| 在线一区二区三区做爰视频网站 | 欧美日韩a区| 亚洲伦理在线观看| 蜜桃久久av| 午夜精品久久久久久| 91久久综合亚洲鲁鲁五月天| 欧美日韩成人在线视频| 鲁大师成人一区二区三区| 极品少妇一区二区| 欧美成人免费在线| 亚洲视频专区在线| 亚洲精品黄色| 免费日韩成人| 久久综合五月天婷婷伊人| 亚洲一区视频在线观看视频| 久久久中精品2020中文| 在线视频亚洲一区| 欧美激情一二三区| 欧美成人精品三级在线观看| 猫咪成人在线观看| 日韩视频免费观看高清完整版| 欧美激情国产日韩| 国产精品一区二区三区乱码| 男女视频一区二区| 欧美亚洲系列| 久久国产精彩视频| 亚洲日本一区二区| 99视频有精品| 亚洲午夜伦理| 亚洲已满18点击进入久久| 性高湖久久久久久久久| 亚洲精品资源美女情侣酒店|