Programski jezici → C# → Kolekcije u C#: List, Dictionary, HashSet, Queue i Stack
Kolekcije u C#: List, Dictionary, HashSet, Queue i Stack
Lekcija 9 od 15 · C#
Niz ima nepromenljivu dužinu. Kolekcije iz prostora imena System.Collections.Generic rastu i smanjuju se po potrebi i imaju gotove metode za dodavanje, brisanje i pretragu. Tip elemenata piše se u uglastim zagradama: List<int> je lista celih brojeva, Dictionary<string, int> rečnik koji tekst preslikava u broj.
Pre nego što počneš: potrebno predznanje – klase i objekti, nizovi. Kako da učiš: svaki primer prekucaj i pokreni, a zadatke na kraju prvo reši sam/a; uputstvo i rešenje otvori tek posle toga. Svi programi su konzolne aplikacije u C#-u (.NET 8 ili noviji, bez „top-level statements“); svaki je proveren i daje navedeni izlaz.
List<T>: niz promenljive dužine
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> drugari = new List<string> { "Ana", "Marko" };
drugari.Add("Iva"); // dodavanje na kraj
drugari.Insert(1, "Luka"); // ubacivanje na poziciju 1
Console.WriteLine(string.Join(", ", drugari));
Console.WriteLine($"Broj: {drugari.Count}");
drugari.Remove("Marko"); // brisanje po vrednosti
drugari.Sort();
Console.WriteLine(string.Join(", ", drugari));
Console.WriteLine(drugari.Contains("Iva"));
Console.WriteLine(drugari.IndexOf("Luka"));
for (int i = 0; i < drugari.Count; i++) // pristup po indeksu, kao kod niza
Console.WriteLine($"{i + 1}. {drugari[i]}");
}
}
Broj elemenata liste daje svojstvo Count (kod niza je to Length). Kada broj podataka nije unapred poznat, lista je bolji izbor od niza:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var brojevi = new List<int>();
while (true) // učitavanje do nule
{
int x = int.Parse(Console.ReadLine());
if (x == 0) break;
brojevi.Add(x);
}
brojevi.RemoveAll(b => b < 0); // ukloni sve negativne
brojevi.Sort((a, b) => b.CompareTo(a)); // sortiraj opadajuće
Console.WriteLine(string.Join(" ", brojevi));
}
}
Izrazi b => b < 0 i (a, b) => b.CompareTo(a) su lambda izrazi – kratke funkcije napisane na mestu upotrebe. Detaljno su objašnjeni u lekciji o LINQ-u.
Dictionary<K, V>: rečnik (ključ → vrednost)
Rečnik čuva parove ključ – vrednost i brzo pronalazi vrednost po ključu. Ključevi su jedinstveni.
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var broj = new Dictionary<string, int>();
foreach (string rec in Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries))
{
if (broj.ContainsKey(rec))
broj[rec]++; // reč već postoji – uvećaj brojač
else
broj[rec] = 1; // nova reč
}
foreach (var par in broj) // par je KeyValuePair<string, int>
Console.WriteLine($"{par.Key}: {par.Value}");
if (broj.TryGetValue("mis", out int m))
Console.WriteLine($"mis: {m}");
else
Console.WriteLine("mis se ne pojavljuje");
}
}
Čitanje ključa koji ne postoji (broj["mis"]) prekida program greškom, zato se koristi ContainsKey ili TryGetValue. Redosled obilaska rečnika nije zagarantovan; kada su potrebni sortirani ključevi, koristi se SortedDictionary.
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var imenik = new Dictionary<string, string>
{
["Ana"] = "064 111 222",
["Marko"] = "063 333 444"
};
imenik["Iva"] = "065 555 666"; // dodavanje
imenik["Ana"] = "064 999 888"; // izmena postojećeg ključa
imenik.Remove("Marko"); // brisanje
foreach (string ime in imenik.Keys)
Console.WriteLine($"{ime}: {imenik[ime]}");
Console.WriteLine($"Ukupno kontakata: {imenik.Count}");
}
}
HashSet<T>: skup bez ponavljanja
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var a = new HashSet<int> { 1, 2, 3, 4, 5 };
var b = new HashSet<int> { 4, 5, 6, 7 };
Console.WriteLine(a.Add(3)); // False – 3 već postoji
Console.WriteLine(a.Contains(4)); // brza provera pripadnosti
var presek = new HashSet<int>(a);
presek.IntersectWith(b);
var unija = new HashSet<int>(a);
unija.UnionWith(b);
Console.WriteLine("Presek: " + string.Join(" ", presek));
Console.WriteLine("Unija: " + string.Join(" ", unija));
}
}
Skup je najbolji kada treba proveriti „da li se već pojavilo“ ili ukloniti duplikate: new HashSet<int>(niz).
Queue<T> (red) i Stack<T> (stek)
Red radi po pravilu „prvi došao, prvi uslužen“ (FIFO), a stek po pravilu „poslednji stavljen, prvi uzet“ (LIFO).
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var red = new Queue<string>();
red.Enqueue("Ana"); // stani u red
red.Enqueue("Bojan");
red.Enqueue("Ceca");
Console.WriteLine($"Na redu je: {red.Peek()}");
while (red.Count > 0)
Console.Write(red.Dequeue() + " "); // izađi iz reda
Console.WriteLine();
var stek = new Stack<int>();
for (int i = 1; i <= 4; i++)
stek.Push(i * 10); // stavi na vrh
Console.WriteLine($"Vrh steka: {stek.Peek()}");
while (stek.Count > 0)
Console.Write(stek.Pop() + " "); // skini sa vrha
Console.WriteLine();
}
}
Kolekcija
Kada je koristiti
Važne metode
List<T>
niz promenljive dužine
Add, Insert, Remove, Sort, Contains, Count
Dictionary<K,V>
brza pretraga po ključu, brojanje
[ključ], ContainsKey, TryGetValue, Remove
HashSet<T>
jedinstveni elementi, pripadnost
Add, Contains, UnionWith, IntersectWith
Queue<T>
obrada redom dolaska
Enqueue, Dequeue, Peek
Stack<T>
poslednji ulazi – prvi izlazi
Push, Pop, Peek
Zadaci za vežbu
Za svaki zadatak postoji primer, uputstvo i rešenje. Rešenja su provereno tačna na primerima iz teksta.
ZADATAK 01Težina: lako
Najčešća reč
Učitati red reči razdvojenih razmakom i ispisati reč koja se najčešće pojavljuje i koliko puta. Ako ima više takvih reči, ispisati onu koja je prva po abecedi.
Primer 1
Ulaz
da ne da mozda ne da
Izlaz
da 3
Primer 2
Ulaz
b a b a
Izlaz
a 2
Uputstvo
Prebroj reči u Dictionary<string, int>, pa u jednom prolazu kroz rečnik pamti najbolju: veći broj, ili isti broj i manja reč (string.CompareOrdinal).
Rešenje (C#)
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var broj = new Dictionary<string, int>();
foreach (string r in Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries))
broj[r] = broj.TryGetValue(r, out int k) ? k + 1 : 1;
string najRec = "";
int najBroj = 0;
foreach (var p in broj)
if (p.Value > najBroj || (p.Value == najBroj && string.CompareOrdinal(p.Key, najRec) < 0))
{
najRec = p.Key;
najBroj = p.Value;
}
Console.WriteLine($"{najRec} {najBroj}");
}
}
ZADATAK 02Težina: srednje
Zagrade
Učitati red koji sadrži zagrade ( ) [ ] { } (i eventualno druge znakove) i ispisati DA ako su zagrade pravilno uparene i ugnježdene, a NE u suprotnom.
Primer 1
Ulaz
{[()()]}
Izlaz
DA
Primer 2
Ulaz
([)]
Izlaz
NE
Primer 3
Ulaz
((
Izlaz
NE
Uputstvo
Otvorenu zagradu stavi na stek. Za zatvorenu: stek ne sme biti prazan, a zagrada na vrhu mora biti odgovarajuća otvorena. Na kraju stek mora biti prazan.
Rešenje (C#)
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
string s = Console.ReadLine();
var stek = new Stack<char>();
bool ok = true;
foreach (char c in s)
{
if (c == '(' || c == '[' || c == '{')
stek.Push(c);
else if (c == ')' || c == ']' || c == '}')
{
char ocekivano = c == ')' ? '(' : c == ']' ? '[' : '{';
if (stek.Count == 0 || stek.Pop() != ocekivano)
{
ok = false;
break;
}
}
}
Console.WriteLine(ok && stek.Count == 0 ? "DA" : "NE");
}
}
Česte greške i saveti
Na vrh fajla dodaj using System.Collections.Generic;.
Lista ima Count, a niz Length.
Pre čitanja iz rečnika proveri ključ (ContainsKey ili TryGetValue).
Kolekcija se ne sme menjati (dodavati ili brisati elemente) dok se kroz nju prolazi petljom foreach.
Proveri znanje
Otvori kviz
Kolekcije u C#
1. Koje svojstvo daje broj elemenata liste?
2. Koja kolekcija je najbolja za brojanje koliko puta se pojavila svaka reč?
3. Šta vraća Add na HashSet ako element već postoji?
4. Koja kolekcija radi po pravilu „poslednji ulazi, prvi izlazi“?
Podešavanja kolačića
Koristimo kolačiće da bismo vam pružili najbolje moguće iskustvo. Takođe nam omogućavaju da analiziramo ponašanje korisnika kako bismo stalno poboljšavali veb lokaciju za vas.