Կլոնավորեք Երկուական ծառ Պատահական ցուցիչներով


Դժվարության մակարդակ Դժվար
Հաճախակի հարցնում են Ակոլիտ Amazon Cisco Փաստեր Ֆանատիկա Google Microsoft Օպերա Snapchat
Խանգարել ծառ

Խնդիրի հայտարարություն

Ձեզ տրվում է ամբողջական երկուական ծառ որոշ պատահական ցուցիչների հետ: Պատահական ցուցիչները վերաբերում են այն հանգույցներին, որոնց յուրաքանչյուր հանգույց մատնանշում է իր ձախ և աջ երեխայից բացի: Այսպիսով, սա նաև փոխում է պարզ երկուական ծառի հանգույցի ստանդարտ կառուցվածքը: Այժմ երկուական ծառի հանգույցը տվյալները կպահի ընթացիկ հանգույցում և ցուցչում ձախից, աջից և պատահական ցուցիչից: Այսպիսով, հիմա մենք լավն ենք գնալու այն բանի հետ, թե ի՞նչ է հարցն անգամ հարցնում: «Կլոնավորեք երկուական ծառ պատահական ցուցիչներով» խնդիրը պահանջում է ստեղծել նոր երկուական ծառ, որը տվյալ նախնական ծառի ճշգրիտ պատճենն է: Այսպիսով, նոր ստեղծված ծառի մեջ, եթե մենք ընտրում ենք մի հանգույց, դրա ձախ, աջ և պատահական ցուցիչը վերաբերում է այս նոր ծառի այն հանգույցներին, որոնք համապատասխանում են սկզբնական ծառի հանգույցներին:

Օրինակ

Մուտքային

Կլոնավորեք Երկուական ծառ Պատահական ցուցիչներով

Inorder traversal of original binary tree is [current node data, random pointer data]:
[1 2], [2 7], [3 9], [5 1], [7 1], [9 5],

Inorder traversal of cloned binary tree is[current node data, random pointer data]:
[1 2], [2 7], [3 9], [5 1], [7 1], [9 5],

բացատրություն

Երկուական ծառի ձախ և աջ հանգույցները ցուցադրվում են, ինչպես միշտ, յուրաքանչյուր հանգույցի ձախ և աջ կողմում: Եվ մնացած ցուցիչները, ձախ և աջ ցուցիչները պատահական ցուցիչներ են: Որոշ եզրեր ունեն կրկնակի սլաքներ (դա ուղղված է երկու ուղղություններով): Հանգույցի ծնողներից որևէ մեկի ուղղությունը նշանակում է, որ այդ հանգույցն ունի պատահական ցուցիչ ծնողի համար: Արդյունքը տրվում է [ընթացիկ հանգույցի տվյալներ / պատահական հանգույցների տվյալներ] ձևաչափով:

Խարդախության մոտեցում

Այսպիսով, քանի որ գիտենք, որ մենք պետք է ստեղծենք նոր ծառ, որը նախնական ծառի ճշգրիտ պատճենն է: Մենք կարող ենք գործարկել անշարժ շրջագիծ և կառուցել դրա կրկնօրինակը: Բայց մենք պատահական ցուցիչների հետ խնդիրներ կունենանք, քանի որ որոշ հանգույցներ կարող են ցույց տալ այն հանգույցները, որոնք դեռ կառուցված չեն: Այսպիսով, այս սխալից ազատվելու համար: Մենք նախ կկառուցենք նոր ծառ: Դրանից հետո օգտագործեք ա HashMap որը պահպանում է սկզբնական ծառի յուրաքանչյուր հանգույցին համապատասխանող նոր հանգույցի հասցեն: Այսպիսով, մեկ անգամ ևս մենք կատարում ենք անկարգությունների անցում և կատարում պատահական ցուցիչները դեպի նոր ծառի հանգույցները (որոնք պահվում են որպես արժեքներ HashMap- ում):

Արդյունավետ մոտեցում

