தமிழ்

பைனரி தேடல் மரங்களின் (BSTs) அடிப்படைகளை ஆராய்ந்து, அவற்றை ஜாவாஸ்கிரிப்டில் திறமையாக செயல்படுத்துவது எப்படி என்பதை அறிக. இந்த வழிகாட்டி BST அமைப்பு, செயல்பாடுகள் மற்றும் உலகெங்கிலும் உள்ள டெவலப்பர்களுக்கான நடைமுறை எடுத்துக்காட்டுகளை உள்ளடக்கியது.

பைனரி தேடல் மரங்கள்: ஜாவாஸ்கிரிப்டில் ஒரு விரிவான செயல்படுத்தல் வழிகாட்டி

பைனரி தேடல் மரங்கள் (BSTs) கணினி அறிவியலில் ஒரு அடிப்படை தரவுக் கட்டமைப்பாகும், இது தரவுகளை திறமையாக தேட, வரிசைப்படுத்த மற்றும் மீட்டெடுக்க பரவலாக பயன்படுத்தப்படுகிறது. அவற்றின் படிநிலை அமைப்பு பல செயல்பாடுகளில் மடக்கை நேர சிக்கலை (logarithmic time complexity) அனுமதிக்கிறது, இது பெரிய தரவுத்தொகுப்புகளை நிர்வகிக்க ஒரு சக்திவாய்ந்த கருவியாக அமைகிறது. இந்த வழிகாட்டி BST-களின் விரிவான கண்ணோட்டத்தை வழங்குகிறது மற்றும் ஜாவாஸ்கிரிப்டில் அவற்றின் செயலாக்கத்தை நிரூபிக்கிறது, இது உலகெங்கிலும் உள்ள டெவலப்பர்களுக்கு ஏற்றது.

பைனரி தேடல் மரங்களைப் புரிந்துகொள்ளுதல்

பைனரி தேடல் மரம் என்றால் என்ன?

பைனரி தேடல் மரம் என்பது மரம் சார்ந்த தரவுக் கட்டமைப்பாகும், இதில் ஒவ்வொரு கணுவிற்கும் (node) அதிகபட்சம் இரண்டு குழந்தைகள் இருக்கும், அவை இடது குழந்தை மற்றும் வலது குழந்தை என்று குறிப்பிடப்படுகின்றன. ஒரு BST-யின் முக்கிய பண்பு என்னவென்றால், எந்தவொரு குறிப்பிட்ட கணுவிற்கும்:

இந்த பண்பு ஒரு BST-இல் உள்ள கூறுகள் எப்போதும் வரிசைப்படுத்தப்பட்டிருப்பதை உறுதிசெய்கிறது, இது திறமையான தேடல் மற்றும் மீட்டெடுப்பை செயல்படுத்துகிறது.

முக்கிய கருத்துக்கள்

ஜாவாஸ்கிரிப்டில் ஒரு பைனரி தேடல் மரத்தை செயல்படுத்துதல்

கணு வகுப்பை (Node Class) வரையறுத்தல்

முதலில், BST-இல் உள்ள ஒவ்வொரு கணுவையும் குறிக்க `Node` என்ற வகுப்பை வரையறுக்கிறோம். ஒவ்வொரு கணுவும் தரவைச் சேமிக்க ஒரு `key` மற்றும் அதன் குழந்தைகளுக்கான `left` மற்றும் `right` சுட்டிகளைக் கொண்டிருக்கும்.


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

பைனரி தேடல் மரம் வகுப்பை (Binary Search Tree Class) வரையறுத்தல்

