AVL वृक्ष: घूर्णन, सम्मिलन, विलोपन C++ उदाहरण
⚡ स्मार्ट सारांश
AVL ट्री स्व-संतुलन वाले बाइनरी सर्च ट्री होते हैं, जहां प्रत्येक नोड के बाएं और दाएं सबट्री के बीच ऊंचाई का अंतर -1, 0 या +1 के भीतर रहता है, जो O(log n) सर्च प्रदर्शन की गारंटी देता है।
AVL वृक्ष क्या हैं?
एवीएल पेड़ बाइनरी सर्च ट्री (बीएसटी) में प्रत्येक नोड के बाएं और दाएं सबट्री के बीच ऊंचाई का अंतर -1, 0 या +1 होता है। ये स्व-संतुलित बीएसटी होते हैं जो लॉगरिदमिक सर्च टाइम बनाए रखते हैं, और इनका नाम आविष्कारकों एडेलसन-वेल्स्की और लैंडिस (एवीएल) के नाम पर रखा गया है।
AVL ट्री कैसे काम करता है?
AVL ट्री क्यों मौजूद हैं, यह समझने के लिए, देखें कि एक साधारण AVL ट्री में क्या गड़बड़ी होती है। बाइनरी सर्च ट्रीइन कुंजियों को दिए गए क्रम में डालने पर विचार करें:
AVL वृक्ष दृश्यावलोकन
कुंजीयाँ बढ़ते क्रम में आने पर वृक्ष रैखिक रूप से बढ़ता है, जिससे खोज समय O(n) तक सीमित हो जाता है। यह एक संतुलित वृक्ष (BST) के उद्देश्य को ही विफल कर देता है — केवल एक संतुलित वृक्ष ही खोज समय को लघुगणकीय बनाए रखता है। अब उन्हीं कुंजियों को अलग क्रम में डालने पर विचार करें।
समान कुंजी, अलग-अलग सम्मिलन क्रम से एक उथली आकृति बनती है, इसलिए प्रत्येक खोज O(log n) समय में पूरी होती है। AVL ट्री प्रत्येक सम्मिलन पर ऊंचाई की निगरानी करके और BST क्रम को तोड़े बिना असंतुलन को ठीक करके उस आकृति को बनाए रखते हैं।
AVL वृक्षों में संतुलन कारक
संतुलन कारक (बीएफ) tracप्रत्येक नोड की ऊंचाई को समायोजित करें ताकि ट्री चलते-फिरते स्वयं को संतुलित कर सके।
बैलेंस फैक्टर के गुण
संतुलन कारक AVL वृक्ष
- संतुलन कारक बाएं सबट्री की ऊंचाई और दाएं सबट्री की ऊंचाई के बीच का अंतर है।
Balance factor(node) = height(node->left) − height(node->right)- केवल अनुमत मान -1, 0 और +1 हैं।
- -1 का मान यह दर्शाता है कि दाएँ उपवृक्ष में एक अतिरिक्त स्तर है - नोड दाएँ-भारी है।
- +1 का मान यह दर्शाता है कि बाएं उपवृक्ष में एक अतिरिक्त स्तर है - नोड बाएँ ओर अधिक भार वाला है।
- 0 का मान यह दर्शाता है कि दोनों भुजाओं की ऊंचाई बराबर है — नोड पूरी तरह से संतुलित है।
एवीएल रोटेशन
जब भी कोई प्रविष्टि या विलोपन संतुलन कारक नियम को तोड़ता है, तो घूर्णन प्रक्रिया चलती है। ये चार स्थितियाँ हैं: LL, RR, LR और RL।
बायाँ – बायाँ घुमाव
यह रोटेशन तब किया जाता है जब बाएं उपवृक्ष के बाएं संतान में एक नया नोड डाला जाता है।
AVL ट्री बायाँ – बायाँ रोटेशन
एक बार दाएँ ओर घूर्णन किया जाता है। यह स्थिति तब उत्पन्न होती है जब किसी नोड का BF +2 हो और उसके बाएँ चाइल्ड का BF +1 हो।
दायाँ-दायाँ घुमाव
यह रोटेशन तब किया जाता है जब दाएं उपवृक्ष के दाएं संतान में एक नया नोड डाला जाता है।
एक बार बाएँ ओर घूर्णन किया जाता है। यह स्थिति तब उत्पन्न होती है जब किसी नोड का BF −2 हो और उसके दाएँ चाइल्ड का BF −1 हो।
दायाँ-बायाँ घुमाव
यह रोटेशन तब किया जाता है जब दाएं उपवृक्ष के बाएं संतान में एक नया नोड डाला जाता है।
यह तब सक्रिय होता है जब BF(नोड) = −2 और BF(दायां चाइल्ड) = +1 हो। दाएं चाइल्ड को दाईं ओर घुमाएं, फिर नोड को बाईं ओर घुमाएं।
बाएँ-दाएँ घुमाव
यह रोटेशन तब किया जाता है जब बाएं उपवृक्ष के दाएं संतान में एक नया नोड डाला जाता है।
यह तब सक्रिय होता है जब BF(नोड) = +2 और BF(बायां चाइल्ड) = −1 हो। पहले बाएं चाइल्ड को बाईं ओर घुमाएं, फिर नोड को दाईं ओर घुमाएं।
AVL वृक्षों में सम्मिलन
इंसर्शन प्रक्रिया लगभग एक सामान्य BST इंसर्शन के समान है। प्रत्येक इंसर्शन के बाद, ट्री ऊपर की ओर बढ़ता है और पुनः संतुलन स्थापित करता है। इंसर्शन प्रक्रिया सबसे खराब स्थिति में O(log n) समय में पूरी हो जाती है।
AVL वृक्ष सम्मिलन कार्यान्वयन
चरण १: मानक BST एल्गोरिदम का उपयोग करके नोड डालें। ऊपर दिए गए उदाहरण में, 160 डालें।
चरण १: सम्मिलन पथ के साथ प्रत्येक पूर्वज के संतुलन कारक को अद्यतन करें।
चरण १: यदि कोई पूर्वज संतुलन कारक सीमा का उल्लंघन करता है, तो मिलान रोटेशन निष्पादित करें। उदाहरण में, नोड 350 का संतुलन कारक उल्लंघन करता है, इसलिए एक एलएल रोटेशन संतुलन को बहाल करता है।
- If
BF(node) = +2औरBF(left-child) = +1एलएल रोटेशन करें। - If
BF(node) = −2औरBF(right-child) = −1आरआर रोटेशन करें। - If
BF(node) = −2औरBF(right-child) = +1आरएल रोटेशन निष्पादित करें। - If
BF(node) = +2औरBF(left-child) = −1LR रोटेशन करें।
AVL वृक्षों में विलोपन
विलोपन की प्रक्रिया एक सामान्य बीएसटी के समान ही होती है और बाद में पुनः संतुलित हो जाती है।
चरण १: पेड़ में तत्व ढूंढें.
चरण १: मानक बीएसटी विलोपन विधि का उपयोग करके नोड को हटाएँ।
चरण १: दो स्थितियाँ संभव हैं।
प्रकरण 1: दाएँ उपवृक्ष से हटाया जा रहा है.
- 1A. If
BF(node) = +2औरBF(left-child) = +1एलएल रोटेशन करें। - 1B। If
BF(node) = +2औरBF(left-child) = −1LR रोटेशन करें। - 1C। If
BF(node) = +2औरBF(left-child) = 0एलएल रोटेशन करें।
प्रकरण 2: बाएँ उपवृक्ष से हटाना।
- 2A. If
BF(node) = −2औरBF(right-child) = −1आरआर रोटेशन करें। - 2B। If
BF(node) = −2औरBF(right-child) = +1आरएल रोटेशन निष्पादित करें। - 2C। If
BF(node) = −2औरBF(right-child) = 0आरआर रोटेशन करें।
C++ AVL वृक्षों का उदाहरण
नीचे एक है C++ AVL ट्री को लागू करने वाला प्रोग्राम:
#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); }
ऊपर दिए गए कोड का उदाहरण:
- ऊपर दिए गए कोड को कॉपी करें और इसे एक फ़ाइल में सेव करें जिसका नाम है
avl.cpp. - कोड संकलित करें:
g++ avl.cpp -o run
- कोड चलाएँ.
./run
एवीएल वृक्षों के लाभ
- AVL ट्री की ऊंचाई हमेशा संतुलित रहती है और कभी भी log N से अधिक नहीं बढ़ती है।
- यह सर्च एक साधारण बाइनरी सर्च ट्री की तुलना में तेज़ है क्योंकि ट्री विकृत नहीं हो सकता।
- स्व-संतुलन स्वचालित है — पुनर्निर्माण की कोई आवश्यकता नहीं है।
- निश्चित प्रदर्शन वास्तविक समय प्रणालियों और इन-मेमोरी इंडेक्स के लिए उपयुक्त है।












