📜  以n叉树形式排列的资源的加锁和解锁

📅  最后修改于: 2022-05-13 01:57:20.593000             🧑  作者: Mango

以n叉树形式排列的资源的加锁和解锁

给定一棵按层次排列的资源树,使得树的高度为 O(Log N),其中 N 是节点(或资源)的总数。进程需要锁定资源节点才能使用它。但是,如果节点的任何后代或祖先被锁定,则无法锁定节点。
给定资源节点需要以下操作:

  • islock() - 如果给定节点被锁定,则返回 true,否则返回 false。如果 lock() 已成功执行该节点,则该节点被锁定。
  • Lock() - 如果可能,锁定给定节点并更新锁定信息。仅当当前节点的祖先和后代未锁定时才可以锁定。
  • unLock() - 解锁节点并更新信息。

如何设计资源节点并实现上述操作以实现以下时间复杂度。

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

我们强烈建议您最小化您的浏览器并首先自己尝试。
假设资源需要以n叉树的形式存储。现在的问题是,如何扩充树以实现上述复杂性界限。

一些一般性问题:

Q1。为什么单独设置 Lock = true 不能解决目的?
A1。因为对于我们向父节点移动以检查是否可以锁定的方法,如果请求来自锁定节点和根节点之间的任何节点,那么没有办法告诉后代节点被锁定。因此,诸如 isLockable 之类的变量用于维护此信息。

Q2。为什么不锁定当前节点到根节点的所有节点呢?
A2。因为锁定通常是一种资源密集型操作,并且对直到根节点的所有节点执行锁定将浪费资源。因此,使用了轻量级解决方案,例如引入 isLockable 变量。

方法1(简单)
一个简单的解决方案是为每个资源节点存储一个布尔变量isLocked 。如果当前节点被锁定,布尔变量 isLocked 为真,否则为假。
让我们看看如何使用这种方法进行操作。

  • isLock():检查给定节点的isLocked
  • Lock():如果设置了isLocked ,则无法锁定节点。否则检查节点的所有后代和祖先,如果其中任何一个被锁定,则该节点也不能被锁定。如果以上条件均不成立,则通过将isLocked设置为 true 来锁定该节点。
  • unLock():如果给定节点的isLocked为 false,则不做任何事情。否则将isLocked设置为 false。

时间复杂度:

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

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


方法2(根据问题的时间复杂度)
这个想法是用以下三个字段来扩充树:

  1. 布尔字段isLocked (与上述方法相同)。
  2. 在 O(Log n) 时间内访问所有祖先的父指针
  3. 锁定后代的计数。请注意,一个节点可以是许多后代的祖先。我们可以使用此计数检查是否有任何后代被锁定。

让我们看看如何使用这种方法进行操作。

  • isLock():检查给定节点的isLocked
  • Lock():遍历所有祖先。如果没有一个祖先被锁定, Count-of-locked-descendants为 0 并且isLocked为 false,则将当前节点的isLocked设置为 true。并为所有祖先增加Count-of-locked-descendants 。时间复杂度为 O(Log N),因为最多可以有 O(Log N) 个祖先。
  • unLock():遍历所有祖先,减少所有祖先的 Count-of-locked-descendants 。将当前节点的isLocked设置为 false。时间复杂度为 O(Log N)

感谢 Utkarsh Trivedi 提出这种方法。

方法3(根据问题的时间复杂度和更好的内存使用)这个想法是用以下三个字段来扩充树:

  1. 布尔字段 isLocked (与上述方法相同)。
  2. 在 O(Log n) 时间内访问所有祖先的父指针。
  3. 是可锁定的。我们可以使用这个变量检查是否有任何后代被锁定。如果没有后代被锁定,isLockable 为真,否则为假。

让我们看看如何使用这种方法进行操作。

  • isLock():检查给定节点的isLocked。
  • Lock():遍历所有祖先。如果没有一个祖先被锁定,isLockable 为真,isLocked 为假,则设置当前节点的 isLocked 为真。并且为所有祖先标记 isLockable false。时间复杂度为 O(Log N),因为最多可以有 O(Log N) 个祖先。
  • unLock():遍历所有祖先并将所有祖先的isLockable标记为true。将当前节点的 isLocked 设置为 false。时间复杂度为 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;
}


感谢 Adarsh Singh 提出这种方法。