Follow Us
माध्यम चुनें / Select Medium:
Eng (English) Beng (বাংলা) Hindi (हिन्दी)
WBB • कक्षा XI • Computer Science • अध्याय 4
अनुमानित समय: 45 Mins
प्रगति: अध्ययनरत

डेटा संरचना

डेटा संरचना (Data Structure) कंप्यूटर विज्ञान एवं सॉफ्टवेयर इंजीनियरिंग का मूलभूत आधार स्तंभ है, जो कंप्यूटर की मुख्य मेमोरी (RAM) में डेटा को व्यवस्थित, सुरक्षित और कुशल तरीके से संग्रहीत, एक्सेस एवं संसाधित करने के लिए गणितीय व तार्किक मॉडल प्रदान करता है। जहां प्रिमिटिव डेटा प्रकार (जैसे int, float, char) एकल और विशिष्ट मानों का प्रतिनिधित्व करते हैं, वहीं नॉन-प्रिमिटिव डेटा संरचनाएं वास्तविक जीवन की जटिल समस्याओं को हल करने के लिए विभिन्न डेटा तत्वों का एक सुव्यवस्थित ढांचा तैयार करती हैं। पश्चिम बंगाल उच्चतर माध्यमिक शिक्षा परिषद (WBCHSE) के कक्षा 11 पाठ्यक्रम के अनुसार इस अध्याय में लीनियर सन्निहित ऐरे (एक-विमीय एवं द्वि-विमीय मेमोरी मैपिंग तथा रो-मेजर व कॉलम-मेजर सूत्र), प्रतिबंधित पहुंच वाले अमूर्त डेटा प्रकार जैसे लास्ट-इन फर्स्ट-आउट (LIFO) स्टैक एवं फर्स्ट-इन फर्स्ट-आउट (FIFO) क्यू, सर्कुलर क्यू (Circular Queue), हीप मेमोरी में डायनेमिक सिंगली लिंक्ड लिस्ट तथा मौलिक सर्चिंग एवं सॉर्टिंग एल्गोरिदम का एसिम्प्टोटिक जटिलता विश्लेषण विस्तारपूर्वक प्रस्तुत किया गया है।

यह अध्याय क्यों महत्वपूर्ण है

आधुनिक कंप्यूटिंग युग में यदि डेटा मेमोरी में सही ढंग से संगठित नहीं है, तो तीव्रतम प्रोसेसर भी अप्रभावी हो जाते हैं। डेटा संरचना का चुनाव सीधे तौर पर किसी एल्गोरिदम के समय और स्थान की जटिलता (Time and Space Complexity) को निर्धारित करता है। एक अनुचित डेटा संरचना किसी सिस्टम की कार्यक्षमता को गंभीर रूप से धीमा कर सकती है। ऑपरेटिंग सिस्टम में रिकर्सिव फंक्शन कॉल्स और सिस्टम कॉल्स को ट्रैक करने के लिए स्टैक (कॉल स्टैक) अनिवार्य है; प्रिंटर स्पूलिंग एवं सीपीयू शेड्यूलिंग में क्यू का उपयोग होता है; परिवर्तनशील मेमोरी आवंटन में लिंक्ड लिस्ट प्रयुक्त होती है; तथा ग्राफिक्स रेंडरिंग एवं डेटाबेस इंडेक्सिंग में बहु-विमीय मैट्रिक्स काम आते हैं। कक्षा 11 के विद्यार्थियों के लिए बोर्ड परीक्षा में उत्कृष्ट अंक प्राप्त करने तथा सॉफ्टवेयर इंजीनियरिंग, प्रतियोगी प्रोग्रामिंग व उच्च अनुसंधान में सफल होने के लिए डेटा संरचनाओं का गहन अध्ययन अत्यंत आवश्यक है।

अध्याय रूपरेखा एवं प्रगति

1 मॉड्यूल 1: डेटा संरचनाओं का वर्गीकर...
2 मॉड्यूल 2: ऐरे: 1D एवं 2D मेमोरी मै...
3 मॉड्यूल 3: स्टैक आर्किटेक्चर: LIFO...
4 मॉड्यूल 4: क्यू आर्किटेक्चर: FIFO म...
5 मॉड्यूल 5: लिंक्ड लिस्ट: डायनेमिक न...
6 मॉड्यूल 6: सर्चिंग, सॉर्टिंग एवं तु...

सम्पूर्ण सैद्धांतिक एवं वैचारिक अध्ययन

मॉड्यूल 1: डेटा संरचनाओं का वर्गीकरण एवं एल्गोरिदम जटिलता

1.1 डेटा संरचना की परिभाषा एवं आवश्यकता

डेटा संरचना (Data Structure) कंप्यूटर मेमोरी में डेटा को व्यवस्थित, संसाधित, पुनः प्राप्त और संग्रहीत करने का एक विशेष प्रारूप है ताकि विभिन्न संक्रियाएं न्यूनतम समय में कुशलतापूर्वक निष्पादित की जा सकें। केवल एल्गोरिदम लिखना पर्याप्त नहीं है; एल्गोरिदम की वास्तविक गति डेटा संरचना की उपयुक्तता पर निर्भर करती है।

उपयुक्त डेटा संरचना के चयन हेतु तीन मुख्य कारक हैं: (1) डेटा की मात्रा एवं उनका आपसी संबंध, (2) बुनियादी ऑपरेशनों की आवृत्ति (जैसे खोजना, जोड़ना, हटाना), और (3) हार्डवेयर संसाधन (सीपीयू समय एवं मुख्य मेमोरी की खपत)।

1.2 पूर्ण वर्गीकरण: प्रिमिटिव बनाम नॉन-प्रिमिटिव

डेटा संरचनाओं को मुख्य रूप से दो श्रेणियों में बांटा गया है:

  • प्रिमिटिव डेटा संरचनाएं: वे बुनियादी डेटा प्रकार जो सीधे कंप्यूटर हार्डवेयर और मशीन निर्देशों द्वारा समर्थित होते हैं। C भाषा में int, float, char, double और पॉइंटर्स इसके उदाहरण हैं। ये किसी भी समय केवल एक परमाणु (atomic) मान रखते हैं।
  • नॉन-प्रिमिटिव डेटा संरचनाएं: समरूप या विषम डेटा तत्वों के समूह को व्यवस्थित करने के लिए प्रिमिटिव प्रकारों से निर्मित जटिल संरचनाएं। इन्हें पुनः दो वर्गों में विभाजित किया गया है:
वर्गीकरण श्रेणीसंरचनात्मक विशेषताएंप्रमुख उदाहरणट्रैवर्सल प्रणाली
लीनियर (रैखिक) डेटा संरचनातत्व एक अनुक्रमिक क्रम में व्यवस्थित होते हैं; प्रत्येक तत्व का एक निश्चित पूर्ववर्ती और उत्तरवर्ती होता है।ऐरे, स्टैक, क्यू, लिंक्ड लिस्टएक ही रैखिक पास में सभी तत्वों को $O(n)$ समय में देखा जा सकता है।
नॉन-लीनियर (गैर-रैखिक) संरचनातत्व अनुक्रमिक न होकर पदानुक्रमित (Hierarchical) या बहु-शाखा नेटवर्क के रूप में होते हैं।ट्री (बाइनरी ट्री, BST), ग्राफजटिल बहु-शाखा ट्रैवर्सल (DFS, BFS, इनऑर्डर, प्रीऑर्डर)।
स्टैटिक संरचनाएंकंपाइल समय पर मेमोरी का आकार निश्चित हो जाता है; रनटाइम पर आकार बदला नहीं जा सकता।निश्चित आकार के ऐरेस्टैक या डेटा सेगमेंट में मेमोरी आवंटित होती है।
डायनेमिक संरचनाएंप्रोग्राम निष्पादन के दौरान हीप मेमोरी से आवश्यकतानुसार मेमोरी ली और छोड़ी जाती है।लिंक्ड लिस्ट, डायनेमिक स्टैकmalloc() और free() द्वारा आकार घटता-बढ़ता है।
1.3 डेटा संरचनाओं पर मूल संक्रियाएं (Operations)

सभी डेटा संरचनाओं पर निम्नलिखित छह बुनियादी संक्रियाएं की जाती हैं:

  1. ट्रैवर्सिंग (Traversing): संरचना के प्रत्येक तत्व को कम से कम एक बार एक्सेस और प्रोसेस करना (जैसे सभी तत्वों को प्रिंट करना)।
  2. इंसर्शन (Insertion): संरचना में किसी निश्चित स्थान पर नया डेटा तत्व जोड़ना।
  3. डिलिशन (Deletion): संरचना से किसी मौजूदा तत्व को हटाना।
  4. सर्चिंग (Searching): दी गई 'की' (Key) के आधार पर किसी तत्व का स्थान खोजना (लीनियर व बाइनरी सर्च)।
  5. सॉर्टिंग (Sorting): तत्वों को किसी निश्चित क्रम (आरोही या अवरोही) में व्यवस्थित करना।
  6. मर्जिंग (Merging): दो अलग-अलग सॉर्ट की गई सूचियों को मिलाकर एक संयुक्त सूची बनाना।
कॉम्प्लेक्सिटी नोट: दक्षता को बिग-ओ (Big-O) नोटेशन में व्यक्त किया जाता है: $O(1)$ स्थिर समय, $O(\log n)$ लॉगरिदमिक समय, $O(n)$ रैखिक समय तथा $O(n^2)$ द्विघात समय को दर्शाता है।

मॉड्यूल 2: ऐरे: 1D एवं 2D मेमोरी मैपिंग एवं फॉर्मूले

2.1 एक-विमीय ऐरे (1D Array) आर्किटेक्चर

1D ऐरे समान डेटा प्रकार के तत्वों का एक निश्चित आकार का सतत (contiguous) मेमोरी ब्लॉक होता है। C भाषा में ऐरे इंडेक्सिंग सदैव 0 से प्रारंभ होती है, अतः $N$ आकार के ऐरे के इंडेक्स $0, 1, 2, \dots, N-1$ होते हैं।

चूंकि सभी तत्व मेमोरी में एक के बाद एक रखे जाते हैं, इसलिए किसी भी तत्व $A[i]$ का भौतिक मेमोरी पता बिना बीच के तत्वों को गिने सीधे गणितीय सूत्र द्वारा $O(1)$ समय में ज्ञात किया जा सकता है।

2.2 1D ऐरे मेमोरी एड्रेस गणना का सूत्र

यदि ऐरे का बेस एड्रेस $B$ (प्रथम तत्व $A[\text{LB}]$ का पता), निम्न सीमा $\text{LB}$ (C में $\text{LB} = 0$) तथा प्रत्येक तत्व का आकार $W$ बाइट्स हो:

$$\text{Loc}(A[i]) = B + (i - \text{LB}) \times W$$

उदाहरण: यदि int marks[50] का बेस एड्रेस $2000$ है और प्रत्येक पूर्णांक $4$ बाइट्स ($W=4, \text{LB}=0$) लेता है, तो $marks[15]$ का पता होगा:

$$\text{Loc}(marks[15]) = 2000 + (15 - 0) \times 4 = 2000 + 60 = 2060$$

2.3 C भाषा में 1D ऐरे के मुख्य एल्गोरिदम

अल्गोरिदम 1: स्थिति $k$ पर तत्व जोड़ना (Insertion at $k$)

$N$ तत्वों वाले ऐरे में इंडेक्स $k$ पर नया मान जोड़ने के लिए इंडेक्स $N-1$ से $k$ तक के सभी तत्वों को एक स्थान दाईं ओर शिफ्ट करना पड़ता है:

for (int i = N - 1; i >= k; i--) {
    A[i + 1] = A[i]; // दाईं ओर खिसकाना
}
A[k] = new_value;
N++; // कुल संख्या में वृद्धि

टाइम कॉम्प्लेक्सिटी: बेस्ट केस $O(1)$ (अंत में जोड़ने पर), वर्स्ट केस $O(n)$ (प्रारंभ में जोड़ने पर सभी को खिसकाना पड़ता है)।

अल्गोरिदम 2: स्थिति $k$ से तत्व हटाना (Deletion at $k$)

इंडेक्स $k$ से तत्व हटाने के लिए $k+1$ से $N-1$ तक के तत्वों को एक स्थान बाईं ओर शिफ्ट किया जाता है:

for (int i = k; i < N - 1; i++) {
    A[i] = A[i + 1]; // बाईं ओर खिसकाना
}
N--; // कुल संख्या में कमी
2.4 द्वि-विमीय ऐरे (2D Array) एवं मेमोरी क्रमांकन