Վերը նշված մոտեցման մեջ մենք պետք է պահեինք ա HashMap որը պահում էր յուրօրինակ ծառի յուրաքանչյուր հանգույցին համապատասխանող կլոնային հանգույցի հասցեն: Այսպիսով, դա անելու փոխարեն, մենք կանենք մի բան, ինչպես արվել է կլոնավորելու համար a կապված ցուցակը պատահական ցուցիչներով: Մենք կխթանենք նորաստեղծ հանգույցները ձախ երեխայի և բուն ծառի համապատասխան հանգույցի միջև: Այսպիսով, մինչ այժմ մենք փոխել ենք նախնական ծառի կառուցվածքը: Պատահական ցուցիչներ տեղադրելու համար մենք գիտենք, որ հանգույցին համապատասխանող նոր հանգույցը միշտ մնում է իր ձախ երեխան: Այսպիսով, մենք պարզապես պատահական ցուցիչը դնում ենք մուտքային ծառի հանգույցի ձախ երեխային: Բայց մենք դեռ մեկ բան ունենք հոգալու: Մենք պետք է վերականգնենք նախնական և կլոնային ծառի հանգույցների ձախ երեխային: Դա անելուց հետո մենք կլոնավորել ենք երկուական ծառ ՝ պատահական միավորողներով:

Կոդ

C ++ կոդ ՝ Պատահական ցուցիչներով Երկուական ծառ կլոնավորելու համար

#include <iostream>
using namespace std;

struct node{
    int data;
  node *left, *right, *random;
};

node* create(int data){
  node* tmp = new node();
  tmp->data = data;
  tmp->left = tmp->right = tmp->random = NULL;
}

// print inorder traversal of the given tree in [node, random node] format
void inorder(node* root)
{
  if(root == NULL)
    return;
  // print inorder traversal of left tree
  inorder(root->left);
  // print in [current node, random node] format
  cout << "[" << root->data << " ";
  if (root->random == NULL)
    cout << "NULL], ";
  else
    cout << root->random->data << "], ";
  // print inorder traversal of right tree
  inorder(root->right);
}

// insert clone nodes between the original node and its left child
node* insertCloneNode(node* originalNode)
{
  if (originalNode == NULL)
    return NULL;

  node* left = originalNode->left;
  originalNode->left = create(originalNode->data);
  originalNode->left->left = left;
  if(left != NULL)
    left->left = insertCloneNode(left);

  originalNode->left->right = insertCloneNode(originalNode->right);
  return originalNode->left;
}

// sets the random pointers in clone tree
void setRandomNode(node* originalNode, node* cloneNode)
{
  if (originalNode == NULL)
    return;
  if(originalNode->random != NULL)
    cloneNode->random = originalNode->random->left;
  else
    cloneNode->random = NULL;

  if(originalNode->left != NULL && cloneNode->left != NULL)
    setRandomNode(originalNode->left->left, cloneNode->left->left);
  setRandomNode(originalNode->right, cloneNode->right);
}

// after all the work restore the left pointers in original and clone tree
void restoreTreeLeftNode(node* originalNode, node* cloneNode)
{
  if (originalNode == NULL)
    return;
  if (cloneNode->left != NULL)
  {
    node* cloneLeft = cloneNode->left->left;
    originalNode->left = originalNode->left->left;
    cloneNode->left = cloneLeft;
  }
  else
    originalNode->left = NULL;

  restoreTreeLeftNode(originalNode->left, cloneNode->left);
  restoreTreeLeftNode(originalNode->right, cloneNode->right);
}

// constructs the new clone tree
node* cloneTree(node* originalNode)
{
  if (originalNode == NULL)
    return NULL;
  node* cloneNode = insertCloneNode(originalNode);
  setRandomNode(originalNode, cloneNode);
  restoreTreeLeftNode(originalNode, cloneNode);
  return cloneNode;
}


int main()
{
  node *root = create(3);
  node* two = create(2);
  node* one = create(1);
  node* seven = create(7);
  node* five = create(5);
  node* nine = create(9);

  root->left = two;
  root->left->left = one;
  root->right = seven;
  root->right->left = five;
  root->right ->right = nine;

  root->random = nine;
  root->left->random = seven;
  root->left->left->random = two;
  root->right->random = one;
  root->right->left->random = one;
  root->right->right->random = five;

  cout << "Inorder traversal of original binary tree is [current node data, random pointer data]: \n";
  inorder(root);

  node *clone = cloneTree(root);

  cout << "\n\nInorder traversal of cloned binary tree is[current node data, random pointer data]: \n";
  inorder(clone);

  return 0;
}
Inorder traversal of original binary tree is [current node data, random pointer data]:
[1 2], [2 7], [3 9], [5 1], [7 1], [9 5],

Inorder traversal of cloned binary tree is[current node data, random pointer data]:
[1 2], [2 7], [3 9], [5 1], [7 1], [9 5],

