బైనరీ సెర్చ్ ట్రీస్ (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 లక్షణాన్ని నిర్వహించాల్సి ఉంటుంది. పరిగణించవలసిన మూడు కేసులు ఉన్నాయి:
- కేస్ 1: తొలగించాల్సిన నోడ్ ఒక లీఫ్ నోడ్. దానిని కేవలం తీసివేయండి.
- కేస్ 2: తొలగించాల్సిన నోడ్కు ఒకే చైల్డ్ ఉంది. నోడ్ను దాని చైల్డ్తో భర్తీ చేయండి.
- కేస్ 3: తొలగించాల్సిన నోడ్కు ఇద్దరు పిల్లలు ఉన్నారు. ఇన్-ఆర్డర్ సక్సెసర్ను (కుడి సబ్ట్రీలోని అతి చిన్న నోడ్) కనుగొని, నోడ్ను సక్సెసర్తో భర్తీ చేసి, ఆపై సక్సెసర్ను తొలగించండి.
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
బైనరీ సెర్చ్ ట్రీస్ యొక్క ఆచరణాత్మక అనువర్తనాలు
బైనరీ సెర్చ్ ట్రీస్ వివిధ రకాల అనువర్తనాలలో ఉపయోగించబడతాయి, వాటిలో:
- డేటాబేస్లు: డేటాను ఇండెక్స్ చేయడం మరియు శోధించడం. ఉదాహరణకు, అనేక డేటాబేస్ సిస్టమ్లు రికార్డులను సమర్థవంతంగా గుర్తించడానికి B-ట్రీస్ వంటి BSTల యొక్క వైవిధ్యాలను ఉపయోగిస్తాయి. బహుళ జాతీయ సంస్థలు ఉపయోగించే డేటాబేస్ల ప్రపంచ స్థాయిని పరిగణించండి; సమర్థవంతమైన డేటా పునరుద్ధరణ చాలా ముఖ్యం.
- కంపైలర్లు: సింబల్ టేబుల్స్, ఇవి వేరియబుల్స్ మరియు ఫంక్షన్ల గురించి సమాచారాన్ని నిల్వ చేస్తాయి.
- ఆపరేటింగ్ సిస్టమ్స్: ప్రాసెస్ షెడ్యూలింగ్ మరియు మెమరీ మేనేజ్మెంట్.
- సెర్చ్ ఇంజన్లు: వెబ్ పేజీలను ఇండెక్స్ చేయడం మరియు శోధన ఫలితాలను ర్యాంక్ చేయడం.
- ఫైల్ సిస్టమ్స్: ఫైళ్ళను నిర్వహించడం మరియు యాక్సెస్ చేయడం. వెబ్సైట్లను హోస్ట్ చేయడానికి ప్రపంచవ్యాప్తంగా ఉపయోగించే సర్వర్లోని ఫైల్ సిస్టమ్ను ఊహించుకోండి; చక్కగా వ్యవస్థీకరించబడిన BST-ఆధారిత నిర్మాణం కంటెంట్ను వేగంగా అందించడంలో సహాయపడుతుంది.
పనితీరు పరిగణనలు
ఒక BST యొక్క పనితీరు దాని నిర్మాణంపై ఆధారపడి ఉంటుంది. ఉత్తమ సందర్భంలో, ఒక సమతుల్య BST ఇన్సర్షన్, సెర్చ్ మరియు డిలీషన్ కార్యకలాపాల కోసం లాగరిథమిక్ టైమ్ కాంప్లెక్సిటీని అనుమతిస్తుంది. అయితే, చెత్త సందర్భంలో (ఉదా., ఒక వక్ర ట్రీ), టైమ్ కాంప్లెక్సిటీ లీనియర్ టైమ్కు క్షీణించవచ్చు.
సమతుల్య vs. అసమతుల్య ట్రీస్
ఒక సమతుల్య BST అంటే ప్రతి నోడ్ యొక్క ఎడమ మరియు కుడి సబ్ట్రీల ఎత్తు గరిష్టంగా ఒకటి తేడాతో ఉంటుంది. AVL ట్రీస్ మరియు రెడ్-బ్లాక్ ట్రీస్ వంటి స్వీయ-సమతుల్య అల్గారిథమ్లు, ట్రీ సమతుల్యంగా ఉండేలా చూస్తాయి, స్థిరమైన పనితీరును అందిస్తాయి. సర్వర్పై లోడ్ ఆధారంగా వివిధ ప్రాంతాలకు విభిన్న ఆప్టిమైజేషన్ స్థాయిలు అవసరం కావచ్చు; సమతుల్యం చేయడం అధిక ప్రపంచ వినియోగం కింద పనితీరును నిర్వహించడానికి సహాయపడుతుంది.
టైమ్ కాంప్లెక్సిటీ
- ఇన్సర్షన్: సగటున O(log n), చెత్త సందర్భంలో O(n).
- సెర్చ్: సగటున O(log n), చెత్త సందర్భంలో O(n).
- డిలీషన్: సగటున O(log n), చెత్త సందర్భంలో O(n).
- ట్రావర్సల్: O(n), ఇక్కడ n అనేది ట్రీలోని నోడ్ల సంఖ్య.
అధునాతన 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ల పరిజ్ఞానం ఏ ప్రోగ్రామర్కైనా ఒక అమూల్యమైన ఆస్తి.
మీరు కంప్యూటర్ సైన్స్లో మీ ప్రయాణాన్ని కొనసాగిస్తున్నప్పుడు, స్వీయ-సమతుల్య ట్రీస్ వంటి అధునాతన భావనలను మరియు వాటి వివిధ అమలులను అన్వేషించడం మీ అవగాహనను మరియు సామర్థ్యాలను మరింత పెంచుతుంది. బైనరీ సెర్చ్ ట్రీస్ను సమర్థవంతంగా ఉపయోగించే కళలో నైపుణ్యం సాధించడానికి వివిధ దృశ్యాలతో ప్రాక్టీస్ చేస్తూ మరియు ప్రయోగాలు చేస్తూ ఉండండి.