हिन्दी

बाइनरी सर्च ट्री (BST) के मूल सिद्धांतों को समझें और जावास्क्रिप्ट में उन्हें कुशलता से लागू करना सीखें। यह गाइड BST संरचना, संचालन और दुनिया भर के डेवलपर्स के लिए व्यावहारिक उदाहरणों को कवर करती है।

बाइनरी सर्च ट्री: जावास्क्रिप्ट में एक विस्तृत कार्यान्वयन गाइड

बाइनरी सर्च ट्री (BSTs) कंप्यूटर विज्ञान में एक मौलिक डेटा संरचना है, जिसका उपयोग डेटा की कुशल खोज, सॉर्टिंग और पुनर्प्राप्ति के लिए व्यापक रूप से किया जाता है। इनकी पदानुक्रमित संरचना कई ऑपरेशनों में लॉगरिदमिक समय जटिलता की अनुमति देती है, जिससे वे बड़े डेटासेट को प्रबंधित करने के लिए एक शक्तिशाली उपकरण बन जाते हैं। यह गाइड BSTs का एक व्यापक अवलोकन प्रदान करती है और दुनिया भर के डेवलपर्स के लिए जावास्क्रिप्ट में उनके कार्यान्वयन को प्रदर्शित करती है।

बाइनरी सर्च ट्री को समझना

बाइनरी सर्च ट्री क्या है?

एक बाइनरी सर्च ट्री एक ट्री-आधारित डेटा संरचना है जहां प्रत्येक नोड में अधिकतम दो बच्चे होते हैं, जिन्हें बायां बच्चा और दायां बच्चा कहा जाता है। BST की मुख्य विशेषता यह है कि किसी भी दिए गए नोड के लिए:

यह गुण सुनिश्चित करता है कि BST में तत्व हमेशा क्रमबद्ध रहते हैं, जिससे कुशल खोज और पुनर्प्राप्ति संभव होती है।

मुख्य अवधारणाएं

जावास्क्रिप्ट में बाइनरी सर्च ट्री को लागू करना

नोड क्लास को परिभाषित करना

सबसे पहले, हम BST में प्रत्येक नोड का प्रतिनिधित्व करने के लिए एक `Node` क्लास को परिभाषित करते हैं। प्रत्येक नोड में डेटा स्टोर करने के लिए एक `key` और उसके बच्चों के लिए `left` और `right` पॉइंटर्स होंगे।


class Node {
  constructor(key) {
    this.key = key;
    this.left = null;
    this.right = null;
  }
}

बाइनरी सर्च ट्री क्लास को परिभाषित करना

इसके बाद, हम `BinarySearchTree` क्लास को परिभाषित करते हैं। इस क्लास में रूट नोड और ट्री में इंसर्ट, सर्च, डिलीट और ट्रैवर्स करने के लिए मेथड्स होंगे।


class BinarySearchTree {
  constructor() {
    this.root = null;
  }

  // मेथड्स यहाँ जोड़े जाएंगे
}

इंसर्शन (Insertion)

`insert` मेथड दिए गए की के साथ एक नया नोड BST में जोड़ता है। इंसर्शन प्रक्रिया मौजूदा नोड्स के सापेक्ष नए नोड को उचित स्थिति में रखकर BST की प्रॉपर्टी को बनाए रखती है।


insert(key) {
  const newNode = new Node(key);

  if (this.root === null) {
    this.root = newNode;
  } else {
    this.insertNode(this.root, newNode);
  }
}

insertNode(node, newNode) {
  if (newNode.key < node.key) {
    if (node.left === null) {
      node.left = newNode;
    } else {
      this.insertNode(node.left, newNode);
    }
  } else {
    if (node.right === null) {
      node.right = newNode;
    } else {
      this.insertNode(node.right, newNode);
    }
  }
}

उदाहरण: BST में मान डालना


const bst = new BinarySearchTree();
bst.insert(11);
bst.insert(7);
bst.insert(15);
bst.insert(5);
bst.insert(3);
bst.insert(9);
bst.insert(8);
bst.insert(10);
bst.insert(13);
bst.insert(12);
bst.insert(14);
bst.insert(20);
bst.insert(18);
bst.insert(25);

सर्चिंग (Searching)

`search` मेथड जांचता है कि दी गई की वाला कोई नोड BST में मौजूद है या नहीं। यह ट्री को ट्रैवर्स करता है, की की तुलना वर्तमान नोड की की से करता है और तदनुसार बाएं या दाएं सबट्री में जाता है।