2D ऐरे $M$ पंक्तियों (Rows) एवं $N$ कॉलमों का आयताकार ग्रिड होता है, जिसे C में int A[M][N] लिखा जाता है। चूंकि कंप्यूटर मेमोरी (RAM) एक-विमीय होती है, कंपाइलर को 2D ग्रिड को दो प्रमुख विधियों में से किसी एक द्वारा रैखिक मेमोरी में बदलना पड़ता है:

  1. रो-मेजर ऑर्डर (Row-Major Order - RMO): तत्व पंक्ति-वार अनुक्रम में संग्रहीत होते हैं। पहले पंक्ति 0 के सभी तत्व, फिर पंक्ति 1, फिर पंक्ति 2 रखी जाती है। C, C++, Java एवं Python इसका उपयोग करते हैं।
  2. कॉलम-मेजर ऑर्डर (Column-Major Order - CMO): तत्व कॉलम-वार संग्रहीत होते हैं। पहले कॉलम 0 के सभी तत्व, फिर कॉलम 1 के तत्व रखे जाते हैं। Fortran एवं MATLAB इसका उपयोग करते हैं।
क्रमबद्धता योजनामेमोरी एड्रेस गणना सूत्रव्याख्या
रो-मेजर ऑर्डर (RMO)$$\text{Loc}(A[i][j]) = B + [(i - \text{LB}_r) \times N + (j - \text{LB}_c)] \times W$$$(i - \text{LB}_r)$ पूर्ण पंक्तियों (प्रत्येक में $N$ कॉलम) को पार करना होता है, तथा वर्तमान पंक्ति के $j$ कॉलम।
कॉलम-मेजर ऑर्डर (CMO)$$\text{Loc}(A[i][j]) = B + [(j - \text{LB}_c) \times M + (i - \text{LB}_r)] \times W$$$(j - \text{LB}_c)$ पूर्ण कॉलमों (प्रत्येक में $M$ पंक्तियां) को पार करना होता है, तथा वर्तमान कॉलम की $i$ पंक्तियां।
स्पार्स मैट्रिक्स (Sparse Matrix): जिस मैट्रिक्स में अधिकांश तत्वों का मान शून्य (0) होता है, उसे स्पार्स मैट्रिक्स कहते हैं। इसे सामान्य 2D ऐरे में रखने से मेमोरी की भारी बर्बादी होती है। वैज्ञानिक प्रणालियों में इसे 3-कॉलम वाली ट्रिपलेट तालिका (Row, Column, Value) के रूप में संग्रहीत किया जाता है।

मॉड्यूल 3: स्टैक आर्किटेक्चर: LIFO मॉडल एवं कॉल स्टैक

3.1 स्टैक का मूल सिद्धांत (LIFO मॉडल)

स्टैक एक रैखिक डेटा संरचना है जो LIFO (Last-In, First-Out) अथवा अंतिम-आगमन प्रथम-निर्गमन सिद्धांत पर कार्य करती है। स्टैक में तत्वों को जोड़ना या निकालना केवल एक ही निर्दिष्ट सिरे से संभव है, जिसे TOP कहा जाता है। विपरीत सिरा बंद रहता है जिसे Base कहा जाता है।

3.2 स्टैक की मूल संक्रियाएं एवं सीमाएं

MAX क्षमता वाले ऐरे आधारित स्टैक में TOP शीर्ष तत्व का इंडेक्स दर्शाता है:

  • प्रारंभिक खाली स्थिति: TOP = -1।
  • PUSH संक्रिया: स्टैक के शीर्ष पर नया तत्व डालना।
    सीमा जांच: यदि TOP == MAX - 1 है, तो नया मान नहीं डाला जा सकता; इसे स्टैक ओवरफ्लो (Stack Overflow) कहते हैं। अन्यथा TOP को 1 बढ़ाकर मान रखा जाता है: Stack[++TOP] = val;।
  • POP संक्रिया: स्टैक के शीर्ष से तत्व को हटाना और प्राप्त करना।
    सीमा जांच: यदि TOP == -1 है, तो कोई तत्व नहीं हटाया जा सकता; इसे स्टैक अंडरफ्लो (Stack Underflow) कहते हैं। अन्यथा मान लौटाकर TOP को 1 घटाया जाता है: val = Stack[TOP--];।
  • PEEK संक्रिया: शीर्ष तत्व को बिना हटाए केवल देखना।
  • isEmpty(): यदि TOP == -1 हो तो सत्य लौटाता है।
  • isFull(): यदि TOP == MAX - 1 हो तो सत्य लौटाता है।
3.3 C भाषा में स्टैक कार्यान्वयन
#include <stdio.h>
#define MAX 5

int stack[MAX];
int top = -1;

void push(int val) {
    if (top == MAX - 1) {
        printf("Stack Overflow!\n");
        return;
    }
    stack[++top] = val;
}

