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

• Difficulty Level : Medium
• Last Updated : 18 Aug, 2022

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.
Following operations are required for a given resource node:

• islock()- returns true if a given node is locked and false if it is not. A node is locked if lock() has successfully executed for the node.
• Lock()- locks the given node if possible and updates lock information. Lock is possible only if ancestors and descendants of current node are not locked.
• unLock()- unlocks the node and updates information.

How design resource nodes and implement above operations such that following time complexities are achieved.

```    islock()  O(1)
Lock()    O(log N)
unLock()  O(log N)```

We strongly recommend you to minimize your browser and try this yourself first.
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?
A1. 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 are used to maintain this info.

Q2. Why not lock all nodes from the current node to the root?
A2. 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.

Method 1 (Simple)
A Simple Solution is to store a boolean variable isLocked with every resource node. The boolean variable isLocked is true if the current node is locked, else false.
Let us see how operations work using this Approach.

• isLock(): Check isLocked of the given node.
• Lock(): If isLocked is set, then the node cannot be locked. Else check all descendants and ancestors of the node and if any of them is locked, then also this node cannot be locked. If none of the above conditions is true, then lock this node by setting isLocked as true.
• unLock(): If isLocked of given node is false, nothing to do. Else set isLocked as false.

Time Complexities:

```isLock()  O(1)
Lock()    O(N)
unLock()  O(1)

Lock is O(N) because there can be O(N) descendants. ```

Method 2 (Time Complexities according to question)
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. Note that a node can be ancestor of many descendants. We can check if any of the descendants is locked using this count.

Let us see how operations work using this Approach.

• isLock(): Check isLocked of the given node.
• Lock(): Traverse all ancestors. If none of the ancestors is locked, Count-of-locked-descendants is 0 and isLocked is false, set isLocked of current node as true. And increment Count-of-locked-descendants for all ancestors. Time complexity is O(Log N) as there can be at most O(Log N) ancestors.
• unLock(): Traverse all ancestors and decrease Count-of-locked-descendants for all ancestors. Set isLocked of current node as false. Time complexity is O(Log N)

Thanks to Utkarsh Trivedi for suggesting this approach.

Method 3 (Time Complexities according to question and better memory usage) 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. isLockable. We can check if any of the descendants is locked using this variable. isLockable is true if none of the descendants are locked else false.

Let us see how operations work using this Approach.

• isLock(): Check isLocked of the given node.
• Lock(): Traverse all ancestors. If none of the ancestors is locked, isLockable is true and isLocked is false, set isLocked of current node as true. And mark isLockable false for all ancestors. Time complexity is O(Log N) as there can be at most O(Log N) ancestors.
• unLock(): Traverse all ancestors and mark isLockable true for all ancestors. Set isLocked of current node as false. Time complexity is O(Log N)

## C++

 `#include ``using` `namespace` `std;` `class` `narytree {``public``:``    ``bool` `isLock;``    ``bool` `isLockable;``    ``narytree* parent;``    ``vector children;``    ``narytree()``    ``{``        ``isLock = ``false``;``        ``isLockable = ``true``;``        ``parent = NULL;``    ``}``    ``narytree(narytree* parent)``    ``{``        ``isLock = ``false``;``        ``isLockable = ``true``;``        ``this``->parent = parent;``    ``}``};` `bool` `isLock(narytree* node) { ``return` `node->isLock; }` `void` `Lock(narytree* node)``{``    ``if` `(node->isLockable == ``false``)``        ``return``;` `    ``narytree* T = node;``    ``bool` `flag = ``false``;``    ``while` `(T != NULL) {``        ``if` `(T->isLock == ``true``) {``            ``flag = ``true``;``            ``break``;``        ``}``        ``T = T->parent;``    ``}``    ``if` `(flag)``        ``return``;``    ``else` `{``        ``node->isLock = ``true``;``        ``T = node;``        ``// marking isLockable as false for ancestor nodes.``        ``while` `(T != NULL) {``            ``T->isLockable = ``false``;``            ``T = T->parent;``        ``}``    ``}``}` `void` `unLock(narytree* node)``{``    ``if` `(node->isLock == ``false``)``        ``return``;``    ``narytree* T = node;``    ``node->isLock = ``false``;``    ``// marking isLockable as true for ancestor nodes.``    ``while` `(T != NULL) {``        ``T->isLockable = ``true``;``        ``T = T->parent;``    ``}``}` `int` `main()``{``    ``// Creating N-Array Tree``    ``narytree* root = ``new` `narytree();` `    ``narytree* t1 = ``new` `narytree(root);``    ``narytree* t2 = ``new` `narytree(root);``    ``narytree* t3 = ``new` `narytree(root);` `    ``root->children.push_back(t1);``    ``root->children.push_back(t2);``    ``root->children.push_back(t3);` `    ``narytree* t5 = ``new` `narytree(root->children[0]);``    ``root->children[0]->children.push_back(t5);``    ``narytree* t4 = ``new` `narytree(root->children[1]);``    ``root->children[1]->children.push_back(t4);` `    ``// Locking t4 node.``    ``Lock(t4);``    ``//    Checking if the t4 node is locked.``    ``cout << ``"t4 node is locked:"``         ``<< ((isLock(t4) == ``true``) ? ``"true"` `: ``"false"``)``         ``<< ``"\n"``;``    ``Lock(t2);``    ``cout << ``"t2 node is locked:"``         ``<< ((isLock(t2) == ``true``) ? ``"true"` `: ``"false"``)``         ``<< ``"\n"``;``    ``// Unlocking t4 node.``    ``unLock(t4);``    ``//    Now we should be able to lock the tree.``    ``Lock(t2);``    ``cout << ``"t2 node is locked:"``         ``<< ((isLock(t2) == ``true``) ? ``"true"` `: ``"false"``);` `    ``return` `0;``}`

