3. 01. int get_number(const string& s)
02. {
03. for (const auto& x : phone_book)
04. if (x.name==s)
05. return x.number;
06. return 0; // use 0 to represent "number not found"
07. }
4.
5. 01. map<string,int> phone_book {
02. {"David Hume",123456},
03. {"Karl Popper",234567},
04. {"Bertrand Arthur William Russell",345678}
05. };
01. int get_number(const string& s)
02. {
03. return phone_book[s];
04. }
6. 01. unordered_map<string,int> phone_book {
02. {"David Hume",123456},
03. {"Karl Popper",234567},
04. {"Bertrand Arthur William Russell",345678}
05. };
01. int get_number(const string& s)
02. {
03. return phone_book[s];
04. }
7. vector<T> A variable size vector
list<T> A doubly-linked list
forward_list<T> A singly-linked list
deque<T> A doubly-ended queue
set<T> A set
multiset<T> A set in which a value can occur many times
map<K,V> An associative array
multimap<K,V> A map in which a key can occur may times
unordered_map<k,V> A map using a hashed lookup
unordered_multimap<K,V> A multimap using a hashed lookup
unordered_set<T> A set using a hashed lookup
unordered_multiset<T> A multiset using a hashed lookup
9. 01. bool operator<(const Entry& x, const Entry& y)
02. {
03. return x.name<y.name;// order Entrys by their names
04. }
05.
06. void f(vector<Entry>& vec, list<Entry>& lst)
07. {
08. // use < for order
09. sort(vec.begin(),vec.end());
10. // don't copy adjacent equal elements
11. unique_copy(vec.begin(),vec.end(),lst.begin());
12. }
10. 01. // does s contain the character c?
02. bool has_c(const string& s, char c)
03. {
04. auto p = find(s.begin(),s.end(),c);
05. if (p!=s.end())
06. return true;
07. else
08. return false;
09. }
01. bool has_c(const string& s, char c(
02. {
03. return find(s.begin(),s.end(),c)!=s.end();
04. }
11. p=find(b,e,x) p is the first p in [b:e) so that p==x
p=find_if(b,e,f) p is the first p in [b:e) so that f(p)==true
n=count(b,e,x) n is the number of elemes q in [b:e) so that q==x
n=count_if(b,e,f) n is the number of elems q in [b:e) so that f(q, x)
replace(b,e,v,v2) Replace elements q in [b:e) so that q==v by v2
replace_if(b,e,f,v2) Replace elements q in [b:e) so that f(q) by v2
p=copy(b,e,out) Copy [b:e) to [out:p)
p=copy_if(b,e,out,f) Copy elements q form [b:e) so that f(q) to [out:p)
p=unique_copy(b,e,out) Copy [b:e) to [out:p); don't copy duplicates
sort(b,e) Sort elems of [b:e) using < as the sorting criterion
sort(b,e,f) Sort elems of [b:e) using f as the sorting criterion
(p1,p2)=equal_range(b,e,v) [p1:p2) is the subsequence of the sorted sequence
[b:e) with the value v
p=merge(b,e,b2,e2,out) Merge two sorted sequences [b:e) and [b2:e2)
into [out:p)
Editor's Notes
برای معرفی map با بازم به سراغ مثال دفترچه تلفن می ریم که توی ویدیوهای قبلی بحث کردیم. یکی از کار ها متداول توی دفترچه تلفن اینه که ما اسم کسی رو توی دفترچه تلفن search کنیم و شماره اونو پیدا کنیم. اگه دفترچه تلفن با لیست یا وکتور پیاده سازی شده باشه، باید به صورت خطی از اول تا آخر لیست رو دنبال رکورد مورد نظرمون بگردیم ،
چون تمام المانها پشت سر هم هستند ویا انیکه به صورت پشت سر هم باید بهشون دسترسی داشته باشیم. این روش search کردن خیلی پر هزینه ست مخصوصا زمانی که تعداد entryها زیاد باشه.
کتابخونه استاندارد یه ساختمان داده به نام map داره که برای search کردن امکانات خوبی ارائه میده. Map با استفاده از red-black tree پیاده سازی شده که یه نوع binary search treeی بالانس شده است و مرتبه ی زمانی search توش خیلی از لیست بهتره. ما به map میگیم associative array و اسم دیگه ی اون Dictionary هم هست. المانهای Map به صورت Pairیی از key value یا کلید و مقدار هست که برای جستجو بهینه سازی شده.
Initializeکردن map مثل vector و list هست و میشه اونو با initializer-list مقدار دهی کرد.
می تونیم با آرگمان اول که بهش می گیم Key یه map رو index کرد و مقدار value رو گرفت. با اپراتور subscript در واقع ما داریم یه search داخل map میکنیم. اگه کلیدی که ما داریم سرچ میکنیم داخل map نباشه یه رکورد توی map ایجاد میشه و value اون با مقدار default پر میشه. اگر بخوایم جلوی پر شدن map رو با مقادیر Default که معمولا غیر معتبر هستند رو بگیریم باید بجای subscript از متد find استفاده کنیم. متد find اگه کلید مورد نظر ما داخل map نباشه یه iterator به انتهای map بر می گردونه.
هزینه ی Search توی map از مرتبه ی O(log(n)) هست و n تعداد المانهای داخل Map هست. مرتبه ی زمانی map خیلی خوبه مثلا فرض کنید که 1 میلیون رکورد توی map باشه ما می تونیم با حدود 20تا مقایسه به عنصری که دنبالشیم دسترسی داشته باشیم. اما ساختمان داده ای مثل hash هم وجود داره که ما می تونیم بدون مقایسه به عنصر مورد نظر برسیم. توی C++ به hash table ها unordered میگن چون توی hash معمولا ترتیب مهم نیست. یکی از اون hash table ها unordered_map هست.
با initializer list میشه unordered_map رو مقدار دهی کرد.
برای دسترسی به المانها اون هم میشه مشابه map از subscript استفاده کرد. کتابخونه استاندارد برای string یه hash function پیش فرض داره که اگه بخواید می تونید اونو با یه تابع دیگه جایگزین کرد.
توی این اسلاید یه Overview از تمام Containerهایی که کتابخونه استاندارد داره رو می بینید. Containerهایی که با unordered شروع میشن برای lookup بهینه سازی شدن و با یه کلید که معمولا string هست یه value رو ذخیره می کنن. پیاده سازی اونا هم با hash table هست.
تمامی containerها در namespace ی std قرار دارند. علاوه بر اینا کتابخونه استاندارد containerهایی مثل stack، queue، deque و priority_queue رو هم پشتیبانی میکنه. همین طور bitset و آرایه ی با طول ثابت یا همون Array رو هم فراهم کرده.
تمامی Containerها و Operationهاشون به صورتی طراحی شدن که از طرف کاربر ظاهر یکسانی داشته باشند. تمامی operationهایی که اسمشون یکی هست معنی یکسانی هم دارند و کار یکسانی انجام میدن.
برای مثال تمامی Containerها دارای توابعی به نام های begin و end هستند که با begin اولین المان داخل Container برگردونده میشه و با end المان یکی بعد از آخرین المان داخل Container برگردونده میشه.
تابع push_back یه المان رو به انتهای vector ، list و forward list و بقیه ی containerها اضافه میکنه.
تابع size تعداد المان هایی که داخل container هستند رو بر می گردونه.
وقتی notation و semantic کتابخونه استاندارد یکسان باشه برنامه نویس ها می تون containerهای جدید رو که در کتابخونه نیست اضافه کنن و از الگوریتم های موجود هم روی Containerهایی که اضافه کردن استفاده کنن.
ساختمان داده هایی مثل vector و list به خودی خود سودمند نیستند. برای استفاده از اونا ما نیاز داریم تا یه سری عملیاتهای basic مثل دسترسی به المان ها و اضافه و حذف کردن المانها رو داشته باشیم. اگه فقط بخوایم یه سری object داخل اونا ذخیره کنیم زیاد مفید نیست. ما به عملیاتهایی مثل مرتب سازی، چاپ کردن المانها، گرفتن یه زیرمجموعه از container، search ، remove و غیره نیاز داریم. به همین خاطر کتابخونه استاندارد الگوریتم های رایج روی container ها رو فراهم کرده. مثال زیر یه وکتور رو sort میکنه و بعد به صورت unique المانهای وکتور رو توی لیست کپی میکنه.
در این مثال ما با استفاده از iteratorهای begin و end ابتدا و انتهای یه sequence از المان هایی رو که می خوایم sort کنیم رو مشخص می کنیم.
توابع sort و unique_copy دو تا از الگوریتم هایی هستند که کتابخونه استاندارد برای ما فراهم کرده.
بیشتر الگوریتم ها با iteratorکار میکنند و نتیجه ی خروجیشون رو به صورت iterator برمیگردون. مثلا find دنبال یه عنصر داخل sequence میگرده و اگه اونو پیدا بکنه یه Iterator به اون بر می گردونه.
اگر المانی که دنبالش می گردیم رو پیدا نکنه، iterator به end رو بر می گردونه.
نسخه ی کوتاه شده ی کدهای بالا رو میبینید که کل کار های کدهای بالا رو در یک خط انجام میده. نکته اینه که اگه شما بتونید تعداد خط کدها رو کم کنید ولی همچنان کدها خوانا و قابل فهم باشن بعدا موقعی که می خواید کدها رو maintain یا refactor کنید مشکلات کمتری خواهید داشت.
توی این اسلاید یه overview از الگوریتم های کتابخونه استاندارد رو می بینیم.
کتابخونه استاندارد تعداد زیادی الگوریتم های general و پر کاربرد فراهم کرده. همه ی الگوریتم ها در namespaceی std هستند و با include کردنheader file ی algorithm در دسترس قرار می گیرند.
جمع بندی فصل چهارم
در آخر ویدیوی 15 ما فصل چهارم کتاب رو تموم کردیم. توی فصل چهارم یه معرفی اجمالی در مورد امکانات کتابخونه استاندارد داشتیم و با string، IO stream ، Containerها و الگوریتم ها آشنا شدیم.