search(key) {
  return this.searchNode(this.root, key);
}

searchNode(node, key) {
  if (node === null) {
    return false;
  }

  if (key < node.key) {
    return this.searchNode(node.left, key);
  } else if (key > node.key) {
    return this.searchNode(node.right, key);
  } else {
    return true;
  }
}

उदाहरण: BST में एक मान खोजना


console.log(bst.search(9));  // आउटपुट: true
console.log(bst.search(2));  // आउटपुट: false

डिलीशन (Deletion)

`remove` मेथड दी गई की वाले नोड को BST से हटाता है। यह सबसे जटिल ऑपरेशन है क्योंकि इसे नोड को हटाते समय BST की प्रॉपर्टी को बनाए रखना होता है। विचार करने के लिए तीन मामले हैं:


remove(key) {
  this.root = this.removeNode(this.root, key);
}

removeNode(node, key) {
  if (node === null) {
    return null;
  }

  if (key < node.key) {
    node.left = this.removeNode(node.left, key);
    return node;
  } else if (key > node.key) {
    node.right = this.removeNode(node.right, key);
    return node;
  } else {
    // की, नोड.की के बराबर है

    // केस 1 - एक लीफ नोड
    if (node.left === null && node.right === null) {
      node = null;
      return node;
    }

    // केस 2 - नोड का केवल 1 बच्चा है
    if (node.left === null) {
      node = node.right;
      return node;
    } else if (node.right === null) {
      node = node.left;
      return node;
    }

    // केस 3 - नोड के 2 बच्चे हैं
    const aux = this.findMinNode(node.right);
    node.key = aux.key;
    node.right = this.removeNode(node.right, aux.key);
    return node;
  }
}

findMinNode(node) {
  let current = node;
  while (current != null && current.left != null) {
    current = current.left;
  }
  return current;
}

उदाहरण: BST से एक मान हटाना


bst.remove(7);
console.log(bst.search(7)); // आउटपुट: false

ट्री ट्रैवर्सल

ट्री ट्रैवर्सल में ट्री के प्रत्येक नोड पर एक विशिष्ट क्रम में जाना शामिल है। कई सामान्य ट्रैवर्सल विधियाँ हैं:


inOrderTraverse(callback) {
  this.inOrderTraverseNode(this.root, callback);
}

inOrderTraverseNode(node, callback) {
  if (node !== null) {
    this.inOrderTraverseNode(node.left, callback);
    callback(node.key);
    this.inOrderTraverseNode(node.right, callback);
  }
}

preOrderTraverse(callback) {
  this.preOrderTraverseNode(this.root, callback);
}

preOrderTraverseNode(node, callback) {
  if (node !== null) {
    callback(node.key);
    this.preOrderTraverseNode(node.left, callback);
    this.preOrderTraverseNode(node.right, callback);
  }
}

postOrderTraverse(callback) {
  this.postOrderTraverseNode(this.root, callback);
}

postOrderTraverseNode(node, callback) {
  if (node !== null) {
    this.postOrderTraverseNode(node.left, callback);
    this.postOrderTraverseNode(node.right, callback);
    callback(node.key);
  }
}

उदाहरण: BST को ट्रैवर्स करना


const printNode = (value) => console.log(value);

bst.inOrderTraverse(printNode);   // आउटपुट: 3 5 8 9 10 11 12 13 14 15 18 20 25
bst.preOrderTraverse(printNode);  // आउटपुट: 11 5 3 9 8 10 15 13 12 14 20 18 25
bst.postOrderTraverse(printNode); // आउटपुट: 3 8 10 9 12 14 13 18 25 20 15 11

न्यूनतम और अधिकतम मान

BST में न्यूनतम और अधिकतम मान खोजना इसकी क्रमबद्ध प्रकृति के कारण सीधा है।


min() {
  return this.minNode(this.root);
}

minNode(node) {
  let current = node;
  while (current !== null && current.left !== null) {
    current = current.left;
  }
  return current;
}

max() {
  return this.maxNode(this.root);
}

maxNode(node) {
  let current = node;
  while (current !== null && current.right !== null) {
    current = current.right;
  }
  return current;
}

उदाहरण: न्यूनतम और अधिकतम मान खोजना


console.log(bst.min().key); // आउटपुट: 3
console.log(bst.max().key); // आउटपुट: 25

बाइनरी सर्च ट्री के व्यावहारिक अनुप्रयोग

