AVL Ağaçları: Döndürme, Ekleme, Silme C++ Örnek E-posta
⚡ Akıllı Özet
AVL Ağaçları, her düğümün sol ve sağ alt ağaçları arasındaki yükseklik farkının -1, 0 veya +1 içinde kaldığı, O(log n) arama performansını garanti eden, kendi kendini dengeleyen ikili arama ağaçlarıdır.

AVL Ağaçları nedir?
AVL Ağaçları İkili arama ağaçları, her düğümün sol ve sağ alt ağacı arasındaki yükseklik farkının -1, 0 veya +1 olduğu ağaçlardır. Logaritmik arama süresini koruyan, kendi kendini dengeleyen ikili arama ağaçlarıdır ve mucitleri Adelson-Velsky ve Landis'in (AVL) adını taşırlar.
AVL Ağacı nasıl çalışır?
AVL ağaçlarının neden var olduğunu anlamak için, düz bir yapıda nelerin yanlış gittiğine bakın. İkili Arama AğacıAşağıdaki tuşların verilen sırayla yerleştirildiğini göz önünde bulundurun:
AVL ağaç görselleştirmesi
Anahtarlar artan sırada geldiğinde ağaç doğrusal olarak büyür ve arama karmaşıklığı O(n)'ye düşer. Bu, ikili arama ağacının amacını ortadan kaldırır; yalnızca dengeli bir ağaç aramayı logaritmik tutar. Şimdi aynı anahtarların farklı bir sırada eklenmesine bakalım.
Aynı anahtarlar, farklı ekleme sırası daha sığ bir şekil oluşturur, bu nedenle her arama O(log n) sürede çalışır. AVL Ağaçları, her eklemede yüksekliği izleyerek ve BST sıralamasını bozmadan dengesizliği düzelterek bu şekli sağlar.
AVL Ağaçlarında Denge Faktörü
Denge faktörü (BF) tracHer düğümün yüksekliğini ks cinsinden belirterek ağacın anlık olarak kendi kendini dengeleyebilmesini sağlar.
Denge Faktörünün Özellikleri
Denge faktörü AVL ağacı
- Denge faktörü, sol alt ağacın yüksekliği ile sağ alt ağacın yüksekliği arasındaki farktır.
Balance factor(node) = height(node->left) − height(node->right)- İzin verilen tek değerler -1, 0 ve +1'dir.
- -1 değeri, sağ alt ağacın fazladan bir seviye içerdiği anlamına gelir; yani düğüm sağ ağırlıklıdır.
- +1 değeri, sol alt ağacın fazladan bir seviye içerdiği anlamına gelir; yani düğüm sol ağırlıklıdır.
- 0 değeri, her iki tarafın da eşit yüksekliğe sahip olduğu anlamına gelir; düğüm mükemmel bir şekilde dengededir.
AVL Rotasyonları
Ekleme veya silme işlemi denge faktörü kuralını bozduğunda rotasyonlar çalışır. Dört durum LL, RR, LR ve RL'dir.
Sol – Sola Dönüş
Bu döndürme, sol alt ağacın sol çocuğuna yeni bir düğüm eklendiğinde gerçekleştirilir.
AVL Ağacı Sola – Sola Döndürme
Tek bir sağa döndürme işlemi gerçekleştirilir. Bu durum, bir düğümün BF +2 değerine sahip olması ve sol çocuğunun BF +1 değerine sahip olması durumunda tetiklenir.
Sağ – Sağ Döndürme
Bu döndürme, sağ alt ağacın sağ çocuğuna yeni bir düğüm eklendiğinde gerçekleştirilir.
Tek bir sola döndürme işlemi gerçekleştirilir. Bu durum, bir düğümün BF değeri -2 ve sağ çocuğunun BF değeri -1 olduğunda tetiklenir.
Sağa – Sola Dönüş
Bu döndürme, sağ alt ağacın sol çocuğuna yeni bir düğüm eklendiğinde gerçekleştirilir.
BF(düğüm) = −2 ve BF(sağ çocuk) = +1 olduğunda tetiklenir. Sağ çocuğu sağa döndürün, ardından düğümü sola döndürün.
Sol – Sağa Döndürme
Bu döndürme, sol alt ağacın sağ çocuğuna yeni bir düğüm eklendiğinde gerçekleştirilir.
BF(düğüm) = +2 ve BF(sol çocuk) = −1 olduğunda tetiklenir. Sol çocuğu sola döndürün, ardından düğümü sağa döndürün.
AVL Ağaçlarına Ekleme
Ekleme işlemi, düz bir BST ekleme işlemine neredeyse tamamen benzer. Her eklemeden sonra ağaç yukarı doğru ilerler ve yeniden dengelenir. Ekleme işlemi en kötü durumda O(log n) sürede çalışır.
AVL ağaç ekleme uygulaması
1 Adım: Düğümü standart BST algoritmasını kullanarak ekleyin. Yukarıdaki örnekte, 160'ı ekleyin.
2 Adım: Ekleme yolu boyunca her bir atanın denge faktörünü güncelleyin.
3 Adım: Eğer herhangi bir üst düğüm denge faktörü aralığını ihlal ederse, eşleşen döndürme işlemini gerçekleştirin. Örnekte, 350 numaralı düğümün denge faktörü ihlal edildiğinden, bir LL döndürme işlemi dengeyi yeniden sağlar.
- If
BF(node) = +2hem deBF(left-child) = +1LL rotasyonunu gerçekleştirin. - If
BF(node) = −2hem deBF(right-child) = −1RR rotasyonunu gerçekleştirin. - If
BF(node) = −2hem deBF(right-child) = +1RL rotasyonunu gerçekleştirin. - If
BF(node) = +2hem deBF(left-child) = −1LR rotasyonunu gerçekleştirin.
AVL Ağaçlarında Silme
Silme işlemi, düz bir ikili arama ağacındakiyle aynı mantığı izler ve sonrasında yeniden dengeleme yapar.
1 Adım: Ağaçtaki öğeyi bulun.
2 Adım: Düğümü standart BST silme yöntemini kullanarak silin.
3 Adım: İki olasılık söz konusudur.
Olgu 1: Sağ alt ağaçtan silme.
- 1A. If
BF(node) = +2hem deBF(left-child) = +1LL rotasyonunu gerçekleştirin. - 1B. If
BF(node) = +2hem deBF(left-child) = −1LR rotasyonunu gerçekleştirin. - 1C. If
BF(node) = +2hem deBF(left-child) = 0LL rotasyonunu gerçekleştirin.
Olgu 2: Sol alt ağaçtan silme işlemi.
- 2A. If
BF(node) = −2hem deBF(right-child) = −1RR rotasyonunu gerçekleştirin. - 2B. If
BF(node) = −2hem deBF(right-child) = +1RL rotasyonunu gerçekleştirin. - 2C. If
BF(node) = −2hem deBF(right-child) = 0RR rotasyonunu gerçekleştirin.
C++ AVL Ağaçları Örneği
Aşağıda ise C++ AVL Ağaçlarını uygulayan program:
#include <iostream> #include <queue> #include <unordered_map> using namespace std; struct node { struct node *left; int data; int height; struct node *right; }; class AVL { public: struct node *root; AVL() { this->root = NULL; } int calheight(struct node *p) { if (p->left && p->right) { if (p->left->height < p->right->height) return p->right->height + 1; else return p->left->height + 1; } else if (p->left && p->right == NULL) { return p->left->height + 1; } else if (p->left == NULL && p->right) { return p->right->height + 1; } return 0; } int bf(struct node *n) { if (n->left && n->right) return n->left->height - n->right->height; else if (n->left && n->right == NULL) return n->left->height; else if (n->left == NULL && n->right) return -n->right->height; return 0; } struct node *llrotation(struct node *n) { struct node *p = n; struct node *tp = p->left; p->left = tp->right; tp->right = p; return tp; } struct node *rrrotation(struct node *n) { struct node *p = n; struct node *tp = p->right; p->right = tp->left; tp->left = p; return tp; } struct node *rlrotation(struct node *n) { struct node *p = n; struct node *tp = p->right; struct node *tp2 = p->right->left; p->right = tp2->left; tp->left = tp2->right; tp2->left = p; tp2->right = tp; return tp2; } struct node *lrrotation(struct node *n) { struct node *p = n; struct node *tp = p->left; struct node *tp2 = p->left->right; p->left = tp2->right; tp->right = tp2->left; tp2->right = p; tp2->left = tp; return tp2; } struct node *insert(struct node *r, int data) { if (r == NULL) { r = new struct node; r->data = data; r->left = r->right = NULL; r->height = 1; return r; } if (data < r->data) r->left = insert(r->left, data); else r->right = insert(r->right, data); r->height = calheight(r); if (bf(r) == 2 && bf(r->left) == 1) r = llrotation(r); else if (bf(r) == -2 && bf(r->right) == -1) r = rrrotation(r); else if (bf(r) == -2 && bf(r->right) == 1) r = rlrotation(r); else if (bf(r) == 2 && bf(r->left) == -1) r = lrrotation(r); return r; } void levelorder_newline() { if (this->root == NULL) { cout << "\nEmpty tree\n"; return; } levelorder_newline(this->root); } void levelorder_newline(struct node *v) { queue<struct node *> q; struct node *cur; q.push(v); q.push(NULL); while (!q.empty()) { cur = q.front(); q.pop(); if (cur == NULL && q.size() != 0) { cout << "\n"; q.push(NULL); continue; } if (cur != NULL) { cout << " " << cur->data; if (cur->left != NULL) q.push(cur->left); if (cur->right != NULL) q.push(cur->right); } } } struct node *deleteNode(struct node *p, int data) { if (p->left == NULL && p->right == NULL) { if (p == this->root) this->root = NULL; delete p; return NULL; } struct node *q; if (p->data < data) p->right = deleteNode(p->right, data); else if (p->data > data) p->left = deleteNode(p->left, data); else { if (p->left != NULL) { q = inpre(p->left); p->data = q->data; p->left = deleteNode(p->left, q->data); } else { q = insuc(p->right); p->data = q->data; p->right = deleteNode(p->right, q->data); } } if (bf(p) == 2 && bf(p->left) == 1) p = llrotation(p); else if (bf(p) == 2 && bf(p->left) == -1) p = lrrotation(p); else if (bf(p) == 2 && bf(p->left) == 0) p = llrotation(p); else if (bf(p) == -2 && bf(p->right) == -1) p = rrrotation(p); else if (bf(p) == -2 && bf(p->right) == 1) p = rlrotation(p); else if (bf(p) == -2 && bf(p->right) == 0) p = rrrotation(p); return p; } struct node *inpre(struct node *p) { while (p->right != NULL) p = p->right; return p; } struct node *insuc(struct node *p) { while (p->left != NULL) p = p->left; return p; } ~AVL() {} }; int main() { AVL b; int c, x; do { cout << "\n1.Display levelorder on newline"; cout << "\n2.Insert"; cout << "\n3.Delete\n"; cout << "\n0.Exit\n"; cout << "\nChoice: "; cin >> c; switch (c) { case 1: b.levelorder_newline(); break; case 2: cout << "\nEnter no. "; cin >> x; b.root = b.insert(b.root, x); break; case 3: cout << "\nWhat to delete? "; cin >> x; b.root = b.deleteNode(b.root, x); break; case 0: break; } } while (c != 0); }
Yukarıdaki kodun çalışma örneği:
- Yukarıdaki kodu kopyalayın ve bir dosyaya kaydedin.
avl.cpp. - Kodu derleyin:
g++ avl.cpp -o run
- Kodu çalıştırın.
./run
AVL Ağaçlarının Avantajları
- AVL ağacının yüksekliği her zaman dengelidir ve asla N kütüğünün ötesine geçmez.
- Arama, ağacın dejenere olmaması nedeniyle düz bir ikili arama ağacından daha hızlıdır.
- Otomatik dengeleme işlemi gerçekleşir; yeniden yapılandırma adımı gerekmez.
- Deterministik performans, gerçek zamanlı sistemler ve bellek içi indeksler için uygundur.











