Open In App

Locking and Unlocking of Resources arranged in the form of n-ary Tree

Last Updated : 23 Jul, 2025
Comments
Improve
Suggest changes
30 Likes
Like
Report

Given an n-ary tree of resources arranged hierarchically such that height of tree is O(log n) where n is total number of nodes (or resources). A process needs to lock a resource node in order to use it. But a node cannot be locked if any of its descendant or ancestor is locked. 
The operations that need to be supported are:

  1. islock() – Check if a given resource node is locked or not.
  2. Lock() – Lock a given resource node if it is not already locked and if none of its ancestors or descendants are locked.
  3. unLock() – Unlock a given resource node and update its lock information.

The goal is to ensure the following time complexities:

  • islock() should be O(1)
  • Lock() should be O(log⁡ n)
  • unLock() should be O(log⁡ n)

It is given that resources need to be stored in the form of the n-ary tree. Now the question is, how to augment the tree to achieve the above complexity bounds. 

Some General Questions:

Q1. Why doesn't setting Lock = true alone solve the purpose?
Because for the approaches where we move towards the parent to check if locking is possible if a request comes for any node between a locked node and the root, then there's no way of telling that a descendant node is locked. Hence, variables like isLockable will be used to maintain this info.

Q2. Why not lock all nodes from the current node to the root?
Because locking, in general, is a resource-intensive operation and performing locking for all nodes right up to the root would be a waste of resources. Hence, lightweight solutions such as introducing a isLockable variable are used.

[Naive Approach] Checking ancestors and descendants

The idea is to store a boolean variable isLocked for each resource node. The isLocked variable is set to true if the node is locked, and false otherwise.

Key Operations:

  1. isLock(): Checks the isLocked status of the given node.
  2. Lock(): If isLocked is already true, the node cannot be locked. If isLocked is false, the function checks all descendant and ancestor nodes. If any of these nodes are locked, the current node cannot be locked. If no ancestor or descendant node is locked, the node is locked by setting isLocked to true.
  3. unLock(): If isLocked is false, no action is performed. If isLocked is true, the node is unlocked by setting isLocked to false.
C++
#include <iostream>
#include <vector>
using namespace std;

class NaryTree
{
  public:
    // True if the node is locked
    bool isLocked;

    // Pointer to parent node
    NaryTree *parent;

    // List of child nodes
    vector<NaryTree *> children;

    NaryTree(NaryTree *parent = nullptr) : parent(parent), isLocked(false)
    {
    }

    void addChild(NaryTree *child)
    {
        children.push_back(child);
        child->parent = this;
    }
};

bool isLock(NaryTree *node)
{
    return node->isLocked;
}

bool hasLockedDescendants(NaryTree *node)
{
    for (NaryTree *child : node->children)
    {
        if (child->isLocked || hasLockedDescendants(child))
        {
            return true;
        }
    }
    return false;
}

bool Lock(NaryTree *node)
{
    // Node is already locked
    if (node->isLocked)
    {
        return false;
    }

    // Check all ancestors for locks
    NaryTree *current = node->parent;
    while (current != nullptr)
    {
        if (current->isLocked)
        {
            return false;
        }
        current = current->parent;
    }

    // Check all descendants for locks
    if (hasLockedDescendants(node))
    {
        return false;
    }

    // Lock the node
    node->isLocked = true;
    return true;
}

// Unlock function simply sets isLocked to false (O(1))
void unLock(NaryTree *node)
{
    node->isLocked = false;
}

