Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: drzewo binarne - dodawanie wg poziomów
Forum PHP.pl > Forum > PHP
megasinski
Witam
Mam pewien problem
Stworzyłem w mysql tabelę do której chciałbym wstawiać rekordy w pewien określony sposób.
Ma to być hierarchia binarna, czyli drzewko z dwoma odnogami za każdym razem.

tabela posiada kolumny id, id_parent, right, left

Do tabeli mają być dodawane nowe rekordy w taki sposób, aby najpierw, niezależnie od tego jak aktualnie wygląda struktura, rozpoczynając od wybranego rekordu, najpierw sprawdzał pierwszy poziom pod wybranym rekordem i jeśli jest wolne miejsce to w pierwszej kolejności dodawał nowy rekord do prawej odnogi a jeśli ta jest zajęta, to do lewej. Jeśli natomiast w poziomie pierwszym nie ma już miejsca to przechodzi do poziomu drugiego itd.

To co do tej pory wykombinowałem to przynosiło taki efekt, że najpierw sprawdzał prawą odnogę, jeśli była wolna to dopisywał, jeśli nie to sprawdzał lewą i jeśli była wolna to dopisywał, a jeśli nie to wtedy wchodzi w poziom niżej i do tego miejsca było OK, ale dalej kiedy sprawdził rekord w drugim poziomie to juz nie przechodził do następnego rekordu w tym poziomie tylko szedł niżej w będącej już odnodze i praktycznie pomijał pozostałe rekordy w danym poziomie.

Chodzi mi o to, żeby najpierw sprawdził poziom 1 pod jakimś tam rekordem, jeśli jest pełny to wtedy poziom 2, jeśli ten jest pełny to przechodzi do poziomu 3 itd.
Czy da się coś takiego stworzyć w PHP? Jeśli tak to w jaki sposób?
Pomocy please.
Mam nadzieję, że nie zagmatwałem pytania.
timon27
Po piersze zrezygnuj z kolumny id_parent, bo jest zbędna i znacznie utrudnia procedury.
Zakładam, że id jest autoincrement.
Piszę od ręki, więc pewnie są błędy, ale chodzi o ideę

  1. function dodaj($id){
  2. $r=mysql_query("SELECT * FROM drzewo WHERE id=$id");
  3.  
  4. $right=mysql_result($r,0,'right');
  5. if($right!=NULL){//tego nie jestem pewien
  6. mysql_query("INSERT INTO drzewo VALUES ('',NULL,NULL)");
  7. }
  8.  
  9. $left=mysql_result($r,0,'right');
  10. if($left!=NULL){//tego nie jestem pewien
  11. mysql_query("INSERT INTO drzewo VALUES ('',NULL,NULL)");
  12. }
  13.  
  14. dodaj($right);//drzewo rozrasta się niesymetrycznie, ale o tym już nie było mowy
  15. }
com
http://pl1.php.net/mysql_result zraca FALSE czasem warto odwiedzić manual wink.gif

9 linijka zapewne
  1. $left=mysql_result($r,0,'left');
megasinski
Dzięki wielkie.
Jednak to dało efekt, który już osiągnąłem.
Może spróbuję inaczej to wytłumaczyć.

Powiedzmy, że wyjściowym ID jest 1, który ma pod sobą 2 i 3.
Jeżeli 2 nie ma nic pod sobą, to dodaje kolejne id do niej, czyli np 4.
Potem kolejne id byłoby 5.

To co uzyskałem poprzez Twoją funkcję daje efekt taki, że w dalszej kolejności nie przechodzi do 3, tylko dalej drąży w strukturze 2, czyli sprawdza 4, i nawet nie przechodzi do 5.

A ja chcę uzyskać taki efekt, żeby jeśli okaże się, że 2 ma już zajęte i right i left, to wtedy przechodzi do 3 i sprawdza czy jest pełna czy nie, jeśli tak, to dopiero wtedy przechodzi do 4, a następnie do 5 które to już są na kolejnym poziomie.

Np. na tym rysunku najpierw sprawdza 2, widzi że ona ma zajęte i prawy i lewy, to przechodzi do 3, tam widzi, że prawy jest zajęty , ale lewy wolny więc uzupełnia go numerem ID = 11, następny rekord będzie dodany już w kolejnym poziomie, gdzie sprawdzi 4, potem 5(gdzie doda 12), potem 6(gdzie doda 13) potem 11(lewy pod trójką, gdzie doda 14 i 15), następnie przechodzi niżej i tam wszystkie są puste, więc uzupełnia je po kolei począwszy od prawej.

Oczywiście dodawanie rekordów odbywa się tylko wówczas, kiedy sam chcę dodać kolejny rekord cool.gif

timon27
Czyli chcesz mieć jeden z góry określony porządek.
Proponuję: skasuj WSZYSTKIE kolumny poza id.
Przyjmij że: prawym dzieckiem pola o id "n" będzie 2*n, lewym 2*n+1.
Analogicznie rodzicem będzie [n/2].

I masz już gotową strukturę drzewa binarnego.

megasinski
Idea jest dobra...
tylko jeszcze jeden mały problem.
Powiedzmy, że niektóre odnogi zostaną rozwinięte (przez kogoś)tak jak np. 3-6-10 i jeśli chcę dodać losowo kolejny ID to chcę żeby uzupełnił pierwszy pusty na najbliższym poziomie, czyli w tym wypadku będzie to drugie ramię trójki i tam wejdzie 11.
W tym momencie nawet jeśli dodam to pole, to wywołanie rodzica będzie błędne no i w wielu przypadkach dziecka też.
timon27
Cytat(megasinski @ 14.09.2013, 17:30:28 ) *
Powiedzmy, że niektóre odnogi zostaną rozwinięte (przez kogoś)tak jak np. 3-6-10...

1. drzewo musi mieć na samym początku określony korzeń.
Czyli musi istnieć pole id=0, sytuacja 3-6-10 nie jest dopuszczalna
2. Systuacja 0-3-6-10 również nie jest dopuszczalna, bo 10 powinno być dzieckiem 5 której nie ma, więc już wcześniej ktoś coś namieszał z drzewem.

Generalnie zakładamy że drzewo ma poprawną strukturę.
Wtedy dodanie w najwyższym miejscu, najbardziej na lewo (tak jak chcesz) = dodanie pola o najmniejszym niewykorzystanym id.
Dodanie dziecka pola o id=n to stworzenie pola o id=2n (lewe) lub 2n+1 (prawe).
megasinski
no i właśnie o to chodzi, że jeśli jakaś noga rozrośnie się celowo w jakiś sposób, to jeśli kolejne działanie nie będzie celowe, ma szukać pierwszej wolnej i w tym wypadku co przedstawiono na rysunku pierwszą wolną jest 11 pod trójką.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.