बाइनरी सर्च ट्री का उपयोग विभिन्न प्रकार के अनुप्रयोगों में किया जाता है, जिनमें शामिल हैं:

प्रदर्शन संबंधी विचार

BST का प्रदर्शन उसकी संरचना पर निर्भर करता है। सबसे अच्छे परिदृश्य में, एक संतुलित BST इंसर्शन, सर्च और डिलीशन ऑपरेशंस के लिए लॉगरिदमिक समय जटिलता की अनुमति देता है। हालांकि, सबसे खराब स्थिति में (उदाहरण के लिए, एक तिरछा ट्री), समय जटिलता रैखिक समय तक गिर सकती है।

संतुलित बनाम असंतुलित ट्री

एक संतुलित BST वह है जहां किसी भी नोड के बाएं और दाएं सबट्री की ऊंचाई में अधिकतम एक का अंतर होता है। स्व-संतुलन एल्गोरिदम, जैसे कि एवीएल ट्री और रेड-ब्लैक ट्री, यह सुनिश्चित करते हैं कि ट्री संतुलित बना रहे, जिससे लगातार प्रदर्शन मिलता है। सर्वर पर लोड के आधार पर विभिन्न क्षेत्रों में विभिन्न अनुकूलन स्तरों की आवश्यकता हो सकती है; संतुलन उच्च वैश्विक उपयोग के तहत प्रदर्शन बनाए रखने में मदद करता है।

समय जटिलता

उन्नत BST अवधारणाएं

स्व-संतुलन ट्री

स्व-संतुलन ट्री ऐसे BSTs हैं जो संतुलन बनाए रखने के लिए अपनी संरचना को स्वचालित रूप से समायोजित करते हैं। यह सुनिश्चित करता है कि ट्री की ऊंचाई लॉगरिदमिक बनी रहे, जिससे सभी ऑपरेशनों के लिए लगातार प्रदर्शन मिलता है। सामान्य स्व-संतुलन ट्री में एवीएल ट्री और रेड-ब्लैक ट्री शामिल हैं।

एवीएल ट्री (AVL Trees)

एवीएल ट्री यह सुनिश्चित करके संतुलन बनाए रखते हैं कि किसी भी नोड के बाएं और दाएं सबट्री के बीच ऊंचाई का अंतर अधिकतम एक हो। जब यह संतुलन बाधित होता है, तो संतुलन बहाल करने के लिए रोटेशन किए जाते हैं।

रेड-ब्लैक ट्री (Red-Black Trees)

रेड-ब्लैक ट्री संतुलन बनाए रखने के लिए रंग गुणों (लाल या काला) का उपयोग करते हैं। वे एवीएल ट्री की तुलना में अधिक जटिल हैं लेकिन कुछ परिदृश्यों में बेहतर प्रदर्शन प्रदान करते हैं।

जावास्क्रिप्ट कोड उदाहरण: संपूर्ण बाइनरी सर्च ट्री कार्यान्वयन


class Node {
  constructor(key) {
    this.key = key;
    this.left = null;
    this.right = null;
  }
}

class BinarySearchTree {
  constructor() {
    this.root = null;
  }

  insert(key) {
    const newNode = new Node(key);

    if (this.root === null) {
      this.root = newNode;
    } else {
      this.insertNode(this.root, newNode);
    }
  }

  insertNode(node, newNode) {
    if (newNode.key < node.key) {
      if (node.left === null) {
        node.left = newNode;
      } else {
        this.insertNode(node.left, newNode);
      }
    } else {
      if (node.right === null) {
        node.right = newNode;
      } else {
        this.insertNode(node.right, newNode);
      }
    }
  }

  search(key) {
    return this.searchNode(this.root, key);
  }

  searchNode(node, key) {
    if (node === null) {
      return false;
    }

    if (key < node.key) {
      return this.searchNode(node.left, key);
    } else if (key > node.key) {
      return this.searchNode(node.right, key);
    } else {
      return true;
    }
  }

  remove(key) {
    this.root = this.removeNode(this.root, key);
  }

  removeNode(node, key) {
    if (node === null) {
      return null;
    }

    if (key < node.key) {
      node.left = this.removeNode(node.left, key);
      return node;
    } else if (key > node.key) {
      node.right = this.removeNode(node.right, key);
      return node;
    } else {
      // की, नोड.की के बराबर है

      // केस 1 - एक लीफ नोड
      if (node.left === null && node.right === null) {
        node = null;
        return node;
      }

      // केस 2 - नोड का केवल 1 बच्चा है
      if (node.left === null) {
        node = node.right;
        return node;
      } else if (node.right === null) {
        node = node.left;
        return node;
      }

      // केस 3 - नोड के 2 बच्चे हैं
      const aux = this.findMinNode(node.right);
      node.key = aux.key;
      node.right = this.removeNode(node.right, aux.key);
      return node;
    }
  }