Java կոդ ՝ Պատահական ցուցիչներով Երկուական ծառ կլոնավորելու համար

import java.util.*;
// Class that denotes a node of the tree
class node
{ 
    int data; 
    node left, right, random; 
 
    public node(int data) 
    { 
        this.data = data;
        left = right = random = null; 
    } 
}
 
class Tree 
{ 
    static node root;
  static node create(int data) {
    node tmp = new node(data);
    return tmp;
  }
  // print inorder traversal of the given tree in [node, random node] format
  static void inorder(node root){
    if(root != null){
      // print inorder traversal of left tree
      inorder(root.left);
      // print in [current node, random node] format
      System.out.print("[" + root.data + " ");
      if(root.random == null)
        System.out.print("null], ");
      else
        System.out.print(root.random.data +"], ");
      // print inorder traversal of right tree
      inorder(root.right);
    }
  }
 
  // insert clone nodes between the original node and its left child
  static node insertCloneNode(node originalNode) 
  { 
    if (originalNode == null) 
      return null; 
 
    node left = originalNode.left; 
    originalNode.left = create(originalNode.data); 
    originalNode.left.left = left; 
    if(left != null) 
      left.left = insertCloneNode(left); 
 
    originalNode.left.right = insertCloneNode(originalNode.right); 
    return originalNode.left; 
  } 
 
  // sets the random pointers in clone tree
  static void setRandomNode(node originalNode, node cloneNode) 
  { 
    if (originalNode != null){
      if(originalNode.random != null) 
        cloneNode.random = originalNode.random.left; 
      else
        cloneNode.random = null; 
 
      if(originalNode.left != null && cloneNode.left != null) 
        setRandomNode(originalNode.left.left, cloneNode.left.left); 
      setRandomNode(originalNode.right, cloneNode.right); 
    }
  } 
 
  // after all the work restore the left pointers in original and clone tree
  static void restoreTreeLeftNode(node originalNode, node cloneNode) 
  { 
    if (originalNode != null) {
      if (cloneNode.left != null) 
      { 
        node cloneLeft = cloneNode.left.left; 
        originalNode.left = originalNode.left.left; 
        cloneNode.left = cloneLeft; 
      } 
      else
        originalNode.left = null; 
 
      restoreTreeLeftNode(originalNode.left, cloneNode.left); 
      restoreTreeLeftNode(originalNode.right, cloneNode.right); 
    }
  } 
 
  // constructs the new clone tree
  static node cloneTree(node originalNode) 
  { 
    if (originalNode == null)
      return null;
    node cloneNode = insertCloneNode(originalNode); 
    setRandomNode(originalNode, cloneNode); 
    restoreTreeLeftNode(originalNode, cloneNode); 
    return cloneNode; 
  } 
 
  public static void main(String[] args) {
    node root = create(3);
    node two = create(2);
    node one = create(1);
    node seven = create(7);
    node five = create(5);
    node nine = create(9);
 
    root.left = two;
    root.left.left = one;
    root.right = seven;
    root.right.left = five;
    root.right .right = nine;
 
    root.random = nine;
    root.left.random = seven;
    root.left.left.random = two;
    root.right.random = one;
    root.right.left.random = one;
    root.right.right.random = five;
 
    System.out.print("Inorder traversal of original binary tree is[current node data, random pointer data]: \n");
    inorder(root);
 
    node clone = cloneTree(root);
 
    System.out.print("\n\nInorder traversal of cloned binary tree is[current node data, random pointer data]: \n");
    inorder(clone);
  }
}
Inorder traversal of original binary tree is[current node data, random pointer data]: 
[1 2], [2 7], [3 9], [5 1], [7 1], [9 5], 

Inorder traversal of cloned binary tree is[current node data, random pointer data]: 
[1 2], [2 7], [3 9], [5 1], [7 1], [9 5],

Պատահական ցուցիչներով Երկուական ծառ կլոնավորելու բարդության վերլուծություն

Timeամանակի բարդություն 

ՎՐԱ), մենք պարզապես անցել ենք երկուական ծառի հանգույցները, և քանի որ երկուական ծառի մեջ կան N հանգույցներ: Այսպիսով, ժամանակի բարդությունը գծային է:

Տիեզերական բարդություն

O (1), քանի որ մենք ոչ մի տեղեկություն չենք պահել զանգվածում կամ քարտեզում: Այսպիսով, տարածության բարդությունը կայուն է: