తెలుగు

బైనరీ సెర్చ్ ట్రీస్ (BSTs) యొక్క ప్రాథమికాలను అన్వేషించండి మరియు వాటిని జావాస్క్రిప్ట్‌లో సమర్థవంతంగా ఎలా అమలు చేయాలో తెలుసుకోండి. ఈ గైడ్ BST నిర్మాణం, కార్యకలాపాలు మరియు ప్రపంచవ్యాప్త డెవలపర్‌ల కోసం ఆచరణాత్మక ఉదాహరణలను వివరిస్తుంది.

బైనరీ సెర్చ్ ట్రీస్: జావాస్క్రిప్ట్‌లో ఒక సమగ్ర ఇంప్లిమెంటేషన్ గైడ్

బైనరీ సెర్చ్ ట్రీస్ (BSTs) కంప్యూటర్ సైన్స్‌లో ఒక ప్రాథమిక డేటా స్ట్రక్చర్, డేటాను సమర్థవంతంగా శోధించడానికి, క్రమబద్ధీకరించడానికి మరియు తిరిగి పొందడానికి విస్తృతంగా ఉపయోగించబడతాయి. వాటి క్రమానుగత నిర్మాణం చాలా కార్యకలాపాలలో లాగరిథమిక్ టైమ్ కాంప్లెక్సిటీని అనుమతిస్తుంది, ఇది పెద్ద డేటాసెట్‌లను నిర్వహించడానికి వాటిని ఒక శక్తివంతమైన సాధనంగా చేస్తుంది. ఈ గైడ్ BSTల యొక్క సమగ్ర అవలోకనాన్ని అందిస్తుంది మరియు ప్రపంచవ్యాప్తంగా ఉన్న డెవలపర్‌ల కోసం జావాస్క్రిప్ట్‌లో వాటి అమలును ప్రదర్శిస్తుంది.

బైనరీ సెర్చ్ ట్రీస్‌ను అర్థం చేసుకోవడం

బైనరీ సెర్చ్ ట్రీ అంటే ఏమిటి?

బైనరీ సెర్చ్ ట్రీ అనేది ఒక ట్రీ-ఆధారిత డేటా స్ట్రక్చర్, ఇక్కడ ప్రతి నోడ్‌కు గరిష్టంగా రెండు పిల్లలు ఉంటారు, వాటిని లెఫ్ట్ చైల్డ్ మరియు రైట్ చైల్డ్ అని పిలుస్తారు. 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;
  }

  // మెథడ్స్ ఇక్కడ జోడించబడతాయి
}

ఇన్సర్షన్ (జోడించడం)

`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);

సెర్చింగ్ (వెతకడం)

`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

డిలీషన్ (తొలగించడం)