int main()
{
    NaryTree root;
    NaryTree child1(&root);
    NaryTree child2(&root);
    NaryTree child3(&child1);
    NaryTree child4(&child1);

    // Add children to the nodes
    root.addChild(&child1);
    root.addChild(&child2);
    child1.addChild(&child3);
    child1.addChild(&child4);

    // Test lock and unlock functionality
    // Lock child1
    if (Lock(&child1))
    {
        cout << "child1 locked successfully." << endl;
    }
    else
    {
        cout << "Failed to lock child1." << endl;
    }

    // Try to lock child3, should fail since child1 is locked
    if (Lock(&child3))
    {
        cout << "child3 locked successfully." << endl;
    }
    else
    {
        cout << "Failed to lock child3." << endl;
    }

    // Unlock child1
    unLock(&child1);
    cout << "child1 unlocked." << endl;

    // Try to lock child3 again, should succeed now
    if (Lock(&child3))
    {
        cout << "child3 locked successfully." << endl;
    }
    else
    {
        cout << "Failed to lock child3." << endl;
    }

    return 0;
}
Java
import java.util.ArrayList;
import java.util.List;

class NaryTree {
    // True if the node is locked
    boolean isLocked;

    // Pointer to parent node
    NaryTree parent;

    // List of child nodes
    List<NaryTree> children;

    NaryTree(NaryTree parent)
    {
        this.parent = parent;
        this.isLocked = false;
        this.children = new ArrayList<>();
    }

    void addChild(NaryTree child)
    {
        children.add(child);
        child.parent = this;
    }
}

class NaryTreeLock {
    static boolean isLock(NaryTree node)
    {
        return node.isLocked;
    }

    static boolean hasLockedDescendants(NaryTree node)
    {
        for (NaryTree child : node.children) {
            if (child.isLocked
                || hasLockedDescendants(child)) {
                return true;
            }
        }
        return false;
    }

    static boolean Lock(NaryTree node)
    {
        // Node is already locked
        if (node.isLocked) {
            return false;
        }

        // Check all ancestors for locks
        NaryTree current = node.parent;
        while (current != null) {
            if (current.isLocked) {
                return false;
            }
            current = current.parent;
        }

        // Check all descendants for locks
        if (hasLockedDescendants(node)) {
            return false;
        }

        // Lock the node
        node.isLocked = true;
        return true;
    }

    // Unlock function simply sets isLocked to false (O(1))
    static void unLock(NaryTree node)
    {
        node.isLocked = false;
    }

    public static void main(String[] args)
    {
        NaryTree root = new NaryTree(null);
        NaryTree child1 = new NaryTree(root);
        NaryTree child2 = new NaryTree(root);
        NaryTree child3 = new NaryTree(child1);
        NaryTree child4 = new NaryTree(child1);

        // Add children to the nodes
        root.addChild(child1);
        root.addChild(child2);
        child1.addChild(child3);
        child1.addChild(child4);

        // Test lock and unlock functionality
        // Lock child1
        if (Lock(child1)) {
            System.out.println(
                "child1 locked successfully.");
        }
        else {
            System.out.println("Failed to lock child1.");
        }

        // Try to lock child3, should fail since child1 is
        // locked
        if (Lock(child3)) {
            System.out.println(
                "child3 locked successfully.");
        }
        else {
            System.out.println("Failed to lock child3.");
        }

        // Unlock child1
        unLock(child1);
        System.out.println("child1 unlocked.");

        // Try to lock child3 again, should succeed now
        if (Lock(child3)) {
            System.out.println(
                "child3 locked successfully.");
        }
        else {
            System.out.println("Failed to lock child3.");
        }
    }
}
Python
class NaryTree:
    # True if the node is locked
    def __init__(self, parent=None):
        self.isLocked = False
        self.parent = parent
        self.children = []

    def addChild(self, child):
        self.children.append(child)
        child.parent = self


def isLock(node):
    return node.isLocked


def hasLockedDescendants(node):
    for child in node.children:
        if child.isLocked or hasLockedDescendants(child):
            return True
    return False


def Lock(node):
    # Node is already locked
    if node.isLocked:
        return False

    # Check all ancestors for locks
    current = node.parent
    while current:
        if current.isLocked:
            return False
        current = current.parent

    # Check all descendants for locks
    if hasLockedDescendants(node):
        return False

    # Lock the node
    node.isLocked = True
    return True