அடுத்து, `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 {
    // key is equal to 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

மரம் கடத்தல் (Tree Traversal)

மரம் கடத்தல் என்பது மரத்தில் உள்ள ஒவ்வொரு கணுவையும் ஒரு குறிப்பிட்ட வரிசையில் சென்று பார்ப்பதாகும். பல பொதுவான கடத்தல் முறைகள் உள்ளன:


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 செருகல், தேடல் மற்றும் நீக்குதல் செயல்பாடுகளுக்கு மடக்கை நேர சிக்கலை அனுமதிக்கிறது. இருப்பினும், மோசமான நிலையில் (எ.கா., ஒரு சாய்ந்த மரம்), நேர சிக்கல் நேரியல் நேரத்திற்கு (linear time) குறையக்கூடும்.

சமநிலையான மற்றும் சமநிலையற்ற மரங்கள்

ஒரு சமநிலையான BST என்பது ஒவ்வொரு கணுவின் இடது மற்றும் வலது துணை மரங்களின் உயரம் அதிகபட்சம் ஒன்றால் வேறுபடும் ஒரு மரம் ஆகும். AVL மரங்கள் மற்றும் சிவப்பு-கருப்பு மரங்கள் போன்ற சுய-சமநிலைப்படுத்தும் வழிமுறைகள், மரம் சமநிலையாக இருப்பதை உறுதிசெய்து, நிலையான செயல்திறனை வழங்குகின்றன. வெவ்வேறு பிராந்தியங்களுக்கு சேவையகத்தின் சுமையைப் பொறுத்து வெவ்வேறு தேர்வுமுறை நிலைகள் தேவைப்படலாம்; சமநிலைப்படுத்துதல் அதிக உலகளாவிய பயன்பாட்டின் கீழ் செயல்திறனை பராமரிக்க உதவுகிறது.

நேர சிக்கல் (Time Complexity)

மேம்பட்ட BST கருத்துக்கள்

சுய-சமநிலைப்படுத்தும் மரங்கள்

சுய-சமநிலைப்படுத்தும் மரங்கள் என்பவை சமநிலையை பராமரிக்க தங்கள் கட்டமைப்பை தானாக சரிசெய்யும் BST-கள் ஆகும். இது மரத்தின் உயரம் மடக்கையாக இருப்பதை உறுதிசெய்கிறது, அனைத்து செயல்பாடுகளுக்கும் நிலையான செயல்திறனை வழங்குகிறது. பொதுவான சுய-சமநிலைப்படுத்தும் மரங்கள் AVL மரங்கள் மற்றும் சிவப்பு-கருப்பு மரங்கள் ஆகியவை அடங்கும்.

AVL மரங்கள்

AVL மரங்கள் எந்தவொரு கணுவின் இடது மற்றும் வலது துணை மரங்களுக்கு இடையிலான உயர வேறுபாடு அதிகபட்சம் ஒன்று என்பதை உறுதி செய்வதன் மூலம் சமநிலையை பராமரிக்கின்றன. இந்த சமநிலை சீர்குலைந்தால், சமநிலையை மீட்டெடுக்க சுழற்சிகள் (rotations) செய்யப்படுகின்றன.

சிவப்பு-கருப்பு மரங்கள்

சிவப்பு-கருப்பு மரங்கள் சமநிலையை பராமரிக்க வண்ணப் பண்புகளை (சிவப்பு அல்லது கருப்பு) பயன்படுத்துகின்றன. அவை 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

      // நிலை 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));

முடிவுரை

பைனரி தேடல் மரங்கள் எண்ணற்ற பயன்பாடுகளைக் கொண்ட ஒரு சக்திவாய்ந்த மற்றும் பல்துறை தரவுக் கட்டமைப்பாகும். இந்த வழிகாட்டி BST-களின் விரிவான கண்ணோட்டத்தை வழங்கியுள்ளது, அவற்றின் கட்டமைப்பு, செயல்பாடுகள் மற்றும் ஜாவாஸ்கிரிப்டில் செயல்படுத்தல் ஆகியவற்றை உள்ளடக்கியது. இந்த வழிகாட்டியில் விவாதிக்கப்பட்ட கொள்கைகள் மற்றும் நுட்பங்களைப் புரிந்துகொள்வதன் மூலம், உலகெங்கிலும் உள்ள டெவலப்பர்கள் மென்பொருள் மேம்பாட்டில் பல்வேறு வகையான சிக்கல்களைத் தீர்க்க BST-களை திறம்பட பயன்படுத்தலாம். உலகளாவிய தரவுத்தளங்களை நிர்வகிப்பது முதல் தேடல் வழிமுறைகளை மேம்படுத்துவது வரை, BST-களின் அறிவு எந்தவொரு புரோகிராமருக்கும் ஒரு விலைமதிப்பற்ற சொத்தாகும்.

கணினி அறிவியலில் உங்கள் பயணத்தைத் தொடரும்போது, சுய-சமநிலைப்படுத்தும் மரங்கள் போன்ற மேம்பட்ட கருத்துக்களையும் அவற்றின் பல்வேறு செயலாக்கங்களையும் ஆராய்வது உங்கள் புரிதலையும் திறன்களையும் மேலும் மேம்படுத்தும். பைனரி தேடல் மரங்களை திறம்பட பயன்படுத்தும் கலையில் தேர்ச்சி பெற வெவ்வேறு சூழ்நிலைகளில் பயிற்சி மற்றும் பரிசோதனை செய்து கொண்டே இருங்கள்.