最近因為一直在面試,所以一直在准備,現在工作總算是有點着落了,所以就繼續開始我的學習之旅。今天我們來總結STL容器中的std::find,std::find_if以及LAMABDA表達式的用法。為什么會突然寫這個呢?這是因為最近筆者最近碰到一個技術問題,就是我有一些長的字符串(20位以上)(存放到list中的元素類中的某個成員變量中),然后呢,因為某些原因,底層上報上來的字符串有重復,那么我們現在需要把它過濾掉,有什么好辦法呢?首先用memcmp這種方法是不可能的,算法效率太低了。能想到的有這幾種。
一、可以采用set容器把這些東西全部導入進去,然后在把它導出來就好了。但是這樣做有個缺點,就是因為我后面都用這個list讀取數據,如果都改會比較麻煩,所以我果斷放棄了。
二、可以采用hash校驗的方法,這個方法需要添加算法不說,最終要的是我這邊生成的hash校驗和字符串校驗差不多長度,壓根也沒這必要。
三、采用STL容器中的find和find_if的用法來進行處理,我果斷選擇了第三種。
好,接下來我們開始研究一下這些內容。
一、STL容器中find的用法
二、STL容器中find_if的用法
三、LAMBDA表達式到底是個啥?
四、為什么要用LABMBDA表達式
一、STL容器中find的用法
首先說一下,STL容器中有很多find,比如說set,map。他們內部都有內置的find函數,一般情況下,如果我們用到這些容器,那么我們直接用它的內置find就可以了。(這是因為map和set中內置的find函數比std::find時間復雜度要低,速度更快)。但是像list,vector這些容器是沒有find函數的,所以我們只能用默認的std::find來進行查找。首先說一下find函數的原型
template<class InputIterator, class T>
InputIterator find ( InputIterator first, InputIterator last, const T& value )
{
for ( ;first!=last; first++)
if ( *first==value ) break;
return first;
}
我們從find的定義中可以看到,find內部一共包含三個參數,第一個參數和第二個參數指的是迭代器的頭部和尾端,而第三個參數表示的是要比較的值。(不過這里要注意這個值必須是const類型的,所以我們在后面的賦值過程中也要賦值成const類型)。
廢話不說,看一個最簡單的例子。
std::vector<int> score{ 10, 20, 30, 40 }; // 待查找
key int find_key_10 = 10; // 找一個存在於數組中的元素
auto ret_val_1 = std::find(score.begin(), score.end(), find_key_10);
if (score.end() != ret_val_1)
std::cout << "找到了 10 了\n\n";
else
std::cout << "沒有找到 10\n\n"; // 找一個不在數組中的元素
int find_key_50 = 50;
auto ret_val_2 = std::find(score.begin(), score.end(), find_key_50);
if (score.end() != ret_val_2)
std::cout << "找到了 50 了\n\n";
else
std::cout << "沒有找到 50\n\n";
只看標紅的這一句,這就是find的一個最簡單的用法,第一個參數和第二個參數分別傳遞STL容器的頭端和尾端,而第三個參數我們直接傳入一個常量,然后直接進行判斷,如果說沒有找到,那么它返回的值一定是到尾端,反之返回的就是中間的迭代器。
但是這里有個問題,那就是如果說我們傳入的vector或者list容器不是一個基本類型呢?比如說這樣:
class CPerson
{
public:
CPerson(void);
~CPerson(void);
int getage(){return age;
}
private:
int age; // 年齡
};
我們這里要比較其中的age是否相等,那么我們仿照上面的例子應該怎么書寫呢
std::vector<Cperson> score;
// 插入數據
CPerson c;
c.age = 20;
auto ret_val_2 = std::find(score.begin(), score.end(), c);
// 比較
好的,那么我們根據find的定義來分析一下這個find語句,根據find定義,我們執行過程會是這樣
for ( ;first!=last; first++)
if ( *first==c ) break;
return first;
這樣就變成了類進行比較,不用說,編譯肯定是報錯的。而且也沒有按照我們的age來解決。
那么我們該怎么解決這個問題呢?其實問題的關鍵就在於first==c這句話上,所以我們最容易的解決方案就是重載==運算符。我們可以在類中添加這樣的話。
class CPerson
{
public:
CPerson(void);
~CPerson(void);
int getage(){return age;
}
bool CPerson::operator==(const CPerson &rhs) const
{
return (age == rhs.age);
}
private:
int age; // 年齡
};
這樣問題就解決了。
但是這樣設置的條件有點窄,比如說我如果要求找到的這個值自動在類中加30怎么辦呢?這就需要find_if函數了。
我們首先來看一下find_if的用法
template<class InputIterator, class Predicate>
InputIterator find_if(InputIterator _First, InputIterator _Last, Predicate _Pred);
我們從find_if定義上可知,find_if上也有三個參數,其中前兩個參數是和find代表是相同的,但是第三個參數是我們自定義的函數。
直接上例子:
class CPerson
{
public:
CPerson(void);
~CPerson(void);
int getage(){return age;
}
bool CPerson::operator() (const CPerson &rhs) const
{
if (age == rhs.age) {
rhs.age +=30;
return true;
}
}
private:
int age; // 年齡
};
std::vector<Cperson> score;
// 插入數據
CPerson c;
c.age = 20;
auto ret_val_2 = std::find_if(score.begin(), score.end(), c);
這里的區別在於之前是重載了==,現在是重載了(),換句話說,這里的空間要大一些。
三、LAMBMA表達式
當然,作為一個懶人其實還有一種方法,那就是把LAMBDA表達式融入到其中,我們可以這樣寫:
int age = 30;
auto ret_val_2 = std::find_if(score.begin(), score.end(), [age](const Cperson &rhs))-> bool {
return age == rhs.getage();
}
這里要說的一點就是getage返回必須是個常量,因為find_if就是這么定義的。
四、說一下為什么要用LAMBMA表達式
使用LAMBDA表達式有兩個原因,第一個原因在於LAMBDA表達式時在函數中間定義,這樣比較好查找。
第二個原因在於LAMBDA表達式使用起來比較方便,可以直接操縱動態參數,如果不然我們還得重新寫一個構造函數,把參數傳進去進行比較,多有不便,綜上所述,所以一般我都用LAMBDA表達式來寫。
今天就分享到這里了