# Unlock function simply sets isLocked to false (O(1))


def unLock(node):
    node.isLocked = False


if __name__ == '__main__':
    root = NaryTree()
    child1 = NaryTree(root)
    child2 = NaryTree(root)
    child3 = NaryTree(child1)
    child4 = NaryTree(child1)

    # Add children to the nodes
    root.addChild(child1)
    root.addChild(child2)
    child1.addChild(child3)
    child1.addChild(child4)

    # Test lock and unlock functionality
    # Lock child1
    if Lock(child1):
        print("child1 locked successfully.")
    else:
        print("Failed to lock child1.")

    # Try to lock child3, should fail since child1 is locked
    if Lock(child3):
        print("child3 locked successfully.")
    else:
        print("Failed to lock child3.")

    # Unlock child1
    unLock(child1)
    print("child1 unlocked.")

    # Try to lock child3 again, should succeed now
    if Lock(child3):
        print("child3 locked successfully.")
    else:
        print("Failed to lock child3.")
C#
using System;
using System.Collections.Generic;

public class NaryTree {
    // True if the node is locked
    public bool IsLocked;

    // Pointer to parent node
    public NaryTree Parent;

    // List of child nodes
    public List<NaryTree> Children;

    public NaryTree(NaryTree parent = null)
    {
        Parent = parent;
        IsLocked = false;
        Children = new List<NaryTree>();
    }

    public void AddChild(NaryTree child)
    {
        Children.Add(child);
        child.Parent = this;
    }
}

public class Program {
    public static bool IsLock(NaryTree node)
    {
        return node.IsLocked;
    }

    public static bool HasLockedDescendants(NaryTree node)
    {
        foreach(NaryTree child in node.Children)
        {
            if (child.IsLocked
                || HasLockedDescendants(child)) {
                return true;
            }
        }
        return false;
    }

    public static bool Lock(NaryTree node)
    {
        // Node is already locked
        if (node.IsLocked) {
            return false;
        }

        // Check all ancestors for locks
        NaryTree current = node.Parent;
        while (current != null) {
            if (current.IsLocked) {
                return false;
            }
            current = current.Parent;
        }

        // Check all descendants for locks
        if (HasLockedDescendants(node)) {
            return false;
        }

        // Lock the node
        node.IsLocked = true;
        return true;
    }

    // Unlock function simply sets IsLocked to false (O(1))
    public static void UnLock(NaryTree node)
    {
        node.IsLocked = false;
    }

    public static void Main()
    {
        NaryTree root = new NaryTree();
        NaryTree child1 = new NaryTree(root);
        NaryTree child2 = new NaryTree(root);
        NaryTree child3 = new NaryTree(child1);
        NaryTree child4 = new NaryTree(child1);

        // Add children to the nodes
        root.AddChild(child1);
        root.AddChild(child2);
        child1.AddChild(child3);
        child1.AddChild(child4);

        // Test lock and unlock functionality
        // Lock child1
        if (Lock(child1)) {
            Console.WriteLine(
                "child1 locked successfully.");
        }
        else {
            Console.WriteLine("Failed to lock child1.");
        }

        // Try to lock child3, should fail since child1 is
        // locked
        if (Lock(child3)) {
            Console.WriteLine(
                "child3 locked successfully.");
        }
        else {
            Console.WriteLine("Failed to lock child3.");
        }

        // Unlock child1
        UnLock(child1);
        Console.WriteLine("child1 unlocked.");

        // Try to lock child3 again, should succeed now
        if (Lock(child3)) {
            Console.WriteLine(
                "child3 locked successfully.");
        }
        else {
            Console.WriteLine("Failed to lock child3.");
        }
    }
}
JavaScript
class NaryTree {
    // True if the node is locked
    constructor(parent = null)
    {
        this.isLocked = false;
        this.parent = parent;
        this.children = [];
    }

    addChild(child)
    {
        this.children.push(child);
        child.parent = this;
    }
}

function isLock(node) { return node.isLocked; }

function hasLockedDescendants(node)
{
    for (const child of node.children) {
        if (child.isLocked || hasLockedDescendants(child)) {
            return true;
        }
    }
    return false;
}

function Lock(node)
{
    // Node is already locked
    if (node.isLocked) {
        return false;
    }

    // Check all ancestors for locks
    let current = node.parent;
    while (current !== null) {
        if (current.isLocked) {
            return false;
        }
        current = current.parent;
    }

    // Check all descendants for locks
    if (hasLockedDescendants(node)) {
        return false;
    }

    // Lock the node
    node.isLocked = true;
    return true;
}

// Unlock function simply sets isLocked to false (O(1))
function unLock(node) { node.isLocked = false; }

function main()
{
    const root = new NaryTree();
    const child1 = new NaryTree(root);
    const child2 = new NaryTree(root);
    const child3 = new NaryTree(child1);
    const child4 = new NaryTree(child1);

    // Add children to the nodes
    root.addChild(child1);
    root.addChild(child2);
    child1.addChild(child3);
    child1.addChild(child4);

    // Test lock and unlock functionality
    // Lock child1
    if (Lock(child1)) {
        console.log("child1 locked successfully.");
    }
    else {
        console.log("Failed to lock child1.");
    }

    // Try to lock child3, should fail since child1 is
    // locked
    if (Lock(child3)) {
        console.log("child3 locked successfully.");
    }
    else {
        console.log("Failed to lock child3.");
    }

    // Unlock child1
    unLock(child1);
    console.log("child1 unlocked.");

    // Try to lock child3 again, should succeed now
    if (Lock(child3)) {
        console.log("child3 locked successfully.");
    }
    else {
        console.log("Failed to lock child3.");
    }
}

main();

Output
child1 locked successfully.
Failed to lock child3.
child1 unlocked.
child3 locked successfully.

Time Complexity:

  • isLock() O(1)
  • Lock() O(n), because there can be O(n) descendants.
  • unLock() O(1)

Auxiliary Space: O(1)

[Expected Approach] Using counter variable

The idea is to augment tree with following three fields:  

  1. A boolean field isLocked (same as above method).
  2. Parent-Pointer to access all ancestors in O(Log n) time.
  3. Count-of-locked-descendants A node can be ancestor of many descendants. We can check if any of the descendants is locked using this count.

Key Operations:

  • isLock(): Returns the current lock status of the node.
  • Lock(): This operation checks all ancestors (up to O(log n) ancestors) to ensure no ancestor is locked, and ensures no descendants are locked using the lockedDescendantsCount. If everything is clear, it locks the node and increments the lockedDescendantsCount for all ancestors.
  • unLock(): This operation sets the node's isLocked to false, and decrements the lockedDescendantsCount for all ancestors as the node is no longer considered a locked descendant in log(n).
C++
#include <iostream>
#include <vector>
using namespace std;

class NaryTree
{
  public:
    // True if the node is locked
    bool isLocked;

    // Pointer to parent node
    NaryTree *parent;

    // List of child nodes (n-ary tree structure)
    vector<NaryTree *> children;

    // Count of locked descendants in the subtree
    int lockedDescendantsCount;

    NaryTree(NaryTree *parent = nullptr) : parent(parent), isLocked(false), lockedDescendantsCount(0)
    {
    }

    void addChild(NaryTree *child)
    {
        children.push_back(child);
        child->parent = this;
    }

    bool isLock()
    {
        return isLocked;
    }

    bool Lock()
    {
        // Node is already locked or has locked descendants
        if (isLocked || lockedDescendantsCount > 0)
        {
            return false;
        }

        // Check all ancestors for locks
        NaryTree *current = parent;
        while (current != nullptr)
        {
            // If any ancestor is locked, this node cannot be locked
            if (current->isLocked)
            {
                return false;
            }
            current = current->parent;
        }

        // Lock the node
        isLocked = true;

        // Update locked descendants count for all ancestors
        current = parent;
        while (current != nullptr)
        {
            current->lockedDescendantsCount++;
            current = current->parent;
        }

        return true;
    }

    void unLock()
    {
        // Node is not locked, nothing to do
        if (!isLocked)
        {
            return;
        }

        // Unlock the node
        isLocked = false;

        // Update locked descendants count for all ancestors
        NaryTree *current = parent;
        while (current != nullptr)
        {
            current->lockedDescendantsCount--;
            current = current->parent;
        }
    }
};

int main()
{

    NaryTree root;
    NaryTree child1(&root);
    NaryTree child2(&root);
    NaryTree child3(&child1);
    NaryTree child4(&child1);

    // Add children to root and child1
    root.addChild(&child1);
    root.addChild(&child2);
    child1.addChild(&child3);
    child1.addChild(&child4);

    // Lock child1
    if (child1.Lock())
    {
        cout << "child1 locked successfully." << endl;
    }
    else
    {
        cout << "Failed to lock child1." << endl;
    }

    // Try to lock child3, should fail since child1 is locked
    if (child3.Lock())
    {
        cout << "child3 locked successfully." << endl;
    }
    else
    {
        cout << "Failed to lock child3." << endl;
    }

    // Unlock child1
    child1.unLock();
    cout << "child1 unlocked." << endl;

    // Try to lock child3 again, should succeed now
    if (child3.Lock())
    {
        cout << "child3 locked successfully." << endl;
    }
    else
    {
        cout << "Failed to lock child3." << endl;
    }

    return 0;
}
Java
import java.util.ArrayList;
import java.util.List;

class NaryTree {
    // True if the node is locked
    private boolean isLocked;

    // Pointer to parent node
    private NaryTree parent;

    // List of child nodes (n-ary tree structure)
    private List<NaryTree> children;

    // Count of locked descendants in the subtree
    private int lockedDescendantsCount;

    public NaryTree(NaryTree parent)
    {
        this.parent = parent;
        this.isLocked = false;
        this.lockedDescendantsCount = 0;
        this.children = new ArrayList<>();
    }

    public NaryTree() { this(null); }

    public void addChild(NaryTree child)
    {
        children.add(child);
        child.parent = this;
    }

    public boolean isLock() { return isLocked; }

    public boolean Lock()
    {
        // Node is already locked or has locked descendants
        if (isLocked || lockedDescendantsCount > 0) {
            return false;
        }

        // Check all ancestors for locks
        NaryTree current = parent;
        while (current != null) {
            // If any ancestor is locked, this node cannot
            // be locked
            if (current.isLocked) {
                return false;
            }
            current = current.parent;
        }

        // Lock the node
        isLocked = true;

        // Update locked descendants count for all ancestors
        current = parent;
        while (current != null) {
            current.lockedDescendantsCount++;
            current = current.parent;
        }

        return true;
    }

    public void unLock()
    {
        // Node is not locked, nothing to do
        if (!isLocked) {
            return;
        }

        // Unlock the node
        isLocked = false;

        // Update locked descendants count for all ancestors
        NaryTree current = parent;
        while (current != null) {
            current.lockedDescendantsCount--;
            current = current.parent;
        }
    }

