如何在PHP中对链表进行排序?

时间:2010-02-07 04:32:35

标签: php arrays linked-list

$arr[] = array(...,'id'=1,'prev'=>2,'next'=>null);
$arr[] = array(...,'id'=2,'prev'=>3..,'next'=>1);
$arr[] = array(...,'id'=3,'prev'=>4,'next'=>2);
..

每条记录的顺序可以是任意的。如何对这种数组进行排序,以便prev的值为null的记录是第一个,而{{1} } null是最后一个?

5 个答案:

答案 0 :(得分:7)

数组是链表的容器。 A linked list is a list with linked objects,而不是包含具有关系的对象的列表。基本上,你得到的是两个容器中最差的。我会尝试将该结构转换为其他数据容器;真正的链接列表永远不需要按照您对数据进行排序的方式进行排序。

好方法会涉及到类似的东西。我会给你留下在列表中间插入对象的方式,这并不难。

<?php
class LinkedObject
{
    var $value;
    var $prev;
    var $next;

    public function __construct($value, $prev = null, $next = null)
    {
        $this->value = $value;
        $this->prev = $prev;
        $this->next = $next;
    }

    public function append(LinkedObject $insertee)
    {
        $link = $this;
        while($link->next != null)
            $link = $link->next;

        $link->next = $insertee;
        $insertee->prev = $link;
    }

    public function __toString()
    {
        $str = $this->value;
        if($this->next != null)
        {
            $str .= " » ";
            $str .= $this->next;
        }
        return $str;
    }
}

$head = new LinkedObject("foo");
$head->append(new LinkedObject("bar"));
$head->append(new LinkedObject("baz"));
echo $head . "\n"; // gives "foo » bar » baz"
?>

但是,如果出于某种神秘的原因,你真的需要它们在数组中,这就是你需要的:

<?php
function find_row($array, $id)
{
    foreach($array as $current_row)
    {
        if($current_row['id'] === $id)
            return $current_row;
    }
    return null;
}

function what_the_heck_sort($array)
{
    $start_record = $array[0];
    $working_record = $array[0];
    $result = array($working_record);
    while($working_record['prev'] !== null)
    {
        $working_record = find_row($array, $working_record['prev']);
        array_unshift($result, $working_record);
    }

    $working_record = $start_record;
    while($working_record['next'] !== null)
    {
        $working_record = find_row($array, $working_record['next']);
        array_push($result, $working_record);
    }
    return $result;
}

// the test code
$test = array(
    array("foo 01", 'id' => 0, 'prev' => null, 'next' => 1),
    array("foo 02", 'id' => 1, 'prev' => 0, 'next' => 2),
    array("foo 03", 'id' => 2, 'prev' => 1, 'next' => 3),
    array("foo 04", 'id' => 3, 'prev' => 2, 'next' => 4),
    array("foo 05", 'id' => 4, 'prev' => 3, 'next' => 5),
    array("foo 06", 'id' => 5, 'prev' => 4, 'next' => 6),
    array("foo 07", 'id' => 6, 'prev' => 5, 'next' => 7),
    array("foo 08", 'id' => 7, 'prev' => 6, 'next' => 8),
    array("foo 09", 'id' => 8, 'prev' => 7, 'next' => 9),
    array("foo 10", 'id' => 9, 'prev' => 8, 'next' => null));

shuffle($test);
print_r(what_the_heck_sort($test));
?>

但实际上,帮自己一个忙,做一个真正的链表,使用对象而不是数组。在我看来,上面的排序方法非常适合了解约束,但是非常慢,因为它需要为每个id查找数组。

答案 1 :(得分:1)

嗯,所以你想把你的阵列变成这样的东西:

$array[] = array('id'=>1324, 'prev'=>null, 'next'=>15834);
$array[] = array('id'=>15834, 'prev'=>1324, 'next'=>1023);
$array[] = array('id'=>1023, 'prev'=>15834, 'next'=>12482);
$array[] = array('id'=>12482, 'prev'=>1023, 'next'=>null);

无论他们开始的顺序是什么?好吧,这不会是一个基本的排序模式,所以我会选择像:

// Find the first entry
foreach($arr as $index => $row) {
  if ($row['prev'] == null) {
    // This is the first row
    $cur_row = $row;
    break; // Jump out of the foreach loop
  }
}
$sorted = array();
$sorted[] = $cur_row;
while ($cur_row['next'] != null) {
  // Find the next row
  foreach($arr as $index => $row) {
    if ($row['id'] = $cur_row['next']) {
      // This is the next row
      $sorted[] = $row;
      $cur_row = $row;
      break; // Jump out of the foreach loop
    }
  }
}
print_r($sorted); // $sorted now has your sorted array

答案 2 :(得分:1)

我会先将id作为数组键进行一轮。在录制第一个元素的同一时刻。

$newArray = array():
$firstElement = null;
foreach( $array as $row ) {
    $newArray[$row['id']] = $row;
    if( $row['prev'] == null ) $firstElement = $row['id'];
}

之后你可以像这样遍历列表:

$curId = $firstElement;
while($curId != null) {
    do_something($newArray[ $curId ])
    $curId = $newArray[ $curId ]['next'];
}

为了提高效率,您可能会考虑查看数据水槽(从数组中的数据库中获取数据的函数)来查看或者它可以将id作为array-key立即添加。您也可以使用查询排序顺序确保第一个元素始终是原始数组中的第一个元素,从而可以轻松找到该ID。

顺便说一句,不要将其称为链表实现,因为链表的特征是对下一个元素(不是索引)的对象引用。

编辑:有一点我还没提到。如果你想将排序列表放在一个数组中,那么替换do_something($ newArray [$ curId]); with $ array [] = $ newArray [$ curId];。

我相信这个解决方案比大多数其他解决方案更透明/更快,因为这会在整个阵列上花费两轮,或者如果你可以在没有成本的情况下将第一部分集成到水合方法中,只需要在阵列中进行一次迭代。

答案 3 :(得分:0)

我相信内置的usort可以很好地用于你描述的数据结构。

编辑:这不能正常工作。请取消接受,以便删除。

<?php
//$arr = your array as described

usort($arr, 'subkey_compare_next');

function subkey_compare_next($a, $b) {
    $a = $a['next'];
    $b = $b['next'];
    if($a === null) {
        return -1;
    }
    if ($a == $b) {
        return 0;
    }
    return ($a < $b) ? -1 : 1;

}
?>

答案 4 :(得分:0)

此代码可以使用

$a[0] = array('0', '00', '000');
$a[1] = array('1', '11', '111');
$a[2] = array('2', '22', '222');
$a[3] = array('3', '33', '333');
$a[4] = array('4', '44', '444');
$result = count($a);
echo $result; // print count


list ($result1, $result2, $result3) = $a[4]; // array to list
echo $result3; // print data in list
相关问题