`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 {
    // key అనేది node.key కు సమానం

    // కేస్ 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 ఇన్సర్షన్, సెర్చ్ మరియు డిలీషన్ కార్యకలాపాల కోసం లాగరిథమిక్ టైమ్ కాంప్లెక్సిటీని అనుమతిస్తుంది. అయితే, చెత్త సందర్భంలో (ఉదా., ఒక వక్ర ట్రీ), టైమ్ కాంప్లెక్సిటీ లీనియర్ టైమ్‌కు క్షీణించవచ్చు.

సమతుల్య vs. అసమతుల్య ట్రీస్

ఒక సమతుల్య BST అంటే ప్రతి నోడ్ యొక్క ఎడమ మరియు కుడి సబ్‌ట్రీల ఎత్తు గరిష్టంగా ఒకటి తేడాతో ఉంటుంది. AVL ట్రీస్ మరియు రెడ్-బ్లాక్ ట్రీస్ వంటి స్వీయ-సమతుల్య అల్గారిథమ్‌లు, ట్రీ సమతుల్యంగా ఉండేలా చూస్తాయి, స్థిరమైన పనితీరును అందిస్తాయి. సర్వర్‌పై లోడ్ ఆధారంగా వివిధ ప్రాంతాలకు విభిన్న ఆప్టిమైజేషన్ స్థాయిలు అవసరం కావచ్చు; సమతుల్యం చేయడం అధిక ప్రపంచ వినియోగం కింద పనితీరును నిర్వహించడానికి సహాయపడుతుంది.

టైమ్ కాంప్లెక్సిటీ

అధునాతన BST భావనలు

స్వీయ-సమతుల్య ట్రీస్

స్వీయ-సమతుల్య ట్రీస్ అంటే సమతుల్యాన్ని కాపాడుకోవడానికి వాటి నిర్మాణాన్ని స్వయంచాలకంగా సర్దుబాటు చేసుకునే BSTలు. ఇది ట్రీ యొక్క ఎత్తు లాగరిథమిక్‌గా ఉండేలా చేస్తుంది, అన్ని కార్యకలాపాలకు స్థిరమైన పనితీరును అందిస్తుంది. సాధారణ స్వీయ-సమతుల్య ట్రీస్‌లో AVL ట్రీస్ మరియు రెడ్-బ్లాక్ ట్రీస్ ఉన్నాయి.

AVL ట్రీస్

AVL ట్రీస్ ఏ నోడ్ యొక్క ఎడమ మరియు కుడి సబ్‌ట్రీల మధ్య ఎత్తు వ్యత్యాసం గరిష్టంగా ఒకటి ఉండేలా చూసుకోవడం ద్వారా సమతుల్యాన్ని నిర్వహిస్తాయి. ఈ సమతుల్యం దెబ్బతిన్నప్పుడు, సమతుల్యాన్ని పునరుద్ధరించడానికి రొటేషన్లు చేయబడతాయి.

రెడ్-బ్లాక్ ట్రీస్

రెడ్-బ్లాక్ ట్రీస్ సమతుల్యాన్ని నిర్వహించడానికి రంగు లక్షణాలను (ఎరుపు లేదా నలుపు) ఉపయోగిస్తాయి. అవి AVL ట్రీస్ కంటే సంక్లిష్టంగా ఉంటాయి కానీ కొన్ని సందర్భాల్లో మెరుగైన పనితీరును అందిస్తాయి.

జావాస్క్రిప్ట్ కోడ్ ఉదాహరణ: పూర్తి బైనరీ సెర్చ్ ట్రీ ఇంప్లిమెంటేషన్


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 {
      // key is equal to node.key

      // case 1 - a leaf node
      if (node.left === null && node.right === null) {
        node = null;
        return node;
      }

      // case 2 - node has only 1 child
      if (node.left === null) {
        node = node.right;
        return node;
      } else if (node.right === null) {
        node = node.left;
        return node;
      }

      // case 3 - node has 2 children
      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));

ముగింపు

బైనరీ సెర్చ్ ట్రీస్ అనేవి అనేక అనువర్తనాలతో కూడిన ఒక శక్తివంతమైన మరియు బహుముఖ డేటా స్ట్రక్చర్. ఈ గైడ్ BSTల యొక్క నిర్మాణం, కార్యకలాపాలు మరియు జావాస్క్రిప్ట్‌లో వాటి అమలును కవర్ చేస్తూ సమగ్ర అవలోకనాన్ని అందించింది. ఈ గైడ్‌లో చర్చించిన సూత్రాలు మరియు పద్ధతులను అర్థం చేసుకోవడం ద్వారా, ప్రపంచవ్యాప్తంగా ఉన్న డెవలపర్లు సాఫ్ట్‌వేర్ డెవలప్‌మెంట్‌లో అనేక రకాల సమస్యలను పరిష్కరించడానికి BSTలను సమర్థవంతంగా ఉపయోగించుకోవచ్చు. ప్రపంచ డేటాబేస్‌లను నిర్వహించడం నుండి సెర్చ్ అల్గారిథమ్‌లను ఆప్టిమైజ్ చేయడం వరకు, BSTల పరిజ్ఞానం ఏ ప్రోగ్రామర్‌కైనా ఒక అమూల్యమైన ఆస్తి.

మీరు కంప్యూటర్ సైన్స్‌లో మీ ప్రయాణాన్ని కొనసాగిస్తున్నప్పుడు, స్వీయ-సమతుల్య ట్రీస్ వంటి అధునాతన భావనలను మరియు వాటి వివిధ అమలులను అన్వేషించడం మీ అవగాహనను మరియు సామర్థ్యాలను మరింత పెంచుతుంది. బైనరీ సెర్చ్ ట్రీస్‌ను సమర్థవంతంగా ఉపయోగించే కళలో నైపుణ్యం సాధించడానికి వివిధ దృశ్యాలతో ప్రాక్టీస్ చేస్తూ మరియు ప్రయోగాలు చేస్తూ ఉండండి.