    public static void main(String[] args)
    {
        NaryTree root = new NaryTree();
        NaryTree child1 = new NaryTree(root);
        NaryTree child2 = new NaryTree(root);
        NaryTree child3 = new NaryTree(child1);
        NaryTree child4 = new NaryTree(child1);

        // Add children to root and child1
        root.addChild(child1);
        root.addChild(child2);
        child1.addChild(child3);
        child1.addChild(child4);

        // Lock child1
        if (child1.Lock()) {
            System.out.println(
                "child1 locked successfully.");
        }
        else {
            System.out.println("Failed to lock child1.");
        }

        // Try to lock child3, should fail since child1 is
        // locked
        if (child3.Lock()) {
            System.out.println(
                "child3 locked successfully.");
        }
        else {
            System.out.println("Failed to lock child3.");
        }

        // Unlock child1
        child1.unLock();
        System.out.println("child1 unlocked.");

        // Try to lock child3 again, should succeed now
        if (child3.Lock()) {
            System.out.println(
                "child3 locked successfully.");
        }
        else {
            System.out.println("Failed to lock child3.");
        }
    }
}
Python
class NaryTree:
    def __init__(self, parent=None):
        self.isLocked = False  # True if the node is locked
        self.parent = parent  # Pointer to parent node
        self.children = []  # List of child nodes (n-ary tree structure)
        self.lockedDescendantsCount = 0  # Count of locked descendants in the subtree

    def addChild(self, child):
        self.children.append(child)
        child.parent = self

    def isLock(self):
        return self.isLocked

    def Lock(self):
        # Node is already locked or has locked descendants
        if self.isLocked or self.lockedDescendantsCount > 0:
            return False

        # Check all ancestors for locks
        current = self.parent
        while current is not None:
            # If any ancestor is locked, this node cannot be locked
            if current.isLocked:
                return False
            current = current.parent

        # Lock the node
        self.isLocked = True

        # Update locked descendants count for all ancestors
        current = self.parent
        while current is not None:
            current.lockedDescendantsCount += 1
            current = current.parent

        return True

    def unLock(self):
        # Node is not locked, nothing to do
        if not self.isLocked:
            return

        # Unlock the node
        self.isLocked = False

        # Update locked descendants count for all ancestors
        current = self.parent
        while current is not None:
            current.lockedDescendantsCount -= 1
            current = current.parent


if __name__ == '__main__':
    root = NaryTree()
    child1 = NaryTree(root)
    child2 = NaryTree(root)
    child3 = NaryTree(child1)
    child4 = NaryTree(child1)

    # Add children to root and child1
    root.addChild(child1)
    root.addChild(child2)
    child1.addChild(child3)
    child1.addChild(child4)

    # Lock child1
    if child1.Lock():
        print('child1 locked successfully.')
    else:
        print('Failed to lock child1.')

    # Try to lock child3, should fail since child1 is locked
    if child3.Lock():
        print('child3 locked successfully.')
    else:
        print('Failed to lock child3.')

    # Unlock child1
    child1.unLock()
    print('child1 unlocked.')

    # Try to lock child3 again, should succeed now
    if child3.Lock():
        print('child3 locked successfully.')
    else:
        print('Failed to lock child3.')
C#
using System;
using System.Collections.Generic;

public class NaryTree {
    // True if the node is locked
    public bool isLocked;

    // Pointer to parent node
    public NaryTree parent;

    // List of child nodes (n-ary tree structure)
    public List<NaryTree> children;

    // Count of locked descendants in the subtree
    public int lockedDescendantsCount;

    public NaryTree(NaryTree parent = null)
    {
        this.parent = parent;
        this.isLocked = false;
        this.lockedDescendantsCount = 0;
        this.children = new List<NaryTree>();
    }

    public void AddChild(NaryTree child)
    {
        children.Add(child);
        child.parent = this;
    }

    public bool IsLocked() { return isLocked; }

    public bool Lock()
    {
        // Node is already locked or has locked descendants
        if (isLocked || lockedDescendantsCount > 0) {
            return false;
        }

        // Check all ancestors for locks
        NaryTree current = parent;
        while (current != null) {
            // If any ancestor is locked, this node cannot
            // be locked
            if (current.isLocked) {
                return false;
            }
            current = current.parent;
        }

        // Lock the node
        isLocked = true;

        // Update locked descendants count for all ancestors
        current = parent;
        while (current != null) {
            current.lockedDescendantsCount++;
            current = current.parent;
        }

        return true;
    }

    public void Unlock()
    {
        // Node is not locked, nothing to do
        if (!isLocked) {
            return;
        }

        // Unlock the node
        isLocked = false;

        // Update locked descendants count for all ancestors
        NaryTree current = parent;
        while (current != null) {
            current.lockedDescendantsCount--;
            current = current.parent;
        }
    }
}

