php - "Family Tree"数据结构

标签 php data-structures family-tree

我正在寻找一种在 PHP 中表示家谱的方法。这意味着 child 需要从两个(或更多) parent 那里继承。

要求如下:

  • 1、2 或更多 parent
  • 如果我可以附上姓氏或关系状态等元数据,可加分

这是我的无效尝试(遗憾的是没有数组作为键):

$tree = array(
    'uncle' => false, // no children
    array('mom', 'dad') => array(
        'me' => false,
        array('brother', 'sister-in-law') => array(
            'niece' => false
        )
    )
);

问题是,我如何表示具有这些要求的家谱?

最佳答案

您无法像那样在单个 array() 中完成所有操作。您可以像那样设置树,但设置具有多个父项和其他关系的更复杂的图需要多行代码。

如果您对此进行一些 OO 处理,将会大有帮助。让我们创建一个 Person 类来帮助管理关系。从根本上说,我们已经有了人以及他们与其他人的关系,所以我们将从这里开始。

人物类

我想象的是每个人都有一系列的关系。该数组将首先按关系类型进行索引,例如“ parent ”或“ child ”。然后每个条目将是一个 Person 数组。

class Person {
    var $name, $relations;

    function __construct($name) {
        $this->name      = $name;
        $this->relations = array();
    }

    function addRelation($type, $person) {
        if (!isset($this->relations[$type])) {
            $this->relations[$type] = array();
        }

        $this->relations[$type][] = $person;
    }

    // Looks up multiple relations, for example "parents".
    function getRelations($type) {
        if (!isset($this->relations[$type])) {
            return array();
        }

        return $this->relations[$type];
    }

    // Looks up a single relation, for example "spouse".
    function getRelation($type) {
        $relations = $this->getRelations($type);
        return empty($relations) ? null : $relations[0];
    }

    function __toString() {
        return $this->name;
    }

友好的加法器和 setter/getter

以上述为基础,我们可以添加一些更友好命名的方法。为了便于说明,我们将处理 parent /子女关系和配偶。

    function addParents($mom, $dad) {
        $mom->addChild($this);
        $dad->addChild($this);
    }

    function addChild($child) {
        $this ->addRelation('children', $child);
        $child->addRelation('parents',  $this);
    }

    function addSpouse($spouse) {
        $this  ->addRelation('spouse', $spouse);
        $spouse->addRelation('spouse', $this);
    }

    function getParents () { return $this->getRelations('parents');  }
    function getChildren() { return $this->getRelations('children'); }
    function getSpouse  () { return $this->getRelation ('spouse');   }
}

创造人

现在我们可以创建几个人并设置他们的关系。让我们试试 Billy 和他的 parent John 和 Jane。

$john  = new Person('John');
$jane  = new Person('Jane');
$billy = new Person('Billy');

$john ->addSpouse ($jane);
$billy->addParents($jane, $john);

我们可以像这样检查他们的关系:

echo "John is married to " . $john->getSpouse() . ".\n";
echo "Billy's parents are " . implode(" and ", $billy->getParents()) . ".\n";

输出:

John is married to Jane.
Billy's parents are Jane and John.

显示家谱

如果图变大,我们可以递归遍历图。下面是一个显示基本家谱的树遍历函数示例。我已经将 Sara、她的丈夫 Mike 和他们的儿子 Bobby 添加到组合中。

$john  = new Person('John');
$jane  = new Person('Jane');
$sara  = new Person('Sara');
$mike  = new Person('Mike');
$bobby = new Person('Bobby');
$billy = new Person('Billy');

$john ->addSpouse ($jane);
$sara ->addParents($jane, $john);
$sara ->addSpouse ($mike);
$bobby->addParents($sara, $mike);
$billy->addParents($jane, $john);

function displayFamilyTree($root, $prefix = "") {
    $parents = array($root);

    if ($root->getSpouse() != null) {
        $parents[] = $root->getSpouse();
    }

    echo $prefix . implode(" & ", $parents) . "\n";

    foreach ($root->getChildren() as $child) {
        displayFamilyTree($child, "....$prefix");
    }
}

displayFamilyTree($john);

输出:

John & Jane
....Sara & Mike
........Bobby
....Billy


编辑:下面是@Wrikken 的评论,为了便于阅读,转载了:

确实如此。恕我直言,为每个关系添加一个从-到日期(可能是 NULL 表示没有结束)。离婚和收养等都会发生。此外:我会向 addRelation() 函数添加反向类型和“ping-back”:

function addRelation($type, $person, $reverseType, $pingback = false) {
    if (!isset($this->relations[$type])) {
        $this->relations[$type] = array();
    }

    if (!in_array($person, $this->relations[$type], true)) {
        $this->relations[$type][] = $person;
    }

    if (!$pingback) {
        $person->addRelation($reverseType, $this, $type, true);
    }
}

关于php - "Family Tree"数据结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3304670/

相关文章:

algorithm - 用于存储由唯一的 8 位十六进制标识的对象的数据结构,用于快速插入和查找

css - 动态家谱

iphone - 如何将家庭 map 添加到我的 iPhone 应用程序?

php - MySQL 表中的 64 位密码哈希

php - 在 Apache/PHP 中,如何运行一个独立的进程,并在 linux 上重启 apache 后继续存在

php - mysql php从表B中获取与表A中给定列不匹配的条目的最佳方法是什么

data-structures - 具有随机访问的自排序数据结构

php - SilverStripe - 网站服务器无法响应您的请求

algorithm - 如何将时间序列数据存储在列表(或任何其他数据结构)中以获得各种范围内的合理趋势?

python - Python 中的家谱