## Java

 `import` `java.io.*;``import` `java.util.*;` `class` `GFG {` `    ``static` `class` `narytree {``        ``boolean` `isLock;``        ``boolean` `isLockable;``        ``narytree parent;``        ``List children;` `        ``narytree()``        ``{``            ``isLock = ``false``;``            ``isLockable = ``true``;``            ``parent = ``null``;``        ``}` `        ``narytree(narytree parent)``        ``{``            ``isLock = ``false``;``            ``isLockable = ``true``;``            ``this``.parent = parent;``        ``}``    ``}` `    ``static` `boolean` `isLock(narytree node)``    ``{``        ``return` `node.isLock;``    ``}` `    ``static` `void` `lock(narytree node)``    ``{``        ``if` `(node.isLockable == ``false``) {``            ``return``;``        ``}` `        ``narytree T = node;``        ``boolean` `flag = ``false``;``        ``while` `(T != ``null``) {``            ``if` `(T.isLock == ``true``) {``                ``flag = ``true``;``                ``break``;``            ``}``            ``T = T.parent;``        ``}` `        ``if` `(flag) {``            ``return``;``        ``}``        ``else` `{``            ``T = node;``            ``node.isLock = ``true``;``            ``// marking isLockable as false for ancestor``            ``// nodes.``            ``while` `(T != ``null``) {``                ``T.isLockable = ``false``;``                ``T = T.parent;``            ``}``        ``}``    ``}` `    ``static` `void` `unLock(narytree node)``    ``{``        ``if` `(node.isLock == ``false``) {``            ``return``;``        ``}` `        ``narytree T = node;``        ``node.isLock = ``false``;``        ``// marking isLockable as true for ancestor nodes.``        ``while` `(T != ``null``) {``            ``T.isLockable = ``true``;``            ``T = T.parent;``        ``}``    ``}` `    ``public` `static` `void` `main(String[] args)``    ``{``        ``// Creating N-Array Tree``        ``narytree root = ``new` `narytree();` `        ``narytree t1 = ``new` `narytree(root);``        ``narytree t2 = ``new` `narytree(root);``        ``narytree t3 = ``new` `narytree(root);` `        ``root.children = ``new` `ArrayList<>();``        ``root.children.add(t1);``        ``root.children.add(t2);``        ``root.children.add(t3);` `        ``narytree t5 = ``new` `narytree(root.children.get(``0``));``        ``root.children.get(``0``).children = ``new` `ArrayList<>();``        ``root.children.get(``0``).children.add(t5);` `        ``narytree t4 = ``new` `narytree(root.children.get(``1``));``        ``root.children.get(``1``).children = ``new` `ArrayList<>();``        ``root.children.get(``1``).children.add(t4);` `        ``// Locking t4 node.``        ``lock(t4);``        ``// Checking if the t4 node is locked.``        ``System.out.println(``            ``"t4 node is locked:"``            ``+ ((isLock(t4) == ``true``) ? ``"true"` `: ``"false"``));` `        ``lock(t2);``        ``System.out.println(``            ``"t2 node is locked:"``            ``+ ((isLock(t2) == ``true``) ? ``"true"` `: ``"false"``));``        ``// Unlocking t4 node.``        ``unLock(t4);``        ``// Now we should be able to lock the tree.``        ``lock(t2);``        ``System.out.println(``            ``"t2 node is locked:"``            ``+ ((isLock(t2) == ``true``) ? ``"true"` `: ``"false"``));``    ``}``}` `// This code is contributed by Snigdha Patil`

Thanks to Adarsh Singh for suggesting this approach.