public class Program {
    public static void Main()
    {
        NaryTree root = new NaryTree();
        NaryTree child1 = new NaryTree(root);
        NaryTree child2 = new NaryTree(root);
        NaryTree child3 = new NaryTree(child1);
        NaryTree child4 = new NaryTree(child1);

        // Add children to root and child1
        root.AddChild(child1);
        root.AddChild(child2);
        child1.AddChild(child3);
        child1.AddChild(child4);

        // Lock child1
        if (child1.Lock()) {
            Console.WriteLine(
                "child1 locked successfully.");
        }
        else {
            Console.WriteLine("Failed to lock child1.");
        }

        // Try to lock child3, should fail since child1 is
        // locked
        if (child3.Lock()) {
            Console.WriteLine(
                "child3 locked successfully.");
        }
        else {
            Console.WriteLine("Failed to lock child3.");
        }

        // Unlock child1
        child1.Unlock();
        Console.WriteLine("child1 unlocked.");

        // Try to lock child3 again, should succeed now
        if (child3.Lock()) {
            Console.WriteLine(
                "child3 locked successfully.");
        }
        else {
            Console.WriteLine("Failed to lock child3.");
        }
    }
}
JavaScript
class NaryTree {
    // True if the node is locked
    constructor(parent = null)
    {
        this.isLocked = false;
        this.parent = parent;
        this.children = [];
        this.lockedDescendantsCount = 0;
    }

    addChild(child)
    {
        this.children.push(child);
        child.parent = this;
    }

    isLock() { return this.isLocked; }

    Lock()
    {
        // Node is already locked or has locked descendants
        if (this.isLocked
            || this.lockedDescendantsCount > 0) {
            return false;
        }

        // Check all ancestors for locks
        let current = this.parent;
        while (current !== null) {
            // If any ancestor is locked, this node cannot
            // be locked
            if (current.isLocked) {
                return false;
            }
            current = current.parent;
        }

        // Lock the node
        this.isLocked = true;

        // Update locked descendants count for all ancestors
        current = this.parent;
        while (current !== null) {
            current.lockedDescendantsCount++;
            current = current.parent;
        }

        return true;
    }

    unLock()
    {
        // Node is not locked, nothing to do
        if (!this.isLocked) {
            return;
        }

        // Unlock the node
        this.isLocked = false;

        // Update locked descendants count for all ancestors
        let current = this.parent;
        while (current !== null) {
            current.lockedDescendantsCount--;
            current = current.parent;
        }
    }
}

// Main function
const main = () => {
    const root = new NaryTree();
    const child1 = new NaryTree(root);
    const child2 = new NaryTree(root);
    const child3 = new NaryTree(child1);
    const child4 = new NaryTree(child1);

    // Add children to root and child1
    root.addChild(child1);
    root.addChild(child2);
    child1.addChild(child3);
    child1.addChild(child4);

    // Lock child1
    if (child1.Lock()) {
        console.log("child1 locked successfully.");
    }
    else {
        console.log("Failed to lock child1.");
    }

    // Try to lock child3, should fail since child1 is
    // locked
    if (child3.Lock()) {
        console.log("child3 locked successfully.");
    }
    else {
        console.log("Failed to lock child3.");
    }

    // Unlock child1
    child1.unLock();
    console.log("child1 unlocked.");

    // Try to lock child3 again, should succeed now
    if (child3.Lock()) {
        console.log("child3 locked successfully.");
    }
    else {
        console.log("Failed to lock child3.");
    }
};

main();

Output
child1 locked successfully.
Failed to lock child3.
child1 unlocked.
child3 locked successfully.

Time Complexity:

  • isLock() O(1)
  • Lock() O(log n)
  • unLock() O(log n)

Auxiliary Space: O(1)


Article Tags :

Explore