如何对类似于链表的条目进行排序?

Posted

技术标签:

【中文标题】如何对类似于链表的条目进行排序?【英文标题】:how to sort entries similar to a linked list? 【发布时间】:2016-10-26 21:24:46 【问题描述】:

我有以下数据结构,我想根据 beforeafter 值对其进行排序。

array (size=5)
  0 => 
    array (size=3)
      'id' => int 14
      'parentId' => int 0
      'before' => int 15
  1 => 
    array (size=3)
      'id' => int 15
      'parentId' => int 0
      'after' => int 14
  2 => 
    array (size=3)
      'id' => int 9
      'parentId' => int 0
      'after' => int 15
  3 => 
    array (size=3)
      'id' => int 8
      'parentId' => int 0
      'after' => int 9
  4 => 
    array (size=3)
      'id' => int 1
      'parentId' => int 0
      'after' => int 14

有没有用 php 做到这一点的巧妙方法?

【问题讨论】:

函数 usort() - php.net/manual/en/function.usort.php @splash58 不! ***.com/q/38008964/476 您能否更准确地描述您希望它如何排序?是否与以下内容有关:'after:9' 意味着所有 ID 低于 9 的条目之后,'before : 10' 意味着所有高于 10 的值都应该在这个之后? @rbaker86 写入结果中的 id 顺序 谢谢。我希望这些键的顺序是 0、4、1、2、3。我意识到 1 和 4 都指定“之后:14”,对于这种情况,优先级并不重要。 【参考方案1】:

我认为没有直接的“单线”类型解决方案。

我不清楚parentId 对排序是否有任何意义,但如果不是,这感觉与我本周早些时候回答的this question about sorting an array of javascript includes by dependency 非常相似。

唯一真正的区别是,在您可以按依赖项排序之前,您需要将那些“之前”条目转换为相应行上的“之后”条目。

$data = [
    ["id" => 14, "parentId" => 0, "before" => 15],
    ["id" => 15, "parentId" => 0, "after" => 14],
    ["id" => 9,  "parentId" => 0, "after" => 15],
    ["id" => 8,  "parentId" => 0, "after" => 9],
    ["id" => 1,  "parentId" => 0, "after" => 14]
];

// Use the ID of each element as the array index.
$data = array_combine(array_column($data, "id"), $data);
// Convert each "after" entry into an array.
$data = array_map(function($element) 
        $element["after"] = isset($element["after"]) ? [$element["after"]] : [];
        return $element;
    , $data);
// Convert each "before" entry into an "after" entry.
foreach ($data as $id => $element) 
    if (isset($element["before"])) 
        $data[$element["before"]]["after"][] = $id;
        unset($data[$id]["before"]);
    

// Remove empty "after" entries.
$data = array_map(function($element) 
        if (!count($element["after"])) 
            unset($element["after"]);
        
        return $element;
    , $data);

$sorted = [];
while ($count = count($data)) 
    // Remove any met dependencies.
    foreach ($data as $id => $element) 
        if (isset($element["after"])) 
            foreach ($element["after"] as $after_id => $after_element) 
                if (isset($sorted[$after_element])) 
                    unset($data[$id]["after"][$after_id]);
                
            
            if (!count($data[$id]["after"])) 
                unset($data[$id]["after"]);
            
        
    
    // Add elements with no more dependencies to the output array.
    foreach ($data as $id => $element) 
        if (!isset($element["after"])) 
            $sorted[$id] = $element;
            unset($data[$id]);
        
    
    if (count($data) == $count) 
        die("Unresolvable dependency");
    

var_dump($sorted);
/*
array (size=5)
  14 => 
    array (size=2)
      'id' => int 14
      'parentId' => int 0
  15 => 
    array (size=2)
      'id' => int 15
      'parentId' => int 0
  1 => 
    array (size=2)
      'id' => int 1
      'parentId' => int 0
  9 => 
    array (size=2)
      'id' => int 9
      'parentId' => int 0
  8 => 
    array (size=2)
      'id' => int 8
      'parentId' => int 0
 */

【讨论】:

【参考方案2】:

我认为您可以使用uasort() 函数来满足您的需要。 要定义您的比较函数,我建议将所有after 条件转换为before 条件:

$array = [
    [
        'id'       => 14,
        'parentId' => 0,
        'before'   => 15
    ],
    [
        'id'       => 15,
        'parentId' => 0,
        'after'    => 14
    ],
    [
        'id'       => 9,
        'parentId' => 0,
        'after'    => 15
    ],
    [
        'id'       => 8,
        'parentId' => 0,
        'after'    => 9
    ],

    [
        'id'       => 1,
        'parentId' => 0,
        'after'    => 14
    ]
];

//transform all after conditions to before conditions
function defineBeforeCondition($array)

    $befores = array_column($array, 'before', 'id');
    $afters  = array_column($array, 'after', 'id');
    return array_merge(array_chunk($befores, 1, true), array_map('array_flip', array_chunk($afters, 1, true)));


$condition = defineBeforeCondition($array);

现在您可以在比较函数中使用$condition

$compare = function ($array1, $array2) use ($condition)

    //iterate through before conditions
    foreach ($condition as $before) 
        //if there is a match
        if (isset($before[$array1['id']]) && $before[$array1['id']] === $array2['id']) 
            //if the value of the first element is greater than the value of the second element,
            //but the first element should precede the second, return -1
            if ($array1['id'] > $array2['id']) 
                return -1;
            
            //otherwise make a normal comparison
            //note the spaceship operator for PHP >= 7.0
            return $array1['id'] <=> $array2['id'];
        
    
    //no data, move down the first element
    return 1;
;

uasort($array, $compare);
var_dump($array);

array (size=5)
  0 => 
    array (size=3)
      'id' => int 14
      'parentId' => int 0
      'before' => int 15
  4 => 
    array (size=3)
      'id' => int 1
      'parentId' => int 0
      'after' => int 14
  1 => 
    array (size=3)
      'id' => int 15
      'parentId' => int 0
      'after' => int 14
  2 => 
    array (size=3)
      'id' => int 9
      'parentId' => int 0
      'after' => int 15
  3 => 
    array (size=3)
      'id' => int 8
      'parentId' => int 0
      'after' => int 9

【讨论】:

以上是关于如何对类似于链表的条目进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

算法链表的快速排序和归并排序

C语言如何对链表的数进行排序?

如何正确释放链表的所有元素?

c语言对链表的数据排序的问题,分不是问题!

链表的合并

链表的合并