STL Algoritmaları
STL algoritmaları, container'lar üzerinde işlem yapan hazır fonksiyonlardır. Sıralama, arama, dönüştürme, filtreleme — hepsini kendin yazmak yerine tek satırda halledebilirsin.
Bir İsviçre çakısı gibi düşün: içinde düzinelerce araç var ve her biri belirli bir iş için tasarlanmış. Hepsini bilmek zorunda değilsin ama temel olanları bilmek hayatını inanılmaz kolaylaştırır.
Tüm STL algoritmaları iterator'lar üzerinden çalışır. Bu sayede herhangi bir container ile kullanabilirsin — aynı sort hem vector hem deque üzerinde çalışır.
std::sort — Sıralama
En sık kullanılan algoritmadır. Varsayılan olarak küçükten büyüğe sıralar. Performansı O(n log n) — pratikte son derece hızlıdır (introsort kullanır).
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> nums = {5, 3, 8, 1, 9, 2, 7};
// Küçükten büyüğe sıralama
std::sort(nums.begin(), nums.end());
for (int x : nums) std::cout << x << " ";
// Çıktı: 1 2 3 5 7 8 9
std::cout << "\n";
// Büyükten küçüğe sıralama
std::sort(nums.begin(), nums.end(), std::greater<int>());
for (int x : nums) std::cout << x << " ";
// Çıktı: 9 8 7 5 3 2 1
std::cout << "\n";
return 0;
}Custom Comparator ile Sıralama
Kendi sıralama kuralını tanımlayabilirsin:
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
struct Student {
std::string name;
double gpa;
};
int main() {
std::vector<Student> students = {
{"Ali", 3.5}, {"Ayse", 3.8}, {"Mehmet", 2.9}, {"Zeynep", 3.8}
};
// GPA'ya göre azalan sırala, eşitse isme göre artan
std::sort(students.begin(), students.end(),
[](const Student& a, const Student& b) {
if (a.gpa != b.gpa) return a.gpa > b.gpa;
return a.name < b.name;
});
for (const auto& s : students) {
std::cout << s.name << " (" << s.gpa << ")\n";
}
// Ayse (3.8)
// Zeynep (3.8)
// Ali (3.5)
// Mehmet (2.9)
return 0;
}partial_sort ve stable_sort
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> nums = {5, 3, 8, 1, 9, 2, 7};
// partial_sort — sadece ilk 3'ü sırala
std::partial_sort(nums.begin(), nums.begin() + 3, nums.end());
// İlk 3 eleman sıralı: 1 2 3 ... geri kalanı belirsiz
std::cout << "Top 3: ";
for (int i = 0; i < 3; ++i) std::cout << nums[i] << " ";
std::cout << "\n";
// stable_sort — eşit elemanların orijinal sırasını korur
std::vector<std::pair<int, std::string>> items = {
{2, "elma"}, {1, "armut"}, {2, "muz"}, {1, "cilek"}
};
std::stable_sort(items.begin(), items.end(),
[](const auto& a, const auto& b) { return a.first < b.first; });
for (const auto& [num, name] : items) {
std::cout << num << ":" << name << " ";
}
// 1:armut 1:cilek 2:elma 2:muz — eşit olanların sırası korundu
std::cout << "\n";
return 0;
}std::find ve std::find_if — Arama
find belirli bir değeri, find_if ise bir koşulu sağlayan ilk elemanı arar.
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> nums = {10, 25, 30, 45, 50, 65};
// Değere göre arama
auto it = std::find(nums.begin(), nums.end(), 30);
if (it != nums.end()) {
std::cout << "30 bulundu, indeks: "
<< std::distance(nums.begin(), it) << "\n";
}
// Koşula göre arama — ilk çift sayı
auto it2 = std::find_if(nums.begin(), nums.end(),
[](int x) { return x % 2 == 0; });
if (it2 != nums.end()) {
std::cout << "Ilk cift sayi: " << *it2 << "\n"; // 10
}
// Koşulu sağlamayan ilk eleman
auto it3 = std::find_if_not(nums.begin(), nums.end(),
[](int x) { return x < 40; });
if (it3 != nums.end()) {
std::cout << "40'tan buyuk/esit ilk: " << *it3 << "\n"; // 45
}
return 0;
}💡 Sorted container'larda (set, map) `find` üye fonksiyonunu kullan. STL'in
std::findalgoritması O(n) lineer arama yapar. Amaset::find()O(log n) — ağaç yapısından faydalanır.
std::count ve std::count_if — Sayma
Bir değerin veya koşulu sağlayan elemanların kaç tane olduğunu sayar.
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> nums = {1, 2, 3, 2, 4, 2, 5, 2};
// Değer sayma
int twos = std::count(nums.begin(), nums.end(), 2);
std::cout << "2'lerin sayisi: " << twos << "\n"; // 4
// Koşula göre sayma — kaç tanesi 3'ten büyük?
int bigOnes = std::count_if(nums.begin(), nums.end(),
[](int x) { return x > 3; });
std::cout << "3'ten buyuk: " << bigOnes << "\n"; // 2
// Pratik: çift sayıları say
int evens = std::count_if(nums.begin(), nums.end(),
[](int x) { return x % 2 == 0; });
std::cout << "Cift sayilar: " << evens << "\n"; // 5
return 0;
}std::transform — Dönüştürme
Her elemanı bir fonksiyondan geçirip sonucu başka bir yere (veya aynı yere) yazar. Fonksiyonel programlamadaki map operasyonuna karşılık gelir.
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
#include <cctype>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
std::vector<int> squares(nums.size());
// Her elemanın karesini al
std::transform(nums.begin(), nums.end(), squares.begin(),
[](int x) { return x * x; });
for (int x : squares) std::cout << x << " ";
// Çıktı: 1 4 9 16 25
std::cout << "\n";
// Yerinde dönüştürme — aynı container'a yaz
std::transform(nums.begin(), nums.end(), nums.begin(),
[](int x) { return x * 2; });
for (int x : nums) std::cout << x << " ";
// Çıktı: 2 4 6 8 10
std::cout << "\n";
// String'i büyük harfe çevir
std::string text = "merhaba dunya";
std::transform(text.begin(), text.end(), text.begin(),
[](char c) { return std::toupper(c); });
std::cout << text << "\n"; // MERHABA DUNYA
return 0;
}İki Container ile Transform
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> a = {1, 2, 3, 4, 5};
std::vector<int> b = {10, 20, 30, 40, 50};
std::vector<int> result(a.size());
// İki container'ın elemanlarını topla
std::transform(a.begin(), a.end(), b.begin(), result.begin(),
[](int x, int y) { return x + y; });
for (int x : result) std::cout << x << " ";
// Çıktı: 11 22 33 44 55
std::cout << "\n";
return 0;
}std::accumulate — Biriktirme/Toplama
Tüm elemanları bir başlangıç değerinden başlayarak birleştirir. Varsayılan olarak toplama yapar ama herhangi bir işlem tanımlayabilirsin.
#include <vector>
#include <numeric>
#include <string>
#include <iostream>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
// Toplam
int sum = std::accumulate(nums.begin(), nums.end(), 0);
std::cout << "Toplam: " << sum << "\n"; // 15
// Çarpım
int product = std::accumulate(nums.begin(), nums.end(), 1,
[](int acc, int x) { return acc * x; });
std::cout << "Carpim: " << product << "\n"; // 120
// String birleştirme
std::vector<std::string> words = {"Merhaba", " ", "Dunya", "!"};
std::string sentence = std::accumulate(
words.begin(), words.end(), std::string(""));
std::cout << sentence << "\n"; // Merhaba Dunya!
return 0;
}⚠️ `accumulate`'in başlangıç değerinin tipi önemli!
std::accumulate(v.begin(), v.end(), 0)ile0(int) verirsen sonuç int olur. Ondalıklı sonuç istiyorsan0.0(double) ver.
#include <vector>
#include <numeric>
#include <iostream>
int main() {
std::vector<double> grades = {3.5, 3.8, 2.9, 3.2};
// YANLIŞ — int başlangıç değeri, kesirler kaybolur
// double avg = std::accumulate(grades.begin(), grades.end(), 0) / grades.size();
// DOĞRU — double başlangıç değeri
double avg = std::accumulate(grades.begin(), grades.end(), 0.0)
/ grades.size();
std::cout << "Ortalama: " << avg << "\n"; // 3.35
return 0;
}std::for_each — Her Eleman İçin
Her eleman üzerinde bir fonksiyon çalıştırır. Modern C++'ta range-based for döngüsü genellikle daha okunabilir, ama for_each'in bazı avantajları var.
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
// Her elemanı yazdır
std::for_each(nums.begin(), nums.end(),
[](int x) { std::cout << x * x << " "; });
// Çıktı: 1 4 9 16 25
std::cout << "\n";
// Her elemanı değiştir
std::for_each(nums.begin(), nums.end(),
[](int& x) { x += 10; });
for (int x : nums) std::cout << x << " ";
// Çıktı: 11 12 13 14 15
std::cout << "\n";
return 0;
}std::min_element ve std::max_element
Container'daki en küçük veya en büyük elemana iterator döner.
#include <vector>
#include <algorithm>
#include <iostream>
#include <string>
int main() {
std::vector<int> nums = {5, 3, 8, 1, 9, 2};
auto minIt = std::min_element(nums.begin(), nums.end());
auto maxIt = std::max_element(nums.begin(), nums.end());
std::cout << "Min: " << *minIt << " (indeks "
<< std::distance(nums.begin(), minIt) << ")\n";
std::cout << "Max: " << *maxIt << " (indeks "
<< std::distance(nums.begin(), maxIt) << ")\n";
// İkisini birden — minmax_element
auto [lo, hi] = std::minmax_element(nums.begin(), nums.end());
std::cout << "Min: " << *lo << ", Max: " << *hi << "\n";
// Custom comparator — en uzun string
std::vector<std::string> words = {"elma", "portakal", "muz", "cilek"};
auto longest = std::max_element(words.begin(), words.end(),
[](const std::string& a, const std::string& b) {
return a.length() < b.length();
});
std::cout << "En uzun: " << *longest << "\n"; // portakal
return 0;
}Remove-Erase Idiom
STL'in remove algoritması aslında elemanları silmez — sadece silinmeyecek elemanları öne taşır ve "yeni son"a iterator döner. Gerçek silme işlemi container'ın erase fonksiyonu ile yapılır.
Bu ikili kullanıma remove-erase idiom denir.
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> nums = {1, 2, 3, 2, 4, 2, 5};
// Adım 1: remove — 2'leri "sona taşı"
auto newEnd = std::remove(nums.begin(), nums.end(), 2);
// nums şimdi: {1, 3, 4, 5, ?, ?, ?}
// ^ newEnd
// Adım 2: erase — sondaki çöpleri sil
nums.erase(newEnd, nums.end());
// nums şimdi: {1, 3, 4, 5}
for (int x : nums) std::cout << x << " ";
// Çıktı: 1 3 4 5
std::cout << "\n";
return 0;
}Tek Satırda (Klasik Pattern)
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> nums = {1, 2, 3, 2, 4, 2, 5};
// Tek satır remove-erase
nums.erase(std::remove(nums.begin(), nums.end(), 2), nums.end());
for (int x : nums) std::cout << x << " ";
std::cout << "\n";
// Koşula göre — çift sayıları sil
nums = {1, 2, 3, 4, 5, 6, 7, 8};
nums.erase(
std::remove_if(nums.begin(), nums.end(),
[](int x) { return x % 2 == 0; }),
nums.end());
for (int x : nums) std::cout << x << " ";
// Çıktı: 1 3 5 7
std::cout << "\n";
return 0;
}💡 C++20'de `std::erase` ve `std::erase_if` geldi — artık remove-erase idiom'una gerek yok: ``
cpp std::erase(nums, 2); // Tüm 2'leri sil std::erase_if(nums, [](int x) { return x > 5; }); // Koşula göre sil``
Diğer Faydalı Algoritmalar
copy ve copy_if
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
int main() {
std::vector<int> src = {1, 2, 3, 4, 5, 6, 7, 8};
std::vector<int> dst;
// Sadece çift olanları kopyala
std::copy_if(src.begin(), src.end(), std::back_inserter(dst),
[](int x) { return x % 2 == 0; });
for (int x : dst) std::cout << x << " ";
// Çıktı: 2 4 6 8
std::cout << "\n";
return 0;
}any_of, all_of, none_of
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> nums = {2, 4, 6, 8, 10};
bool allEven = std::all_of(nums.begin(), nums.end(),
[](int x) { return x % 2 == 0; });
std::cout << "Hepsi cift mi? " << (allEven ? "Evet" : "Hayir") << "\n";
bool anyNegative = std::any_of(nums.begin(), nums.end(),
[](int x) { return x < 0; });
std::cout << "Negatif var mi? " << (anyNegative ? "Evet" : "Hayir") << "\n";
bool noneZero = std::none_of(nums.begin(), nums.end(),
[](int x) { return x == 0; });
std::cout << "Sifir yok mu? " << (noneZero ? "Evet" : "Hayir") << "\n";
return 0;
}fill ve iota
#include <vector>
#include <algorithm>
#include <numeric>
#include <iostream>
int main() {
std::vector<int> v(10);
// Hepsini aynı değerle doldur
std::fill(v.begin(), v.end(), 42);
// v: {42, 42, 42, ...}
// Artan değerlerle doldur
std::iota(v.begin(), v.end(), 1);
// v: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for (int x : v) std::cout << x << " ";
std::cout << "\n";
return 0;
}unique
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> nums = {1, 1, 2, 2, 3, 3, 3, 4, 5, 5};
// unique — ardışık tekrarları kaldırır (önce sıralı olmalı!)
auto newEnd = std::unique(nums.begin(), nums.end());
nums.erase(newEnd, nums.end());
for (int x : nums) std::cout << x << " ";
// Çıktı: 1 2 3 4 5
std::cout << "\n";
return 0;
}reverse ve rotate
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// Ters çevir
std::reverse(v.begin(), v.end());
for (int x : v) std::cout << x << " ";
// Çıktı: 5 4 3 2 1
std::cout << "\n";
// Rotate — 3. eleman başa gelsin
v = {1, 2, 3, 4, 5};
std::rotate(v.begin(), v.begin() + 2, v.end());
for (int x : v) std::cout << x << " ";
// Çıktı: 3 4 5 1 2
std::cout << "\n";
return 0;
}Algoritma Hızlı Referans Tablosu
| Algoritma | Ne Yapar | Karmaşıklık |
|---|---|---|
sort | Sıralar | O(n log n) |
stable_sort | Sıralar (eşit elemanların sırası korunur) | O(n log n) |
partial_sort | İlk k elemanı sıralar | O(n log k) |
find / find_if | İlk eşleşeni bulur | O(n) |
count / count_if | Eşleşen sayısını döner | O(n) |
transform | Her elemanı dönüştürür | O(n) |
accumulate | Elemanları birleştirir | O(n) |
for_each | Her elemana fonksiyon uygular | O(n) |
min_element / max_element | En küçük/büyük | O(n) |
remove / remove_if | Elemanları "sona taşır" | O(n) |
copy / copy_if | Elemanları kopyalar | O(n) |
all_of / any_of / none_of | Koşul kontrolü | O(n) |
fill | Aynı değerle doldurur | O(n) |
iota | Artan değerlerle doldurur | O(n) |
reverse | Ters çevirir | O(n) |
unique | Ardışık tekrarları kaldırır | O(n) |
Özet
`std::sort` O(n log n) sıralama yapar. Custom comparator ile kendi sıralama kuralını tanımlayabilirsin.
stable_sorteşit elemanların orijinal sırasını korur.`std::find` ve `std::find_if` lineer arama yapar (O(n)). Sorted container'larda üye fonksiyonlarını (
set::findgibi) tercih et.`std::transform` her elemanı bir fonksiyondan geçirir — fonksiyonel programlamadaki
mapkarşılığı.`std::accumulate` elemanları bir başlangıç değerinden itibaren birleştirir — toplama, çarpma, string birleştirme. Başlangıç değerinin tipi sonucu belirler.
Remove-erase idiom iki adımlı bir silme tekniğidir:
removetaşır,erasesiler. C++20'destd::erase/std::erase_ifbunu tek satıra indirir.STL algoritmaları iterator tabanlıdır — container'dan bağımsız çalışırlar.
<algorithm>ve<numeric>header'larını dahil etmeyi unutma.
AI Asistan
Sorularını yanıtlamaya hazır