Bir kap (container) içinde tutulan her bir değerdeki öğeden kaç tane olduğunu nasıl sayarız? Soruyu bir kodla daha açık hale getirelim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> #include <algorithm> #include <vector> #include <ctime> #include <cstdlib> using namespace std; int main() { vector<int> ivec(1000); srand(static_cast<unsigned>(time(nullptr))); generate(ivec.begin(), ivec.end(), []{return rand() % 100;}); //// return 0; } |
main işlevinde oluşturulan ivec isimli kapta [0-99] aralığında 1000 tamsayı tutuluyor. Bu tamsayıların herbirinden kaç tane olduğunu bulmamız ve bu değerleri kullanıcı ekranına yazdırmamız gereksin.
Bu amaçla standart kütüphanenin map ya da unordered_map sınıflarının [ ] işlevini kullanabiliriz:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#include <iostream> #include <algorithm> #include <ctime> #include <cstdlib> #include <vector> #include <map> using namespace std; int main() { vector<int> ivec(1000); srand(static_cast<unsigned>(time(nullptr))); generate(ivec.begin(), ivec.end(), []{return rand() % 100; }); //// map<int, int> cmap; for (auto i : ivec) ++cmap[i]; /// for (const auto &p : cmap) cout << p.second << " tane " << p.first << endl; /// return 0; } |
Önce burada işimizi gören [] işlevinin bildirimine bir bakalım:
1 |
mapped_type& operator[] (const key_type& k); |
Üye işlevimizin geri dönüş değeri olan mapped_type ve parametre değişkeni türü olan key_type map sınıf şablonunun birinci ve ikinci şablon tür parametrelerine verilen eşisimler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
template < class Key, class T, class Compare = std::less<Key>, class Alloc = std::allocator<std::pair<const Key,T> > > class map { public: typedef Key key_type; typedef T mapped_type; typedef Compare key_compare; typedef Alloc allocator_type; /// } |
Birinci şablon tür parametresinin eşismi olan key_type anahtar olarak kullanılan değerin türü iken ikinci şablon tür parametresine eşisim olan mapped_type ise anahtara karşılık gelen değerin türü. Bilindiği gibi map kabının gerçekleştirimi (implementation) tipik olarak içinde anahtar değer çiftleri tutan bir ikili arama ağacı olarak yapılıyor. Örneğin std::map<int, int> türünden bir kap nesnesi içinde std::pair<const int, int> türünden değerler tutuyor.
Kodda tanımlanan cmap nesnesinin tuttuğu std::pair<const int, int> nesnelerimizin first’ü sayılacak değerler second’ı ise bu değerden kaç tane olduğunu tutacak sayaçlarımız olarak görev yapacak.
[] işlevimiz bir anahtar değeri alıp bunun karşılığında bizi o anahtara karşılık gelen değere eriştiriyor. multimap ve unordered multimap kaplarının böyle bir işlevi yok. Çünkü bu kaplarda aynı anahtara sahip birden fazla değer tutulabiliyor. [] işlevinin ilginç bir davranışı var: Eğer map içinde bu anahtar değeri var ise işlevin geri dönüş değeri map‘te tutulan pair‘in second öğesine referans. Yani map‘te ilgili anahtarın bulunması durumunda doğrudan referans semantiği ile ilgili anahtara karşılk gelen değere erişiyoruz. Peki ya bu anahtar değeri map‘te yer almıyorsa ne oluyor? Bu durumda map kabına yeni bir pair ekleniyor. Eklenen pair‘in first öğesi olarak işleve gönderilen anahtar değeri, second öğesi olarak ise, değerle başlatılan (value initialized) bir mapped_type nesnesi kullanılıyor. Eğer mapped_type varsayılan türlerden birinden ise kurallara göre bu nesne hayata 0 değeriyle başlatılıyor. Bu durumda işlevin geri dönüş değeri eklenen yeni pair‘in second öğesine yani mapped_type türünden nesneye bir referans.Köşeli parantez işlevi olmasaydı aşağıdaki deyimle yine aynı işi yapabilirdik:
1 |
++(*((cmap.insert(make_pair(i,mapped_type()))).first)).second; |
Kodu şimdi içeriden dışarıya açalım:
1 |
mapped_type() |
ifadesi ile mapped_type türünden geçici bir nesne oluşturmuş olduk. Bizim için mapped_type int türü olduğundan oluşturulan int türden geçici nesne 0 degeri ile başlatılacak.
utility başlık dosyasında şablon kodu bulunan make_pair işlevine yapılan çağrının geri dönüş değeri ile first öğesi i değerinde second öğesi 0 değerinde olan bir pair<int, int> değeri elde ettik:
1 |
make_pair(i, mapped_type()) |
1 |
cmap.insert(make_pair(i, mapped_type())) |
1 |
*cmap.insert(make_pair(i, mapped_type())) |
1 |
(*cmap.insert(make_pair(i, mapped_type()))).second |
1 |
++(*cmap.insert(make_pair(i, mapped_type()))).second; |