PHP bağlantılı bir listeyi sıralamak nasıl?

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

Her kaydın sırası keyfi olabilir.

prev 's değer null ilk ve ile bir rekor null next böylece bu tür bir dizi sıralamak için nasıl son?

5 Cevap

Ben usort inşa açıklandığı veri yapısı için güzel işe yarayacağına inanıyorum.

edit: Bu düzgün çalışmıyor. Bu yüzden silebilirsiniz un-kabul edin.

<?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;

}
?>

Bir dizi bağlantılı listesi için not bir kaptır. A linked list is a list with linked ilişkileri nesneler ile bir liste, değil nesneleri. Temelde, ne var iki kapların en kötüsü. Ben diğer bazı veriler kabın içine yapısını dönüştürmek için denemek istiyorum; Gerçek bir bağlantılı liste verilerinizi sıralamak gerekirse şekilde sıralanması gerekiyor asla.

Iyi bir şekilde böyle bir şey içerecektir. Sana listenin ortasında nesneleri eklemek için yol bırakacağım, o kadar da zor değil.

<?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"
?>

Bazı okült nedenle gerçekten, gerçekten onları bir diziye ihtiyacınız varsa, burada ihtiyacınız ne olduğunu:

<?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));
?>

Ama gerçekten, kendinize bir iyilik yapın ve gerçek bir bağlantılı liste yapmak, nesneleri değil, dizileri kullanarak. Yukarıdaki sıralama yöntemi, benim görüşüme göre, kısıtlamaları bilerek oldukça iyi olduğunu, ancak her id için dizi aramak gerekiyor çünkü ridiculously slow bulunuyor.

Hmm, sen gibi bir şey içine dizisini almak istiyorum böylece:

$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);

olursa olsun, onlar ne başladı sipariş? Eh, bu da temel bir çeşit model olmayacak, bu yüzden gibi bir şey ile gitmek istiyorum:

// 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

Ben dizi anahtarları olarak id koyarak ilk turda yapardı. Ilk öğe kaydı aynı anda.

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

Bundan sonra bu gibi liste üzerinde yineleme yapabilirsiniz:

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

Verimlilik için görmek ya da inmediately dizi-anahtar olarak id ekleyebilir veri hidratörün de (dizi veritabanından veri var olsun fonksiyonunu) bakarak düşünüyor olabilir. Ayrıca sorgu sıralama düzeni ile ilk elemanı bu kadar kolay id bulmak için yapım, her zaman orijinal dizideki ilk unsurdur emin olabilir.

Bağlantılı liste sonraki elemanına (değil bir indeks) bir nesne referans ile karakterizedir gibi Btw, bir LinkedList uygulama bu demiyorlar.

Düzenleme: Ben henüz bahsetmedim bir şey. Eğer bir dizi sıralanmış listesini sahip olmak istiyorsanız, o zaman ($ yeni_dizi [$ curId]) do_something değiştirin; $ dizi [] = $ yeni_dizi [$ curId] ile;.

Ben bu tüm dizi üzerinde iki tur mal oluyor gibi, ya da maliyet olmadan hidrasyon yöntemi ilk bölümünü entegre eğer bu çözüm çok daha şeffaf / hızlı çoğu diğer çözümlerden daha sonra inanıyorum, dizi aracılığıyla tek yineleme.

Bu kod çalışır

$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