亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

How to (std::)find something efficiently with the STL

2019-11-14 09:31:19
字體:
來源:轉載
供稿:網友

本文分3部分: 1. 怎么使用STL進行高效的查找: 借用傳統STL算法對元素進行范圍搜索 2. 搜索STL容器: 當你有直接讀取STL容器里元素的權限時, 怎么進行高效準確的搜索(與簡單的范圍搜索相比較) 3. STL搜索算法的秘密: 向公眾展示不為人知的算法, 這些算法在已經學習過的人眼里確實是很有用的

STL根據查看方式的不同, 一共分為兩種: 排序的和不排序的. * 排序集合的遍歷, 通常需要對數時長, 而亂序集合的遍歷, 需要線性時長 * 排序容器中比較元素大小的函數根據equivalence(comparing with <), 而亂序容器中的函數根據equality(comparing with ==).

本文將展示對于在一個范圍內搜索一個給定的值, C++怎么樣去闡述下面3個問題: * 它存在否 * 它在哪 * 它應該在什么位置(排序容器)

Is it there?

亂序容器的元素

這個問題可以用std::find來表達(需要和與范圍的終點值的比較相結合):

vector<int> v = ... // v filled with valuesif (std::find(v.begin(), v.end(), 42) != v.end()){ ...

“Is it there”這個問題也可以用std::count來表達:

vector<int> v = ... // v filled with valuesif (std::count(v.begin(), v.end(), 42)){ ...

std::count()的返回值會被隱式地轉換成if條件里的bool值: 如果該范圍里有至少一個值為42, 則返回true.

與std::find相比, std::count的優劣: 優勢:

std::count避免了與范圍的end值相比較

弊端:

std::count遍歷整個集合, 而std::find在第一個與要查找的值相等的位置停下可以證明, 對于”想要查找某個值”這件事, std::find 表達得更明確 基于以上, std::find用得更多.

Note 若要確認某個值存在而非是與要搜索的值相等, 請使用std::count_if, std::find_if, std::find_if_not

排序容器的元素

使用的算法是std::binary_search, 此函數返回一個bool值, 此bool值表示在集合中是否存在與搜索的值相等的元素.

std::set<int> numbers = // sorted elementsbool is42InThere = std::binary_search(numbers.begin(), numbers.end(), 42);

Where is it?

(當確定了要搜索的值存在后,) 我們想更進一步, 得到指向那個元素的迭代器.

亂序容器的元素

使用std::find. 返回指向第一個與搜索的值相等的元素的迭代器, 如果找不到, 則返回集合的終點.

