set și
multiset din STL
Un set este o mulțime ordonată
de elemente unice. Elementele sunt mereu
sortate și nu pot apărea de două ori.
Un multiset e la fel, dar
permite duplicate.
#include <set>set<T>
set<int> s;
s.insert(5);
s.insert(3);
s.insert(8);
s.insert(3); // ignorat - 3 există deja
// s conține: {3, 5, 8}
cout << s.size(); // 3
cout << s.count(5); // 1 (există)
cout << s.count(7); // 0 (nu există)Operații
| Operație | Ce face | Complexitate |
|---|---|---|
insert(x) |
Adaugă x (dacă nu există) | O(log n) |
erase(x) |
Șterge x | O(log n) |
find(x) |
Iterator la x (sau end() dacă nu există) |
O(log n) |
count(x) |
1 dacă există, 0 dacă nu | O(log n) |
size() |
Număr elemente | O(1) |
empty() |
Verifică gol | O(1) |
clear() |
Golește | O(n) |
begin() |
Iterator la cel mai mic | O(1) |
end() |
Iterator după ultimul | O(1) |
Iterare prin set
Elementele sunt mereu sortate crescător:
set<int> s = {5, 3, 8, 1, 9};
for (int x : s)
cout << x << " ";
// Output: 1 3 5 8 9find și
erase
set<int> s = {3, 5, 8};
auto it = s.find(5);
if (it != s.end())
cout << "Gasit: " << *it; // *it = valoarea
s.erase(5); // șterge valoarea 5
s.erase(it); // șterge elementul la care pointează itfind returnează un iterator.
Dacă elementul nu există, returnează s.end().
lower_bound
și upper_bound pe set
set<int> s = {1, 3, 5, 8, 12};
auto it1 = s.lower_bound(5); // iterator la 5 (primul >= 5)
auto it2 = s.upper_bound(5); // iterator la 8 (primul > 5)
auto it3 = s.lower_bound(6); // iterator la 8 (primul >= 6)
cout << *it1; // 5
cout << *it2; // 8
cout << *it3; // 8| Funcție | Ce returnează |
|---|---|
lower_bound(x) |
Iterator la primul element >= x |
upper_bound(x) |
Iterator la primul element > x |
Dacă nu există un astfel de element, returnează
end().
Important: folosește
s.lower_bound(x) (metoda set-ului), nu
lower_bound(s.begin(), s.end(), x) (funcția
globală). Metoda e O(log n), funcția globală pe set e O(n).
Exemplu: elemente distincte
#include <fstream>
#include <set>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");
int main()
{
int n;
fin >> n;
set<int> s;
for (int i = 0; i < n; i++) {
int x;
fin >> x;
s.insert(x);
}
fout << "Distincte: " << s.size() << endl;
for (int x : s)
fout << x << " ";
return 0;
}date.in:
8
3 1 2 3 1 3 2 3date.out:
Distincte: 3
1 2 3multiset<T>
Ca set, dar permite duplicate:
multiset<int> ms;
ms.insert(3);
ms.insert(5);
ms.insert(3);
ms.insert(3);
// ms conține: {3, 3, 3, 5}
cout << ms.size(); // 4
cout << ms.count(3); // 3Ștergerea din multiset
ms.erase(3); // ATENȚIE: șterge TOATE aparițiile lui 3!
// Dacă vrem să ștergem doar UNA:
auto it = ms.find(3);
if (it != ms.end())
ms.erase(it); // șterge doar o aparițieExemplu: mediana curentă
Primim numere și după fiecare afișăm mediana (elementul din mijloc).
Folosim un multiset care menține elementele sortate. Mediana e la mijloc.
#include <fstream>
#include <set>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");
int main()
{
int n;
fin >> n;
multiset<int> ms;
for (int i = 0; i < n; i++) {
int x;
fin >> x;
ms.insert(x);
// Mediana: elementul de pe poziția size/2
auto it = ms.begin();
advance(it, ms.size() / 2);
fout << *it << " ";
}
return 0;
}
advance(it, k)
advance mută un iterator cu k
poziții. Pe set, e O(k) - nu O(1) ca pe vector.
Pentru mediana eficientă, se folosesc două structuri (un max-heap și un min-heap) sau un Order Statistics Tree (GNU extension).
Set descrescător
set<int, greater<int>> s;
s.insert(3);
s.insert(7);
s.insert(1);
for (int x : s)
cout << x << " ";
// Output: 7 3 1set
vs vector de frecvență vs vector sortat
set |
Vector frecvență | Vector sortat | |
|---|---|---|---|
| Insert | O(log n) | O(1) | O(n) |
| Find | O(log n) | O(1) | O(log n) |
| Erase | O(log n) | O(1) | O(n) |
| Ordine | Mereu sortat | Nu | Doar dacă sortăm |
| Valori mari | Da | Nu (limitare dimensiune) | Da |
| Duplicate | Nu (set) / Da (multiset) | Da | Da |
Folosește set când valorile sunt
mari (nu încap într-un vector de frecvență) sau
când ai nevoie de ordine și
ștergere.
Greșeli frecvente
1.
erase(x) pe multiset șterge TOATE aparițiile
multiset<int> ms = {3, 3, 5};
ms.erase(3); // ms = {5}, nu {3, 5}!
// Pentru o singură apariție:
ms.erase(ms.find(3)); // ms = {3, 5}2. Iterare și ștergere simultană
// GREȘIT:
for (auto it = s.begin(); it != s.end(); it++)
if (*it % 2 == 0)
s.erase(it); // iteratorul devine invalid!
// CORECT:
for (auto it = s.begin(); it != s.end(); )
if (*it % 2 == 0)
it = s.erase(it);
else
it++;3. Acces prin indice
cout << s[0]; // GREȘIT - set nu are operator []Set nu suportă acces prin indice. Folosește iteratori.
Ce să reții
set<T>: mulțime ordonată de elemente unice. Insert/find/erase în O(log n).multiset<T>: ca set dar permite duplicate.erase(x)șterge toate aparițiile.- Elementele sunt mereu sortate. Iterarea e în ordine crescătoare.
lower_bound(x)= primul >= x,upper_bound(x)= primul > x.- Folosește metoda set-ului (
s.lower_bound(x)), nu funcția globală. - Fără acces prin indice - doar iteratori.