int pop() {
    if (top == -1) {
        printf("Stack Underflow!\n");
        return -1;
    }
    return stack[top--];
}
3.4 स्टैक के प्रमुख अनुप्रयोग
  1. फंक्शन कॉल्स एवं रनटाइम कॉल स्टैक: जब भी कोई फंक्शन कॉल होता है, ऑपरेटिंग सिस्टम एक एक्टिवेशन रिकॉर्ड स्टैक में पुश करता है। रिकर्शन में बेस केस तक नए फ्रेम बनते हैं और वापस लौटते समय वे पॉप होते हैं।
  2. एक्सप्रेशन रूपांतरण (इन्फिक्स, प्रीफिक्स, पोस्टफिक्स): इन्फिक्स व्यंजक को ब्रैकेट-रहित पोस्टफिक्स (Reverse Polish Notation) में बदलने हेतु ऑपरेटर स्टैक प्रयुक्त होता है।
  3. पोस्टफिक्स व्यंजक का मूल्यांकन: ऑपरेंड स्टैक का उपयोग करके एक ही पास में गणितीय व्यंजक हल किया जाता है।
  4. कोष्ठक संतुलन जांच (Parentheses Balancing): कंपाइलर प्रारंभिक कोष्ठक ((, {, [) मिलने पर पुश करता है और समापन कोष्ठक मिलने पर पॉप कर मिलान करता है।
  5. बैकट्रैकिंग: ब्राउज़र में Back बटन, टेक्स्ट एडिटर में Undo/Redo तथा भूलभुलैया (Maze) हल करना।

मॉड्यूल 4: क्यू आर्किटेक्चर: FIFO मॉडल एवं सर्कुलर क्यू

4.1 क्यू का मूल सिद्धांत (FIFO मॉडल)

क्यू एक रैखिक डेटा संरचना है जो FIFO (First-In, First-Out) अर्थात प्रथम-आगमन प्रथम-निर्गमन नियम पर कार्य करती है। क्यू में एक सिरे से तत्व जोड़े जाते हैं जिसे REAR कहते हैं, तथा दूसरे सिरे से तत्व निकाले जाते हैं जिसे FRONT कहते हैं।

4.2 लीनियर क्यू एवं 'फॉल्स ओवरफ्लो' की समस्या

साधारण ऐरे आधारित लीनियर क्यू में तत्व जोड़ने पर REAR बढ़ते-बढ़ते MAX - 1 तक पहुंच जाता है। इसके पश्चात यदि हम कुछ तत्वों को DEQUEUE करके निकाल भी दें, तो आगे के इंडेक्स ($0, 1, 2, \dots$) खाली होने के बावजूद नया तत्व नहीं जोड़ा जा सकता क्योंकि REAR पहले से अंतिम सीमा पर है। इस दोष को फॉल्स ओवरफ्लो (False Overflow) कहा जाता है।

4.3 सर्कुलर क्यू (Circular Queue) समाधान

फॉल्स ओवरफ्लो को समाप्त करने के लिए ऐरे को एक सतत रिंग (चक्र) माना जाता है, जहां इंडेक्स MAX - 1 के बाद अगला इंडेक्स मॉड्यूलो ऑपरेटर (%) द्वारा स्वतः 0 बन जाता है।

सर्कुलर क्यू स्थितिमॉड्यूलो सूत्रविवरण
पॉइंटर वृद्धिindex = (index + 1) % MAXपॉइंटर आगे बढ़ता है; अंतिम छोर पर होने पर पुनः शून्य पर आ जाता है।
क्यू खाली स्थितिFRONT == -1क्यू में वर्तमान में कोई तत्व नहीं है।
क्यू पूर्ण स्थिति(REAR + 1) % MAX == FRONTREAR का अगला स्थान FRONT से टकराएगा।
एकल तत्व विलोपनयदि FRONT == REAR तो FRONT = REAR = -1अंतिम शेष तत्व निकलने पर क्यू पुनः खाली हो जाती है।
4.4 C भाषा में सर्कुलर क्यू कोड
#define MAX 5
int cqueue[MAX];
int front = -1, rear = -1;

void enqueue(int val) {
    if ((rear + 1) % MAX == front) {
        printf("Circular Queue Overflow!\n");
        return;
    }
    if (front == -1) front = 0;
    rear = (rear + 1) % MAX;
    cqueue[rear] = val;
}

int dequeue() {
    if (front == -1) {
        printf("Circular Queue Underflow!\n");
        return -1;
    }
    int val = cqueue[front];
    if (front == rear) front = rear = -1;
    else front = (front + 1) % MAX;
    return val;
}
4.5 क्यू के अन्य प्रकार एवं वास्तविक अनुप्रयोग
  • डबल एंडेड क्यू (Deque): FRONT एवं REAR दोनों छोरों से तत्व जोड़ने और हटाने की सुविधा होती है।
  • प्रायोरिटी क्यू (Priority Queue): तत्वों की प्राथमिकता के आधार पर निष्कासन होता है; उच्चतम प्राथमिकता वाला तत्व पहले निकलता है।
  • वास्तविक अनुप्रयोग: ऑपरेटिंग सिस्टम में राउंड-रॉबिन सीपीयू शेड्यूलिंग, प्रिंटर स्पूलर बफर, कीबोर्ड इनपुट बफर तथा ग्राफ में BFS ट्रैवर्सल।

मॉड्यूल 5: लिंक्ड लिस्ट: डायनेमिक नोड्स एवं पॉइंटर्स

5.1 ऐरे की सीमाएं एवं लिंक्ड लिस्ट की आवश्यकता

ऐरे में त्वरित एक्सेस होने पर भी व्यावहारिक अनुप्रयोगों में इसकी मुख्य तीन कमियां हैं:

  • निश्चित आकार: कंपाइल समय पर तय किया गया आकार रनटाइम पर घटाया या बढ़ाया नहीं जा सकता।
  • सतत मेमोरी की बाध्यता: यदि मेमोरी में पर्याप्त खाली स्थान बिखरा हुआ (Fragmented) है, तब भी बड़ा ऐरे आवंटित नहीं हो सकता।
  • महंगा इंसर्शन और डिलिशन: बीच में या प्रारंभ में तत्व जोड़ने/हटाने हेतु शेष सभी तत्वों को खिसकाना पड़ता है, जिसमें $O(n)$ समय व्यर्थ होता है।
5.2 सिंगली लिंक्ड लिस्ट एवं C स्ट्रक्चर

सिंगली लिंक्ड लिस्ट हीप मेमोरी में स्वतंत्र रूप से बने नोड्स (Nodes) की एक गतिशील श्रृंखला होती है। प्रत्येक नोड में दो भाग होते हैं:

  1. डेटा भाग (Data): वास्तविक सूचना या मान संग्रहीत करता है।
  2. पॉइंटर भाग (Next): श्रृंखला के अगले नोड का मेमोरी पता रखता है।
struct Node {
    int data;              // डेटा मान
    struct Node *next;     // अगले नोड का पॉइंटर
};
struct Node *head = NULL;  // प्रथम नोड को इंगित करता है
5.3 लिंक्ड लिस्ट की मुख्य संक्रियाएं

1. ट्रैवर्सल (Traversal): head से प्रारंभ कर अंतिम नोड के NULL तक सभी नोड्स को क्रम से देखना ($O(n)$ समय)।

2. प्रारंभ में नया नोड जोड़ना (Insertion at Beginning - $O(1)$):

void insertAtBeginning(struct Node **head_ref, int val) {
    struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
    new_node->data = val;
    new_node->next = *head_ref; // नए नोड को वर्तमान हेड से जोड़ना
    *head_ref = new_node;       // हेड को नए नोड पर सेट करना
}

3. प्रथम नोड हटाना (Deletion of First Node - $O(1)$):

void deleteFromBeginning(struct Node **head_ref) {
    if (*head_ref == NULL) return;
    struct Node *temp = *head_ref;
    *head_ref = (*head_ref)->next;
    free(temp); // मेमोरी लीक रोकने के लिए मुक्त किया
}
मेमोरी चेतावनी: malloc() द्वारा ली गई मेमोरी को उपयोग के बाद free() करना आवश्यक है, अन्यथा मेमोरी लीक (Memory Leak) होता है। तथा फ्री करने के बाद उस पॉइंटर को उपयोग करने से डैंगलिंग पॉइंटर (Dangling Pointer) क्रैश होता है।

मॉड्यूल 6: सर्चिंग, सॉर्टिंग एवं तुलनात्मक विश्लेषण

6.1 सर्चिंग एल्गोरिदम: लीनियर बनाम बाइनरी सर्च
  • लीनियर सर्च (Linear Search): सूची के प्रथम तत्व से अंतिम तत्व तक क्रमबद्ध रूप से प्रत्येक तत्व की तुलना की जाती है। यह अव्यवस्थित और व्यवस्थित दोनों ऐरे पर कार्य करता है। टाइम कॉम्प्लेक्सिटी: बेस्ट $O(1)$, वर्स्ट $O(n)$।
  • बाइनरी सर्च (Binary Search): यह डिवाइड एंड कॉन्कर पद्धति पर कार्य करता है। मध्य तत्व mid से तुलना कर प्रत्येक चरण में खोज क्षेत्र को आधा कर देता है। अनिवार्य शर्त: ऐरे का सॉर्ट (Sorted) होना आवश्यक है। टाइम कॉम्प्लेक्सिटी: बेस्ट $O(1)$, वर्स्ट $O(\log_2 n)$। 10 लाख तत्वों में लीनियर सर्च में 10 लाख तुलनाएं लग सकती हैं, जबकि बाइनरी सर्च में अधिकतम केवल 20 तुलनाएं लगती हैं!
6.2 मौलिक सॉर्टिंग एल्गोरिदम
  1. बबल सॉर्ट (Bubble Sort): पास-पास के दो तत्वों की तुलना कर गलत क्रम में होने पर उन्हें आपस में बदलता (Swap) है। प्रत्येक पास में सबसे बड़ा तत्व अंत में पहुंच जाता है। फ्लैग वेरिएबल के साथ सॉर्टेड डेटा पर बेस्ट केस $O(n)$ समय देता है, वर्स्ट केस $O(n^2)$।
  2. सिलेक्शन सॉर्ट (Selection Sort): प्रत्येक पास में अव्यवस्थित भाग में से न्यूनतम तत्व ढूंढकर उसे उस भाग के पहले स्थान से बदलता है। इसमें न्यूनतम स्वैप (अधिकतम $N-1$ या $O(n)$ स्वैप) होते हैं। सभी स्थितियों में समय $O(n^2)$ रहता है।
  3. इंसर्शन सॉर्ट (Insertion Sort): ताश के पत्तों की भांति नए तत्व को पहले से सॉर्ट किए गए भाग में सही स्थान पर प्रविष्ट करता है। लगभग सॉर्ट किए गए डेटा पर अत्यंत तेज ($O(n)$) कार्य करता है।
6.3 समग्र कॉम्प्लेक्सिटी तुलना तालिका
डेटा संरचना / एल्गोरिदमएक्सेससर्चशुरुआत में इंसर्टशुरुआत में डिलीटअतिरिक्त मेमोरी
ऐरे$O(1)$$O(n)$ / $O(\log n)$$O(n)$ (शिफ्ट)$O(n)$ (शिफ्ट)$O(1)$
लिंक्ड लिस्ट$O(n)$$O(n)$$O(1)$$O(1)$प्रति नोड पॉइंटर
स्टैक$O(n)$$O(n)$$O(1)$ (PUSH)$O(1)$ (POP)$O(1)$
सर्कुलर क्यू$O(n)$$O(n)$$O(1)$ (ENQUEUE)$O(1)$ (DEQUEUE)$O(1)$

प्रोग्रामिंग सिंटेक्स, स्टेटमेंट्स एवं भाषा अनुवादक नियम

1D ऐरे मेमोरी एड्रेस गणना सूत्र
$$\text{Loc}(A[i]) = B + (i - \text{LB}) \times W$$
2D ऐरे रो-मेजर ऑर्डर (RMO) सूत्र
$$\text{Loc}(A[i][j]) = B + [(i - \text{LB}_r) \times N + (j - \text{LB}_c)] \times W$$
2D ऐरे कॉलम-मेजर ऑर्डर (CMO) सूत्र
$$\text{Loc}(A[i][j]) = B + [(j - \text{LB}_c) \times M + (i - \text{LB}_r)] \times W$$
स्टैक सीमा शर्तें (LIFO नियम)
$$\text{Overflow: } \text{TOP} = \text{MAX} - 1, \quad \text{Underflow: } \text{TOP} = -1$$
सर्कुलर क्यू मॉड्यूलो रिंग सूत्र
अगला स्थान = (Index + 1) ±od{MAX}, Full: ((REAR + 1) ±od{MAX}) = FRONT
बाइनरी सर्च संबंध एवं टाइम कॉम्प्लेक्सिटी
$$T(n) = T(n/2) + O(1) \implies O(\log_2 n)$$

अवधारणात्मक हल उदाहरण एवं अनुप्रयोग (Solved Examples)

उदाहरण 1
विस्तृत समाधान / उत्तर:
भाग क: 1D ऐरे मेमोरी पते की गणना
दिए गए मान:
• बेस एड्रेस $B = 1500$
• निम्न सीमा $\text{LB} = 0$, अभीष्ट इंडेक्स $i = 18$
• तत्व का आकार $W = 4$ बाइट्स

1D सूत्र:
$$\text{Loc}(A[i]) = B + (i - \text{LB}) \times W$$
$$\text{Loc}(A[18]) = 1500 + (18 - 0) \times 4 = 1500 + 72 = \mathbf{1572}$$

भाग ख: 2D मैट्रिक्स मेमोरी पते की गणना
दिए गए मान:
• बेस एड्रेस $B = 4000$
• पंक्तियां: $M = 10$ (पंक्ति $1 \dots 10$, अतः $\text{LB}_r = 1$)
• कॉलम: $N = 15$ (कॉलम $1 \dots 15$, अतः $\text{LB}_c = 1$)
• अभीष्ट इंडेक्स: $i = 6, j = 8$, तत्व का आकार $W = 4$ बाइट्स

(1) रो-मेजर ऑर्डर (RMO) सूत्र:
$$\text{Loc}(\text{MAT}[i][j]) = B + [(i - \text{LB}_r) \times N + (j - \text{LB}_c)] \times W$$
मान रखने पर:
$$\text{Loc}(\text{MAT}[6][8]) = 4000 + [(6 - 1) \times 15 + (8 - 1)] \times 4$$
$$= 4000 + [5 \times 15 + 7] \times 4 = 4000 + [75 + 7] \times 4 = 4000 + 82 \times 4 = 4000 + 328 = \mathbf{4328}$$

(2) कॉलम-मेजर ऑर्डर (CMO) सूत्र:
$$\text{Loc}(\text{MAT}[i][j]) = B + [(j - \text{LB}_c) \times M + (i - \text{LB}_r)] \times W$$
मान रखने पर:
$$\text{Loc}(\text{MAT}[6][8]) = 4000 + [(8 - 1) \times 10 + (6 - 1)] \times 4$$
$$= 4000 + [7 \times 10 + 5] \times 4 = 4000 + [70 + 5] \times 4 = 4000 + 75 \times 4 = 4000 + 300 = \mathbf{4300}$$
उत्तर: RMO में पता 4328 तथा CMO में पता 4300 है।
उदाहरण 2
विस्तृत समाधान / उत्तर:
प्राथमिकता नियम: ^ (सर्वोच्च 3) > *, / (2) > +, - (1)।

चरणस्कैन प्रतीकस्टैक स्थितिआउटपुट स्ट्रिंगलागू नियम
1((प्रारंभिक कोष्ठक पुश
2A(Aऑपरेंड सीधे आउटपुट में
3+( +Aऑपरेटर स्टैक में पुश
4B( +A Bऑपरेंड आउटपुट में जुड़ा
5*( + *A B* की प्राथमिकता + से अधिक, पुश
6C( + *A B Cऑपरेंड आउटपुट में जुड़ा
7)A B C * +) मिला: ( तक सभी ऑपरेटर पॉप
8//A B C * +ऑपरेटर खाली स्टैक में पुश
9(/ (A B C * +प्रारंभिक कोष्ठक पुश
10D/ (A B C * + Dऑपरेंड आउटपुट में जुड़ा
11-/ ( -A B C * + Dऑपरेटर स्टैक में पुश
12E/ ( -A B C * + D Eऑपरेंड आउटपुट में जुड़ा
13^/ ( - ^A B C * + D E^ की प्राथमिकता अधिक, पुश
14F/ ( - ^A B C * + D E Fऑपरेंड आउटपुट में जुड़ा
15)/A B C * + D E F ^ -पॉप ^ तथा -, ( निरस्त
16अंत[खाली]A B C * + D E F ^ - /शेष ऑपरेटर / पॉप किया

अंतिम पोस्टफिक्स व्यंजक: A B C * + D E F ^ - /
उदाहरण 3
विस्तृत समाधान / उत्तर:
मूल्यांकन विधि: संख्या मिलने पर स्टैक में पुश करें; ऑपरेटर मिलने पर शीर्ष की दो संख्याएं पॉप कर गणना करें व परिणाम पुनः पुश करें।

टोकनप्रकारपॉप मान ($op_1, op_2$)गणनास्टैक स्थिति
12ऑपरेंड--[12]
4ऑपरेंड--[12, 4]
/ऑपरेटर$op_2=4, op_1=12$$12 / 4 = 3$[3]
5ऑपरेंड--[3, 5]
3ऑपरेंड--[3, 5, 3]
*ऑपरेटर$op_2=3, op_1=5$$5 \times 3 = 15$[3, 15]
+ऑपरेटर$op_2=15, op_1=3$$3 + 15 = 18$[18]
8ऑपरेंड--[18, 8]
2ऑपरेंड--[18, 8, 2]
/ऑपरेटर$op_2=2, op_1=8$$8 / 2 = 4$[18, 4]
-ऑपरेटर$op_2=4, op_1=18$$18 - 4 = 14$[14]

अंतिम परिणाम: 14
उदाहरण 4
विस्तृत समाधान / उत्तर:
सर्कुलर क्यू स्थिति संक्रमण तालिका (MAX = 4):

क्रमसंक्रियाFRONTREARऐरे स्थिति: [0], [1], [2], [3]विवरण / मॉड्यूलो सूत्र
0प्रारंभिक-1-1[ - , - , - , - ]क्यू खाली है।
1Enqueue(10)00[ 10 , - , - , - ]खाली क्यू: front=0, rear=(0+1)%4=0।
2Enqueue(20)01[ 10 , 20 , - , - ]rear = (0+1)%4 = 1। मान 20 रखा गया।
3Enqueue(30)02[ 10 , 20 , 30 , - ]rear = (1+1)%4 = 2। मान 30 रखा गया।
4Dequeue()12[ - , 20 , 30 , - ]10 निकला; front = (0+1)%4 = 1। स्थान 0 खाली।
5Enqueue(40)13[ - , 20 , 30 , 40 ]rear = (2+1)%4 = 3। मान 40 रखा गया।
6Enqueue(50)10[ 50 , 20 , 30 , 40 ]rear घूमकर शून्य पर आया: (3+1)%4 = 0! खाली स्लॉट 0 भरा। क्यू पूर्ण।
7Dequeue()20[ 50 , - , 30 , 40 ]20 निकला; front = (1+1)%4 = 2। स्थान 1 खाली।
8Enqueue(60)21[ 50 , 60 , 30 , 40 ]rear = (0+1)%4 = 1। स्लॉट 1 पर 60 रखा गया।

निष्कर्ष: लीनियर क्यू में चरण 6 पर फॉल्स ओवरफ्लो हो जाता, परंतु सर्कुलर क्यू ने रिक्त स्थान को कुशलतापूर्वक पुनः उपयोग किया।
उदाहरण 5
विस्तृत समाधान / उत्तर:
(क) प्रारंभ में [5] नोड जोड़ना:
1. malloc द्वारा मेमोरी आवंटन: struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
2. डेटा प्रविष्टि: new_node->data = 5;
3. पॉइंटर जोड़ना: new_node->next = head; (नया नोड [10] को इंगित करता है)
4. हेड अपडेट: head = new_node;
• सूची: HEAD -> [5 | *] -> [10 | *] -> [25 | *] -> [40 | NULL] (समय: $O(1)$)

(ख) मान 25 वाला नोड हटाना:
1. दो पॉइंटर्स curr एवं prev द्वारा सूची को स्कैन कर नोड [25] को खोजा जाता है।
2. पूर्ववर्ती नोड का पॉइंटर अगले नोड से जोड़ना: prev->next = curr->next; ([10] का पॉइंटर सीधे [40] से जुड़ता है)।
3. मेमोरी मुक्त करना: free(curr); (मेमोरी लीक रोकने के लिए)
• अंतिम सूची: HEAD -> [5 | *] -> [10 | *] -> [40 | NULL]।
उदाहरण 6
विस्तृत समाधान / उत्तर:
प्रारंभिक ऐरे: [45, 12, 89, 34, 23], लंबाई $N = 5$।

(1) बबल सॉर्ट ट्रेस:
• पास 1: 45>12 (स्वैप 1) → [12, 45, 89, 34, 23]; 45<89 (स्वैप नहीं); 89>34 (स्वैप 2) → [12, 45, 34, 89, 23]; 89>23 (स्वैप 3) → [12, 45, 34, 23, 89]।
• पास 2: 12<45 (स्वैप नहीं); 45>34 (स्वैप 4) → [12, 34, 45, 23, 89]; 45>23 (स्वैप 5) → [12, 34, 23, 45, 89]।
• पास 3: 12<34 (स्वैप नहीं); 34>23 (स्वैप 6) → [12, 23, 34, 45, 89]।
• पास 4: कोई स्वैप नहीं → समाप्त।
बबल सॉर्ट में कुल स्वैप = 6 बार।

(2) सिलेक्शन सॉर्ट ट्रेस:
• पास 1: [45, 12, 89, 34, 23] में न्यूनतम 12। A[0](45) व A[1](12) स्वैप → [12, 45, 89, 34, 23] (स्वैप 1)।
• पास 2: शेष भाग में न्यूनतम 23। A[1](45) व A[4](23) स्वैप → [12, 23, 89, 34, 45] (स्वैप 2)।
• पास 3: शेष भाग में न्यूनतम 34। A[2](89) व A[3](34) स्वैप → [12, 23, 34, 89, 45] (स्वैप 3)।
• पास 4: शेष भाग में न्यूनतम 45। A[3](89) व A[4](45) स्वैप → [12, 23, 34, 45, 89] (स्वैप 4)।
सिलेक्शन सॉर्ट में कुल स्वैप = 4 बार।

विश्लेषण: दोनों का समय $O(n^2)$ होने पर भी सिलेक्शन सॉर्ट में स्वैप न्यूनतम ($N-1$) होते हैं, जो फ्लैश मेमोरी के लिए अधिक उपयुक्त है।

सामान्य गलतियाँ एवं परीक्षक के जाल (Examiner Traps)

सामान्य भ्रम / गलत उत्तर

सर्कुलर क्यू में पूर्ण स्थिति की जांच के लिए 'front == rear' लिखना।

सही वैज्ञानिक तथ्य

सर्कुलर क्यू में 'front == rear' यह दर्शाता है कि क्यू में केवल एक तत्व बचा है। सही पूर्ण स्थिति '(rear + 1) % MAX == front' होती है।

सामान्य भ्रम / गलत उत्तर

अव्यवस्थित (Unsorted) ऐरे पर बाइनरी सर्च चलाना।

सही वैज्ञानिक तथ्य

बाइनरी सर्च केवल सॉर्टेड डेटा पर ही काम करता है। अव्यवस्थित ऐरे पर चलाने से गलत परिणाम आते हैं। पहले डेटा को सॉर्ट करें या लीनियर सर्च अपनाएं।

सामान्य भ्रम / गलत उत्तर

लिंक्ड लिस्ट में नोड जोड़ते समय पूर्ववर्ती लिंक तोड़ देना।

सही वैज्ञानिक तथ्य

नया नोड जोड़ते समय पहले नए नोड के next को हेड से जोड़ें ('new_node->next = head;'), उसके बाद 'head = new_node;' करें। उल्टा करने पर शेष सूची खो जाती है।

सामान्य भ्रम / गलत उत्तर

C भाषा की मेमोरी एड्रेस गणना में रो-मेजर के स्थान पर कॉलम-मेजर का सूत्र लगाना।

सही वैज्ञानिक तथ्य

C भाषा सदैव रो-मेजर ऑर्डर अपनाती है, जिसमें पंक्ति के अंतर को कुल कॉलम संख्या (N) से गुणा किया जाता है: Base + [(i - LBr) * N + (j - LBc)] * W।

सामान्य भ्रम / गलत उत्तर

स्टैक से POP करने से पूर्व अंडरफ्लो (top == -1) की जांच न करना।

सही वैज्ञानिक तथ्य

top == -1 होने पर pop करने से Stack[-1] एक्सेस होकर मेमोरी करप्शन या सेगमेंटेशन फॉल्ट हो जाता है। सदैव isEmpty() की जांच करें।

अध्याय का सार संक्षेप एवं 10 मुख्य निष्कर्ष

मुख्य बिंदु 1
डेटा संरचनाएं मेमोरी में डेटा को सुव्यवस्थित कर एल्गोरिदम की कार्यक्षमता को अधिकतम करती हैं। लीनियर संरचनाएं (ऐरे, स्टैक, क्यू, लिंक्ड लिस्ट) अनुक्रमिक क्रम में डेटा रखती हैं तथा नॉन-लीनियर संरचनाएं (ट्री, ग्राफ) पदानुक्रमित व बहु-मार्ग संबंध बनाती हैं। ऐरे सतत मेमोरी मैपिंग द्वारा O(1) सीधा एक्सेस प्रदान करता है, जो C में रो-मेजर ऑर्डर का पालन करता है। स्टैक LIFO सिद्धांत से रिकर्शन व एक्सप्रेशन मूल्यांकन को नियंत्रित करता है। क्यू FIFO सिद्धांत पर कार्य करती है, जिसमें सर्कुलर क्यू मॉड्यूलो गणित से फॉल्स ओवरफ्लो समाप्त करती है। सिंगली लिंक्ड लिस्ट सेल्फ-रेफरेंशियल नोड्स द्वारा डायनेमिक मेमोरी का प्रबंधन करती है। सर्चिंग में लीनियर सर्च (O(n)) व बाइनरी सर्च (O(log n)) तथा सॉर्टिंग में बबल, सिलेक्शन व इंसर्शन सॉर्ट महत्वपूर्ण हैं।

स्व-मूल्यांकन अभ्यास (Check Your Understanding)

मूल वैचारिक स्पष्टता की जांच के लिए नैदानिक प्रश्न। पहले स्वयं हल करें, फिर उत्तर देखें।

1
ऐरे को स्टैटिक तथा लिंक्ड लिस्ट को डायनेमिक डेटा संरचना क्यों कहा जाता है? मेमोरी आवंटन के आधार पर समझाइए।
उत्तर एवं व्याख्या देखें
उत्तर: ऐरे का मेमोरी आकार कंपाइल समय पर निश्चित घोषित करना होता है। प्रोग्राम निष्पादन (रनटाइम) के दौरान इसका आकार घटाया या बढ़ाया नहीं जा सकता। आवश्यकता न होने पर भी अतिरिक्त मेमोरी व्यर्थ घिरी रहती है; अतः ऐरे स्टैटिक है। इसके विपरीत, लिंक्ड लिस्ट के लिए पहले से कोई निश्चित आकार तय नहीं किया जाता। रनटाइम पर जब भी नए डेटा की आवश्यकता होती है, malloc() द्वारा हीप मेमोरी से स्वतंत्र नोड लिया जाता है और काम समाप्त होने पर free() द्वारा तुरंत मुक्त किया जा सकता है। आवश्यकतानुसार घटने-बढ़ने के कारण लिंक्ड लिस्ट डायनेमिक है।
2
लीनियर क्यू में 'फॉल्स ओवरफ्लो' क्या है? सर्कुलर क्यू गणितीय रूप से इसे कैसे हल करती है?
उत्तर एवं व्याख्या देखें
उत्तर: लीनियर क्यू में तत्व जोड़ते-जोड़ते जब REAR सूचकांक अंतिम सीमा MAX - 1 पर पहुंच जाता है, तब यदि DEQUEUE द्वारा आगे के कुछ तत्व हटा भी दिए जाएं, तब भी रिक्त स्थान उपलब्ध होने के बावजूद नया तत्व नहीं जोड़ा जा सकता और क्यू ओवरफ्लो बताती है। इसे फॉल्स ओवरफ्लो कहते हैं। सर्कुलर क्यू मॉड्यूलो अंकगणित द्वारा इसका समाधान करती है: rear = (rear + 1) % MAX। जब rear अंतिम छोर पर पहुंचता है, तो (MAX - 1 + 1) % MAX = 0 होकर पॉइंटर स्वतः शून्य इंडेक्स पर मुड़ जाता है और खाली स्लॉट्स को सफलतापूर्वक भर लेता है।
3
इन्फिक्स, प्रीफिक्स एवं पोस्टफिक्स व्यंजकों में क्या अंतर है? कंप्यूटर मूल्यांकन हेतु पोस्टफिक्स को प्राथमिकता क्यों दी जाती है?
उत्तर एवं व्याख्या देखें
उत्तर: इन्फिक्स में ऑपरेटर ऑपरेंड्स के बीच में होता है (A + B)। प्रीफिक्स में ऑपरेटर पहले होता है (+ A B)। पोस्टफिक्स में ऑपरेटर बाद में होता है (A B +)। कंप्यूटर पोस्टफिक्स व्यंजक को इसलिए प्राथमिकता देता है क्योंकि: (1) इसमें किसी कोष्ठक की आवश्यकता नहीं होती, (2) मूल्यांकन के दौरान ऑपरेटरों की प्राथमिकता व साहचर्य (Precedence and Associativity) के नियमों को याद नहीं रखना पड़ता, तथा (3) एक साधारण ऑपरेंड स्टैक द्वारा बाएं से दाएं एक ही पास में $O(n)$ समय में इसका मान निकाला जा सकता है।
4
बबल सॉर्ट किस परिस्थिति में O(n) बेस्ट-केस टाइम कॉम्प्लेक्सिटी प्राप्त करता है? एल्गोरिदम में क्या संशोधन आवश्यक है?
उत्तर एवं व्याख्या देखें
उत्तर: सामान्य बबल सॉर्ट में नेस्टेड लूप के कारण सदैव O(n^2) समय लगता है। किंतु प्रत्येक पास से पूर्व एक बूलियन फ्लैग (जैसे swapped = 0;) लगाकर यदि देखा जाए कि प्रथम पास में दो आसन्न तत्वों के बीच एक भी स्वैप नहीं हुआ, तो सिद्ध होता है कि ऐरे पहले से पूरी तरह सॉर्टेड है। इस स्थिति में एल्गोरिदम तुरंत लूप को ब्रेक कर समाप्त हो जाता है। अतः केवल 1 पास (n - 1 तुलनाएं) में काम पूरा हो जाता है और O(n) रैखिक समय प्राप्त हो जाता है।
5
C भाषा में डायनेमिक मेमोरी प्रबंधन के दो प्रमुख खतरे कौन से हैं? प्रोग्रामर इनसे कैसे बच सकता है?
उत्तर एवं व्याख्या देखें
उत्तर: दो प्रमुख खतरे हैं: (1) मेमोरी लीक (Memory Leak): malloc() द्वारा ली गई मेमोरी को free() किए बिना पॉइंटर बदल देने से वह मेमोरी स्थायी रूप से घिर जाती है। निवारण: काम समाप्त होते ही free(ptr) का प्रयोग करें। (2) डैंगलिंग पॉइंटर (Dangling Pointer): मेमोरी को free() करने के पश्चात भी पॉइंटर यदि पुराने पते को रखता है और उसे पुनः उपयोग किया जाए तो सिस्टम क्रैश हो सकता है। निवारण: मेमोरी मुक्त करने के तुरंत बाद पॉइंटर को NULL सेट करें: free(ptr); ptr = NULL;।
अध्याय का अध्ययन पूर्ण हुआ?
अभ्यास के लिए तैयार?

ऑनलाइन CBT टेस्ट देकर तैयारी का मूल्यांकन करें

झारखण्ड बोर्ड परीक्षा पैटर्न पर आधारित बहुविकल्पीय प्रश्नों का ऑनलाइन टेस्ट दें। तुरंत परिणाम, समय विश्लेषण और प्रत्येक प्रश्न का विस्तृत हल प्राप्त करें।