本演示文稿的主要要點(diǎn)之一是不使用原始循環(huán)。相反,更喜歡使用現(xiàn)有的算法或編寫“包裝”此類循環(huán)的函數(shù)。我對(duì)此想法很好奇,并搜索了不錯(cuò)的代碼示例。這是我在C ++ std庫中使用算法的簡(jiǎn)短列表,這可能有助于編寫更好的代碼。
當(dāng)然。在原始的“ C ++ Seasoning”演講中,我無法跳過兩個(gè)突出的例子:slide and collect。
插入排序僅用兩行代碼!
for (auto i = start; i != end; ++i)
std::rotate(std::upper_bound(start, i, *i), i, std::next(i));
怎么運(yùn)行的?Rotate(first, middle, last)-取一個(gè)范圍[first, last)并旋轉(zhuǎn)它,以便該middle元素成為該范圍中的第一個(gè)元素。
upper_bound-返回指向范圍[first,last)大于的第一個(gè)元素的迭代器val。該范圍應(yīng)已排序(或至少已分區(qū))。
這兩個(gè)元素如何組合成插入類型?
std::upper_bound(start, i, *i)返回第一個(gè)元素的位置大于*i。然后,移動(dòng)范圍,使i-th元素成為第一位。
讓我們看一個(gè)例子:
挺棒的!
在堆棧溢出中發(fā)現(xiàn):
template<class FwdIt, class Compare = std::less<>>
void quickSort(FwdIt first, FwdIt last, Compare cmp = Compare{})
{
auto const N = std::distance(first, last);
if (N <= 1) return;
auto const pivot = std::next(first, N / 2);
std::nth_element(first, pivot, last, cmp);
quickSort(first, pivot, cmp);
quickSort(pivot, last, cmp);
}
怎么運(yùn)行的?我不會(huì)描述快速排序算法...您應(yīng)該已經(jīng)知道它是如何工作的!在此實(shí)現(xiàn)std::nth_element中,用于完成大部分工作。此函數(shù)對(duì)范圍進(jìn)行部分排序,以便將給定的n-th元素放置在適當(dāng)?shù)奈恢?。元素之前的所有n-th元素都小于或等于元素之后的n-th元素。
肖恩·帕特恩(Sean Parent)的演講示例:
template <typename It>
auto slide(It f, It l, randIter p) -> std::pair<It, It>
{
if (p < f) return { p, std::rotate(p, f, l) };
if (l < p) return { std::rotate(f, l, p), p };
return { f, l };
}
怎么運(yùn)行的?例如,您可以想象UI對(duì)話框上的項(xiàng)目列表。用戶選擇一個(gè)連續(xù)范圍,然后算法采用該范圍并將其移至列表的其他位置。
此功能使用std::rotate:向前或向后移動(dòng)元素。它返回兩個(gè)迭代器-新序列的開始和結(jié)束。在C ++ 11中std::rotate獲得了新版本,現(xiàn)在可以將迭代器返回到pelement 的新位置。如果您對(duì)返回此迭代器對(duì)不感興趣,則可以進(jìn)一步簡(jiǎn)化此代碼。實(shí)施說明:
在GCC 4.9(及更低版本)std::rotate中,不返回迭代器,而僅返回void。因此,當(dāng)前,此代碼將無法在此處運(yùn)行。肖恩·潘特(Sean Parent)演講的另一個(gè)例子:
template <typename BiIt, typename UnPred>
auto gather(BiIt f, BiIt l, BiIt p, UnPred s) -> std::pair <BiIt, BiIt>
{
return { stable_partition(f, p, not1(s)),
stable_partition(p, l, s) };
}
怎么運(yùn)行的?它的用例可以類似于slide:選擇元素-使用謂詞s(因此不需要此連續(xù)范圍),然后將這些元素收集到一個(gè)范圍中并將該范圍移動(dòng)到周圍p。它返回所選范圍的開始和結(jié)束。
UnPred是一個(gè)謂詞,它返回是否選擇給定元素。
std::stable_partition:來自cppreference
對(duì)給定范圍內(nèi)的元素進(jìn)行重新排序,使謂詞返回的所有元素都在謂詞返回true的元素之前false。保留元素的相對(duì)順序。
std::stable_partition 使用兩次:
實(shí)施說明:
std::not1無法正確使用代碼,因此建議使用簡(jiǎn)單的lambda。在Sean的評(píng)論中閱讀更多內(nèi)容。發(fā)現(xiàn)在堆棧溢出
std::string trim(const std::string &s) {
return trimLeft(trimRight(s));
}
std::string trimLeft(const std::string &s) {
auto temp = s;
temp.erase(std::begin(temp),
std::find_if(std::begin(temp), std::end(temp),
[](char c){return !std::isspace(c, std::locale());
}));
return temp;
}
std::string trimRight(const std::string &s) {
auto temp = s;
temp.erase(std::find_if(std::rbegin(temp), std::rend(temp),
[](char c){return !std::isspace(c, std::locale()); }).base(),
std::end(temp));
return temp;
}
怎么運(yùn)行的?標(biāo)準(zhǔn)庫的另一個(gè)漂亮用法:
為了修剪字符串,我們從右到左修剪(這是一個(gè)發(fā)現(xiàn)?。┫蜃笮藜簦簊td::find_if將迭代器返回到字符串中的第一個(gè)非空格字符。然后我們刪除那些字符。修剪右:也使用,std::find_if但是這次我們使用反向迭代器注意:您還可以使用升壓字符串算法使生活更輕松。
該代碼的作用是什么?
while (std::next_permutation(start, end));
簡(jiǎn)單,一行代碼...應(yīng)該不錯(cuò)!但...
答:這是對(duì)容器進(jìn)行排序的另一種“絕佳”方法-排列排序!但是請(qǐng)不要在家中使用它:)
復(fù)雜度:O((n + 1)?。?/strong>
該算法是Bogosort和其他類似“排序”算法的變體。在Wiki上閱讀更多內(nèi)容。正如victor_zverovich所注意到的,在Bogosort中,下一個(gè)排列是隨機(jī)選擇的,但是std :: next_permutation在字典上提供了下一個(gè)排列上更大的排列。
我已經(jīng)展示了幾個(gè)我認(rèn)為不錯(cuò)的代碼示例,這些示例中大量使用了C ++標(biāo)準(zhǔn)庫中的算法。也許下一次,當(dāng)我要編寫一些丑陋的代碼時(shí),我會(huì)停下來思考一會(huì)兒,也許可以調(diào)用一些現(xiàn)有的算法/函數(shù)。
你知道一些更有趣的例子嗎?
歡迎討論