  findMinNode(node) {
    let current = node;
    while (current != null && current.left != null) {
      current = current.left;
    }
    return current;
  }

  min() {
    return this.minNode(this.root);
  }

  minNode(node) {
    let current = node;
    while (current !== null && current.left !== null) {
      current = current.left;
    }
    return current;
  }

  max() {
    return this.maxNode(this.root);
  }

  maxNode(node) {
    let current = node;
    while (current !== null && current.right !== null) {
      current = current.right;
    }
    return current;
  }

  inOrderTraverse(callback) {
    this.inOrderTraverseNode(this.root, callback);
  }

  inOrderTraverseNode(node, callback) {
    if (node !== null) {
      this.inOrderTraverseNode(node.left, callback);
      callback(node.key);
      this.inOrderTraverseNode(node.right, callback);
    }
  }

  preOrderTraverse(callback) {
    this.preOrderTraverseNode(this.root, callback);
  }

  preOrderTraverseNode(node, callback) {
    if (node !== null) {
      callback(node.key);
      this.preOrderTraverseNode(node.left, callback);
      this.preOrderTraverseNode(node.right, callback);
    }
  }

  postOrderTraverse(callback) {
    this.postOrderTraverseNode(this.root, callback);
  }

  postOrderTraverseNode(node, callback) {
    if (node !== null) {
      this.postOrderTraverseNode(node.left, callback);
      this.postOrderTraverseNode(node.right, callback);
      callback(node.key);
    }
  }
}

// उदाहरण उपयोग
const bst = new BinarySearchTree();
bst.insert(11);
bst.insert(7);
bst.insert(15);
bst.insert(5);
bst.insert(3);
bst.insert(9);
bst.insert(8);
bst.insert(10);
bst.insert(13);
bst.insert(12);
bst.insert(14);
bst.insert(20);
bst.insert(18);
bst.insert(25);

const printNode = (value) => console.log(value);

console.log("इन-ऑर्डर ट्रैवर्सल:");
bst.inOrderTraverse(printNode);

console.log("प्री-ऑर्डर ट्रैवर्सल:");
bst.preOrderTraverse(printNode);

console.log("पोस्ट-ऑर्डर ट्रैवर्सल:");
bst.postOrderTraverse(printNode);

console.log("न्यूनतम मान:", bst.min().key);
console.log("अधिकतम मान:", bst.max().key);

console.log("9 के लिए खोजें:", bst.search(9));
console.log("2 के लिए खोजें:", bst.search(2));

bst.remove(7);
console.log("7 को हटाने के बाद खोजें:", bst.search(7));

निष्कर्ष

बाइनरी सर्च ट्री एक शक्तिशाली और बहुमुखी डेटा संरचना है जिसके कई अनुप्रयोग हैं। इस गाइड ने BSTs का एक व्यापक अवलोकन प्रदान किया है, जिसमें उनकी संरचना, संचालन और जावास्क्रिप्ट में कार्यान्वयन शामिल है। इस गाइड में चर्चा किए गए सिद्धांतों और तकनीकों को समझकर, दुनिया भर के डेवलपर्स सॉफ्टवेयर विकास में समस्याओं की एक विस्तृत श्रृंखला को हल करने के लिए प्रभावी ढंग से BSTs का उपयोग कर सकते हैं। वैश्विक डेटाबेस के प्रबंधन से लेकर खोज एल्गोरिदम को अनुकूलित करने तक, BSTs का ज्ञान किसी भी प्रोग्रामर के लिए एक अमूल्य संपत्ति है।

जैसे-जैसे आप कंप्यूटर विज्ञान में अपनी यात्रा जारी रखते हैं, स्व-संतुलन ट्री और उनके विभिन्न कार्यान्वयनों जैसी उन्नत अवधारणाओं की खोज आपकी समझ और क्षमताओं को और बढ़ाएगी। बाइनरी सर्च ट्री का प्रभावी ढंग से उपयोग करने की कला में महारत हासिल करने के लिए विभिन्न परिदृश्यों के साथ अभ्यास और प्रयोग करते रहें।