std::vector<int> numbers = ...auto searchResult = std::find(numbers.begin(), numbers.end(), 42);if (searchResult != numbers.end()){ ...

排序容器的元素

對于排序集合, STL并沒有像std::find一樣直接的算法. std::find并不是為排序容器設計的, 因為它依據的是”==”而不是”<”, 消耗的時間為線性時長而不是對數時長. 對于一個給定的容器, 如果容器內元素的”equality”和”equivalence”是相同的, 且你能接受消耗的線性時長, 那么std::find會為你返回正確的結果, 你也能從它簡單直接的接口中獲益. 但是, 不能忘記, std::find并不是為排序容器設計的.

這里推薦使用std::equal_range. (并非std::lower_bound) 函數原型:

template< class ForwardIt, class T >std::pair<ForwardIt,ForwardIt> equal_range( ForwardIt first, ForwardIt last, const T& value );

std::equal_range 返回與搜索值相等的元素的范圍, 這個范圍用一對集合內的迭代器表示. 這兩個迭代器分別指向 與搜索值相等的范圍里第一個元素和最后一個元素的下一個位置.

然而, 它的接口有些笨重: 例A:

std::vector<int> v = {3, 7, 3, 11, 3, 3, 2};sort(v.begin(), v.end());// equal_range, attempt 1: natively clumsystd::pair<std::vector<int>::iterator, std::vector<int>::iterator> range1 = equal_range(v.begin(), v.end(), 3);std::for_each(range1.first, range1.second, doSomething);

用一個typedef 或者using讓它更簡潔: 例B:

std::vector<int> v = {3, 7, 3, 11, 3, 3, 2};sort(v.begin(), v.end());using IteratorPair = std::pair<std::vector<int>::iterator, std::vector<int>::iterator>;// equal_range, attempt 2: with the classical typedefIteratorPair range2 = equal_range(v.begin(), v.end(), 3);std::for_each(range2.first, range2.second, doSomething);

例B確實簡潔了很多, 但是仍有一個根本問題: 沒有考慮 抽象等級. 盡管返回的是一個范圍, 但這對迭代器強迫我們在操作返回的范圍時必須按照”第一”“第二”這種方式來寫代碼. 范圍就應該用”首”“尾”這種方式來表達. 這不僅給我們在其他地方使用這個返回值時造成很大的麻煩, 而且使代碼很別扭.

為了解決這個問題, 我么可以把std::equal_range 返回的迭代器對封裝進一個有”范圍”這種語義的object

template<typename Container>class Range{public: Range(std::pair<typename Container::iterator, typename Container::iterator> range) : m_begin(range.first), m_end(range.second) {} typename Container::iterator begin() { return m_begin; } typename Container::iterator end() { return m_end; }PRivate: typename Container::iterator m_begin; typename Container::iterator m_end;};

注意: 盡管std::equal_range 返回的結果是一個”范圍”, 但是std::beginstd::end 不能用在這個結果上. 而上面的封裝解決了這個問題. 可以像下面這樣使用:

std::vector<int> v = {3, 7, 3, 11, 3, 3, 2};sort(v.begin(), v.end());// equal_range, attempt 3: natural al lastRange<std::vector<int>> range3 = equal_range(v.begin(), v.end(), 3);std::for_each(range3.begin(), range3.end(), doSomething);

不管你使用上面的哪種方式, std::equal_range 都會返回一個范圍, 要確定它是否為空, 可以通過檢查那兩個迭代器(是否相等)或者使用std::distance 檢查它的大小.

bool noElementFound = range3.begin() == range3.end();size_t numberOfElementFound = std::distance(range3.begin(), range3.end())

Where should it be?

這個問題僅僅針對排序的范圍, 因為對于亂序的范圍, 某個元素可能會存在任何位置.

對于排序的范圍, 這個問題可以簡化為: 如果它存在, 那么它在哪兒? 如果它不存在, 那么它應該在哪兒?

這個問題可以用算法std::lower_boundstd::upper_bound 來解釋.

當你理解了std::equal_range 后, 上面這句話就很容易理解了: std::lower_boundstd::upper_bound 都會返回 std::equal_range 返回的那個迭代器對的第一個和第二個迭代器.

要插入某個值x, 使用std::lower_bound 得到指向 在范圍里與x相等的元素之前的位置的迭代器, 使用std::upper_bound 得到指向 在范圍里與x相等的元素之后的位置的迭代器.

注意: 如果僅僅是搜索某個元素, 永遠不要使用std::lower_bound

std::find 相反, 你不能根據 判斷std::lower_bound 返回的迭代器是否與終點的迭代器相等 來判斷要搜索的值是否存在于這個集合. 事實上, 如果這個值在集合里不存在, 則std::lower_bound 返回它應該在的位置, 而不是終點的迭代器. 所以, 你不僅需要確認返回的迭代器不是終點的迭代器, 還要確認它指向的元素跟要搜索的值是相等的.

總結

Question to express in C++ NOT SORTED SORTED
Is it there? std::find != end std::binary_search
Where is it? std::find std::equal_range
Where should it be? - std::lower_bound / std::upper_bound

原文地址: http://www.fluentcpp.com/2017/01/16/how-to-stdfind-something-efficiently-with-the-stl/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美日韩国产区| 亚洲精品在线不卡| 亚洲国产又黄又爽女人高潮的| 亚洲情综合五月天| 欧美大片网站在线观看| 欧美精品久久久久| 精品久久久999| 国产精品精品视频一区二区三区| 91久久精品一区| 九九精品在线播放| 国产日产久久高清欧美一区| 精品色蜜蜜精品视频在线观看| 亚洲欧洲av一区二区| 欧美日韩成人精品| 国产91在线视频| 欧美精品生活片| 97精品国产97久久久久久春色| 亚洲精品在线91| 国产欧美一区二区三区在线| 美日韩丰满少妇在线观看| 日韩精品免费观看| 91探花福利精品国产自产在线| 久久乐国产精品| 日韩黄在线观看| 久久久91精品国产一区不卡| 国产在线观看不卡| 欧美一二三视频| 91免费欧美精品| 亚洲人成网7777777国产| 97香蕉超级碰碰久久免费的优势| 91在线视频导航| 欧美第一黄网免费网站| 色偷偷av一区二区三区| 亚洲精品一区二区网址| 色婷婷亚洲mv天堂mv在影片| 欧美黑人xxx| 国产精品视频一区二区高潮| 亚洲视频免费一区| 欧美在线视频一区二区| 国产日韩精品综合网站| 亚洲人成电影网站色…| 久久色在线播放| 欧美大片免费观看| 欧美午夜无遮挡| 亚洲一区二区久久久| 中文字幕亚洲综合久久| 色婷婷av一区二区三区久久| 国产精品久久久av| 欧美日韩国产二区| 在线电影av不卡网址| 国产精品免费一区二区三区都可以| 亚洲欧美一区二区三区久久| 成人黄在线观看| 国产成人精品一区二区三区| 国产午夜精品久久久| 亚洲无限乱码一二三四麻| 精品日韩美女的视频高清| 日韩在线视频观看正片免费网站| 一本色道久久综合狠狠躁篇的优点| 欧美精品精品精品精品免费| 亚洲91精品在线| 日本最新高清不卡中文字幕| 亚洲欧洲xxxx| 久久久91精品| 久久久久久av| 国产精品美女主播| 成人免费网视频| 日韩欧美国产成人| 日本一区二区三区在线播放| 欧美一区二区三区……| 另类天堂视频在线观看| 欧美精品精品精品精品免费| 97香蕉超级碰碰久久免费软件| 一区二区三区在线播放欧美| 亚洲国产成人爱av在线播放| 日韩欧美黄色动漫| 欧美成人免费播放| 久久久久久久国产精品视频| 亚洲美女中文字幕| 国产一区二中文字幕在线看| 欧美性猛交xxxx富婆| 久久精品成人动漫| 亚洲一区二区久久久| 神马久久桃色视频| 亚洲第一av网站| 欧美黑人性猛交| 国产一区二区黑人欧美xxxx| 日韩成人中文字幕在线观看| 免费91麻豆精品国产自产在线观看| 精品国产一区二区三区久久久| 性色av一区二区三区免费| 欧美日韩中文字幕| 欧美精品18videosex性欧美| 亚洲国产一区二区三区在线观看| 久久精品99国产精品酒店日本| 92国产精品久久久久首页| 欧美电影免费观看高清| 欧美激情小视频| 欧美电影院免费观看| 精品国产乱码久久久久久天美| 国产在线精品播放| 日韩欧美一区二区在线| 亚洲精品99久久久久中文字幕| 国产91久久婷婷一区二区| 在线观看亚洲视频| 久久久黄色av| 日韩电视剧免费观看网站| 亚洲精品电影久久久| 在线播放国产一区二区三区| 亚洲第一偷拍网| 97精品久久久| 国产精品99久久久久久久久久久久| 欧美性xxxx极品hd欧美风情| yw.139尤物在线精品视频| 亚洲第一免费播放区| 亚洲在线www| 亚洲欧美日韩久久久久久| 国产精品久久久久999| 亚洲女性裸体视频| 国产日产欧美a一级在线| 欧洲亚洲女同hd| 欧美麻豆久久久久久中文| 欧美激情性做爰免费视频| 久久国内精品一国内精品| 久久91超碰青草是什么| 国产高清在线不卡| 日韩精品极品毛片系列视频| 欧美放荡办公室videos4k| 91天堂在线观看| 亚洲乱码av中文一区二区| 欧美亚洲在线观看| 日韩在线小视频| 亚洲精品白浆高清久久久久久| 97国产精品视频| 国产精品一区二区av影院萌芽| 高清欧美性猛交xxxx| 欧美视频中文字幕在线| 国产欧美精品日韩精品| 成人在线视频网站| 久久男人资源视频| 性欧美长视频免费观看不卡| 国产精品久久久久久久av大片| 亚洲天堂网在线观看| 视频在线观看一区二区| 欧美在线视频免费| 亚洲午夜av久久乱码| 色偷偷91综合久久噜噜| 亚洲国产欧美一区二区丝袜黑人| 精品美女永久免费视频| 久久久国产一区二区| 国产精品国产三级国产专播精品人| 国产精品福利久久久| 亚洲日韩欧美视频一区| 日韩精品电影网| 亚洲女人被黑人巨大进入al| 久久综合亚洲社区| 国产亚洲精品一区二区| 欧美特黄级在线| 隔壁老王国产在线精品| 亚洲欧美国产精品专区久久| 欧美高跟鞋交xxxxhd| 日韩av在线天堂网| 久久伊人精品一区二区三区| 精品福利免费观看|