MAP oraz SET
ZAGADNIENIA
mapaOto zestaw zagadnień, które mogą Ci pomóc poznać struktury danych std::map i std::set w C++:
Podstawowe operacje:
Struktura danych std::set w C++.
std::set jest częścią biblioteki standardowej języka C++ i reprezentuje kolekcję unikalnych elementów, posortowanych zgodnie z określonym porządkiem.Możesz użyć std::set, aby przechowywać dane w porządku rosnącym lub malejącym i szybko sprawdzać, czy określony element znajduje się w zbiorze.
Typowe zastosowania SET
W C++ instrukcje związane z std::set są zwykle funkcjami i metodami, które pozwalają na manipulację i interakcję ze zbiorem. Oto kilka najczęściej używanych:
std::set
mySet.insert(5);
mySet.erase(3);
auto it = mySet.find(3);
if (it != mySet.end()) {
std::cout << "Element znaleziony: " << *it << std::endl;
}
cout <<"Liczba elementów w zbiorze: " << mySet.size();
mySet.clear();
for (auto it = mySet.begin();
it != mySet.end(); ++it) {
cout << *it << endl;
}
To tylko kilka przykładów funkcji i metod związanych z std::set. Istnieje wiele innych, w tym te związane z operacjami na zbiorach, takimi jak unia, przecięcie czy różnica(dla bardzo chętnych).
std::map jest kolejnym kontenerem w bibliotece standardowej C++, który implementuje strukturę danych zwanej mapą lub słownikiem. Jest to kolekcja par klucz-wartość, gdzie klucze są unikalne i posortowane, a wartości są powiązane z nimi. W kontenerze std::map każdy klucz może być przypisany do jednej wartości.
Oto kilka cech std::map:
Unikalność kluczy: Każdy klucz w mapie jest unikalny. Nie może istnieć dwa identyczne klucze w jednej mapie.
Sortowanie: Elementy mapy są automatycznie sortowane względem kluczy zgodnie z określonym porządkiem. Domyślnie porządek ten jest porządkiem rosnącym.
Efektywne wyszukiwanie: Wyszukiwanie elementów w mapie jest bardzo efektywne, ponieważ jest to implementowane w oparciu o drzewo poszukiwań binarnych lub równoważną strukturę danych.
Dynamiczna struktura: Mapa automatycznie dostosowuje swoją strukturę do zmian w liczbie elementów, co oznacza, że możesz dodawać i usuwać elementy dynamicznie.
Przykład
załóżmy że mamy takie liczby: 3, 5, 8, 6, 3, 2, 1, 3, 5, 7, 4,
czy można za pomocą set zliczyć ile jest jakich elementów?
Rozwiązanie
Tak, możemy użyć kontenera std::set, aby zliczyć, ile razy każdy element występuje w zestawie. Jednak sama klasa std::set przechowuje tylko unikalne elementy, więc w przypadku, gdy potrzebujesz zliczyć wystąpienia każdego elementu, możesz użyć std::multiset, który pozwala przechowywać duplikaty. Oto jak to zrobić:
#include <iostream>
#include <set>
using namespace std;
int main() {
multiset<int> mySet = {3, 5, 8, 6, 3, 2, 1, 3, 5, 7, 4};
// Mapa do przechowywania liczby wystąpień każdego elementu
std::map<int, int> occurrences;
//Iterujemy przez zbiór i zliczamy wystąpienia każdego elementu
for (int num : mySet) {
occurrences[num]++;
}
// Wyświetlamy wyniki
for (const auto& pair : occurrences) {
cout << "Liczba " << pair.first << " występuje " << pair.second << " razy." << endl;
}
return 0;
}
W tym kodzie używamy std::multiset do przechowywania wszystkich liczb, a następnie iterujemy po zestawie, korzystając z mapy occurrences, aby zliczyć wystąpienia każdej liczby. Na końcu wypisujemy liczbę wystąpień każdego elementu.
Przykład
Dany jest plik tekstowy zawierająy np.: liczby całkowite.
Wczytaj te liczby to struktury set a następnie wyświetl
Rozwiązanie
Aby wczytać liczby z pliku tekstowego do zbioru (set) w C++, możesz użyć strumieni wejściowych ifstream oraz operacji na zbiorze. Oto przykładowy kod realizujący to zadanie:
#include <iostream>
#include <fstream>
#include <set>
using namespace std;
int main() {
ifstream plik("nazwa_pliku.txt"); // Otwieramy plik do odczytu
set<int> zbior;
int liczba;
while (plik >> liczba) { // Odczytujemy liczby z pliku
zbior.insert(liczba); // Wstawiamy odczytaną liczbę do zbioru
}
plik.close(); // Zamykamy plik
// Wyświetlamy zawartość zbioru
cout << "Liczby wczytane do zbioru:" << endl;
for (const auto& element : zbior) {
cout << element << endl;
}
return 0;
}
Ten kod otwiera plik o nazwie "nazwa_pliku.txt" i wczytuje kolejne liczby ze strumienia do zbioru. Następnie wyświetla zawartość zbioru. Upewnij się, że plik "nazwa_pliku.txt" zawiera jedną liczbę na linię, aby ten kod działał poprawnie.
Linia for (const auto& element : zbior) to tzw. pętla zakresowa (ang. range-based for loop) w C++. Pozwala ona iterować przez wszystkie elementy w kontenerze, takim jak zbiór (std::set), bez potrzeby korzystania z iteratorów w sposób jawny.
Termin const auto& element oznacza, że dla każdego elementu w zbiorze zbior, typ elementu będzie automatycznie wydedukowany przez kompilator (dzięki auto), a następnie użyty do zadeklarowania zmiennej element.
const oznacza, że element będzie traktowany jako stała, więc nie możemy jej modyfikować.
auto oznacza, że typ element będzie automatycznie dedukowany przez kompilator na podstawie typu elementów w zbiorze.
& oznacza, że element będzie przekazywany przez referencję, co pozwala uniknąć kopiowania elementów.
Wewnątrz pętli, dla każdego elementu w zbiorze, kod wykonuje się z użyciem zmiennej element, która reprezentuje aktualnie przetwarzany element zbioru.
Na przykład, w kontekście kodu wczytującego liczby z pliku do zbioru, linia ta iteruje przez każdą liczbę wczytaną do zbioru i wyświetla ją na ekranie.
Ćwiczenia
Wczytaj przykład:
#include <iostream> #include <unordered_set> #include <unordered_map> #include <utility> using namespace std; int main() { unordered_multiset<string> names; names.insert("Romeo"); names.insert("Julia"); names.insert("Romeo"); // Funkcja names.count("Romeo") zwraca teraz liczbę 2 cout << "Liczba Romeow: " << names.count("Romeo") << endl; cout << "Liczba Julii: " << names.count("Julia") << endl; names.erase("Julia"); // Funkcja names.count("Julia") zwraca teraz liczbę 0 cout << "Liczba Julii: " << names.count("Julia") << endl; names.erase("Julia"); // Nie ma żadnego skutku: w wielozbiorze nie ma już ciągu "Julia" cout << "Liczba Julii: " << names.count("Julia") << endl; unordered_multimap<string, string> friends; friends.insert(make_pair("Tomasz", "Daria")); // Daria przyjaźni się z Tomaszem. friends.insert(make_pair("Tomasz", "Henryk")); // Henryk też się z nim przyjaźni. auto tom_range = friends.equal_range("Tomasz"); // pair |
ZAGADNIENIA
Załóżmy, że mamy dwa zbiory, z których jeden zawiera wszystkie elementy drugiego, na przykład zbiór set1 zawiera wartości 1, 2, 3, 4, a set2 — wartości 2, 3. W tym przypadku zestaw set1 zawiera wszystkie elementy zbioru set2, co oznacza, że set2 jest podzbiorem zbioru set1.
Aby sprawdzić, czy jeden zbiór jest podzbiorem innego, można użyć funkcji includes().
Jej argumentami są dwa iteratory wskazujące posortowane zakresy elementów. Funkcja zwraca wartość true, jeżeli pierwszy zakres zawiera wszystkie elementy drugiego, lub false w przeciwnym razie.
Użycie funkcji includes() demonstruje poniższy przykład:
Program sprawdza, czy zbiór set1 zawiera wszystkie elementy zbioru set2.
#include <iostream> #include <set> #include <algorithm> using namespace std; int main() { // Utworzenie dwóch zbiorów set<int> set1 = { 1, 2, 3, 4 }; set<int> set2 = { 2, 3 }; // Sprawdzenie, czy zbiór set1 zawiera wszystkie elementy zbioru set2 if (includes(set1.begin(), set1.end(), set2.begin(), set2.end())) { cout << "Zbior set2 jest podzbiorem zbioru set1.\n"; } else { cout << "Zbior set2 NIE jest podzbiorem zbioru set1.\n"; } return 0; } |
Operacje na zbiorach - przykład
Poniższy przykład demonstruje różne operacje na zbiorach. Program tworzy dwa zbiory: football, zawierający imiona zawodników drużyny piłki nożnej, i basketball z imionami zawodników drużyny koszykarskiej.Program wykonuje następujące operacje:
Link do pliku - programu:
pobierz program
SPRAWDŹ SIĘ
- Unikatowe słowa
Napisz program otwierający plik tekstowy i wyświetlający unikatowe słowa użyte w tym pliku.
- Quiz geograficzny
Napisz program tworzący mapę, w której kluczami będą nazwy europejskich państw, a wartościami — ich stolice (lista państw i ich stolic znajduje się w załączonym pliku Stolice ). Program powinien wybierać losowo nazwę państwa i prosić użytkownika o podanie nazwy jego stolicy.
Program powinien także zliczać poprawne i błędne odpowiedzi. -
Szyfrowanie i deszyfrowanie pliku
Napisz program wykorzystujący mapę, w której każdej literze alfabetu będzie przypisany określony „kod”, na przykład:
mapcodes = { {'A', '%'}, {'a', '9'}, {'B', '@'}, {'b', '#'}, itd...};
W powyższym przykładzie literze „A” jest przypisany symbol %, literze „a” — cyfra 9, literze „B” — symbol @ itd. Program powinien otwierać zadany plik, odczytywać jego zawartość, następnie ją szyfrować i zapisywać w drugim pliku. Każdy znak w drugim pliku musi zawierać kod odpowiadający znakowi z pierwszego pliku. Napisz drugi program, który będzie otwierał zaszyfrowany plik, deszyfrował jego zawartość i wyświetlał ją na ekranie
-
Analiza pliku tekstowego
Napisz program, który odczytuje zawartość dwóch plików tekstowych
i porównuje je w następujący sposób:
a/ Wyświetla listę wszystkich unikatowych słów występujących w obu plikach.
b/ Wyświetla listę słów występujących przynajmniej w jednym pliku.
c/ Wyświetla listę słów występujących w pierwszym pliku, których nie ma w drugim.
d/ Wyświetla listę słów występujących w drugim pliku, których nie ma w pierwszym.
e/ Wyświetla listę słów występujących w pierwszym i drugim pliku, z wyjątkiem tych, które występują w obu plikach jednocześnie.
Wskazówka: do wykonania powyższej analizy wykorzystaj metody klasy set -
Częstość słów
Napisz program odczytujący zawartość pliku tekstowego. Program powinien
tworzyć mapę, w której kluczami będą unikatowe słowa użyte w pliku,
a wartościami — liczby ich wystąpień. Jeżeli na przykład słowo „jest” występuje w pliku 128 razy, mapa powinna zawierać element z kluczem „jest” i wartością 128. Program powinien wyświetlać na ekranie lub zapisywać w drugim pliku listy słów i liczby ich wystąpień.
-
Indeks słów
Napisz program odczytujący zawartość pliku tekstowego. Program powinien
tworzyć mapę zawierającą następujące pary klucz-wartość:
klucz: unikatowe słowo użyte w pliku;
wartość: zbiór zawierający numery wierszy, w których występuje dane słowo(klucz).
Załóżmy, że słowo „robot” występuje w wierszach 7., 18., 94. i 138.
Niech mapa zawiera element, w którym kluczem jest słowo „robot”, a wartością — zbiór liczb 7, 18, 94 i 138.
Program po utworzeniu mapy powinien tworzyć drugi plik tekstowy z indeksem słów. W pliku tym ma zapisywać w porządku alfabetycznym słowa użyte w oryginalnym pliku wraz z numerami wierszy, w których zostały zastosowane. -
Ceny paliwa
Do poniższego zadania pobierz plik tekstowy paliwo.txt zawierający średnie tygodniowe hurtowe ceny paliwa od 3 stycznia 2004 r. do 4 sierpnia 2018 r.
Zawartość pliku Paliwo.txt:
Każdy wiersz pliku zawiera średnią cenę jednego litra paliwa w określonym dniu, zapisaną w następującym formacie:
RRRR-MM-DD:Cena
gdzie RRRR oznacza rok, MM — miesiąc, DD — dzień, a Cena oznacza średnią hurtową cenę jednego litra paliwa w danym dniu.
Napisz jeden lub kilka programów odczytujących zawartość powyższego pliku i wyliczających następujące dane:
Średnia cena roczna: program powinien wyliczać średnią cenę paliwa za każdy rok. (Dane w pliku obejmują okres od stycznia 2004 r. do sierpnia 2018 r.
Średnia cena miesięczna: program powinien wyliczać średnią cenę paliwa za każdy miesiąc.
Najwyższa i najniższa cena roczna: program powinien wyszukiwać najwyższe i najniższe ceny w każdym roku i odpowiadające im daty.
Lista cen od najniższej do najwyższej: program powinien tworzyć plik tekstowy zawierający listę dat i cen posortowanych od najniższej do najwyższej.
Lista cen od najwyższej do najniższej: program powinien tworzyć plik tekstowy zawierający listę dat i cen posortowanych od najwyższej do najniższej.
Możesz napisać jeden program wykonujący wszystkie powyższe operacje lub osobne programy wykonujące poszczególne operacje. Niezależnie od wyboru program musi odczytywać zawartość pliku Paliwo.txt, wyodrębniać z niego dane i umieszczać je w jednym lub kilku kontenerach odpowiednich do wybranego algorytmu.