Czy ktoś może mi w prosty sposób wyjaśnić, czym jest skierowany graf acykliczny? Zajrzałem do Wikipedii, ale tak naprawdę nie widzę jej zastosowania w programowaniu.
directed-acyclic-graphs
appshare.co
źródło
źródło
Odpowiedzi:
kropki z liniami wskazującymi na inne kropki
źródło
graf = struktura składająca się z węzłów połączonych ze sobą krawędziami
skierowane = połączenia między węzłami (krawędziami) mają kierunek: A -> B to nie to samo co B -> A
acyclic = "non-circle" = przejście od węzła do węzła przez podążanie za krawędziami, nigdy nie napotkasz tego samego węzła po raz drugi.
Dobrym przykładem skierowanego grafu acyklicznego jest drzewo. Należy jednak pamiętać, że nie wszystkie skierowane grafy acykliczne są drzewami.
źródło
Widzę wiele odpowiedzi wskazujących na znaczenie DAG (Directed Acyclic Graph), ale nie ma odpowiedzi na temat jego zastosowań. Oto bardzo prosty -
Wykres wymagań wstępnych - podczas kursu inżynierskiego każdy student ma za zadanie wybrać przedmioty zgodne z wymaganiami, takimi jak wymagania wstępne. Teraz jest jasne, że nie możesz brać udziału w zajęciach ze sztucznej inteligencji [B] bez wymaganego kursu z algorytmów [A]. Stąd B zależy od A lub, mówiąc lepiej, A ma krawędź skierowaną do B. Tak więc, aby dotrzeć do Węzła B, musisz odwiedzić Węzeł A. Wkrótce okaże się, że po dodaniu wszystkich przedmiotów z ich wymaganiami wstępnymi do wykresu okaże się, że jest to ukierunkowany graf acykliczny.
System oprogramowania na uniwersytecie, który umożliwia studentom rejestrowanie się na kursy, może modelować przedmioty jako węzły, aby upewnić się, że student ukończył wymagany kurs przed zarejestrowaniem się na bieżący kurs.
Mój profesor podał tę analogię i najlepiej pomogło mi to zrozumieć DAG, zamiast używać skomplikowanej koncepcji!
Inny przykład czasu rzeczywistego -> Przykład czasu rzeczywistego pokazujący, jak DAG mogą być używane w systemie wersji
źródło
Przykładowe zastosowania skierowanego grafu acyklicznego w programowaniu obejmują mniej więcej wszystko, co reprezentuje łączność i przyczynowość.
Na przykład załóżmy, że masz potok obliczeniowy, który można konfigurować w czasie wykonywania. Jako przykład załóżmy, że obliczenia A, B, C, D, E, F i G zależą od siebie: A zależy od C, C zależy od E i F, B zależy od D i E, a D zależy od F. Można to przedstawić jako DAG. Gdy masz już DAG w pamięci, możesz pisać algorytmy do:
wśród wielu innych rzeczy.
Poza dziedziną programowania aplikacji każde przyzwoite automatyczne narzędzie do kompilacji (make, ant, scons itp.) Będzie używać DAG, aby zapewnić właściwą kolejność kompilacji komponentów programu.
źródło
W kilku odpowiedziach podano przykłady użycia wykresów (np. Modelowanie sieci), a Ty zapytałeś „co to ma wspólnego z programowaniem?”.
Odpowiedź na to pod-pytanie brzmi, że nie ma ono wiele wspólnego z programowaniem. Ma to związek z rozwiązywaniem problemów.
Podobnie jak listy połączone są strukturami danych używanymi do określonych klas problemów, wykresy są przydatne do przedstawiania pewnych relacji. Połączone listy, drzewa, wykresy i inne abstrakcyjne struktury mają połączenie z programowaniem, ponieważ można je zaimplementować w kodzie. Istnieją na wyższym poziomie abstrakcji. Nie chodzi o programowanie, chodzi o zastosowanie struktur danych w rozwiązywaniu problemów.
źródło
Skierowane grafy acykliczne (DAG) mają następujące właściwości, które odróżniają je od innych grafów:
Cóż, w tej chwili przychodzi mi do głowy jedno zastosowanie - DAG (znane jako Wait-For-Graphs - więcej szczegółów technicznych ) są przydatne w wykrywaniu zakleszczeń, ponieważ ilustrują zależności między zestawem procesów i zasobów (oba są węzłami w DAG) . Zakleszczenie nastąpiłoby po wykryciu cyklu.
źródło
Zakładam, że znasz już podstawową terminologię dotyczącą grafów; w przeciwnym razie zacznij od artykułu o teorii grafów .
Skierowane odnosi się do faktu, że krawędzie (połączenia) mają kierunki. Na schemacie kierunki te są pokazane strzałkami. Przeciwieństwem jest wykres niekierowany, którego krawędzie nie określają kierunków.
Acykliczny oznacza, że jeśli zaczniesz od dowolnego węzła X i przejdziesz przez wszystkie możliwe krawędzie, nie możesz wrócić do X bez powrotu do już używanej krawędzi.
Kilka zastosowań:
źródło
DAG to wykres, na którym wszystko płynie w tym samym kierunku i żaden węzeł nie może odwoływać się z powrotem do siebie.
Pomyśl o drzewach przodków; są w rzeczywistości DAGami.
Wszystkie DAG mają
DAG różnią się od drzew. W strukturze przypominającej drzewo musi istnieć unikalna ścieżka między każdymi dwoma węzłami. W DAG węzeł może mieć dwa węzły nadrzędne.
Oto dobry artykuł o DAGach . Mam nadzieję że to pomogło.
źródło
Wszelkiego rodzaju wykresy są używane w programowaniu do modelowania różnych relacji w świecie rzeczywistym. Na przykład sieć społecznościowa jest często reprezentowana przez wykres (w tym przypadku cykliczny). Podobnie topologie sieci, drzewa genealogiczne, trasy lotnicze, ...
źródło
Z perspektywy kodu źródłowego lub nawet kodu trzech adresów (TAC) możesz bardzo łatwo zwizualizować problem na tej stronie ...
http://cgm.cs.mcgill.ca/~hagha/topic30/topic30.html#Exptree
Jeśli przejdziesz do sekcji drzewa wyrażeń, a następnie przewiniesz nieco w dół, zobaczysz „sortowanie topologiczne” drzewa i algorytm oceny wyrażenia.
W takim przypadku możesz użyć DAG do oceny wyrażeń, co jest przydatne, ponieważ ocena jest normalnie interpretowana, a użycie takiego ewaluatora DAG przyspieszy w zasadzie prostą interpretację, ponieważ nie jest to wypychanie i wyskakiwanie na stos, a także dlatego, że eliminuje wspólne wyrażenia podrzędne.
Podstawowy algorytm obliczania DAG w języku innym niż starożytny egipski (tj. Angielski) jest następujący:
1) Zrób swój obiekt DAG w ten sposób
Potrzebujesz listy na żywo, a ta lista zawiera wszystkie bieżące węzły DAG na żywo i wyrażenia podrzędne DAG. Wyrażenie podrzędne DAG jest węzłem DAG lub można je również nazwać węzłem wewnętrznym. Przez węzeł DAG na żywo mam na myśli to, że jeśli przypiszesz do zmiennej X, stanie się ona aktywna. Typowe wyrażenie podrzędne, które następnie używa X, używa tego wystąpienia. Jeśli X zostanie ponownie przypisany do, wówczas tworzony jest NOWY WĘZEŁ DAG i dodawany do aktualnej listy, a stary X jest usuwany, więc następne wyrażenie podrzędne, które używa X, będzie odnosić się do nowej instancji i nie będzie kolidować z wyrażeniami podrzędnymi, które wystarczy użyć tej samej nazwy zmiennej.
Po przypisaniu do zmiennej X, przypadkowo wszystkie węzły wyrażenia podrzędnego DAG, które są aktywne w momencie przypisania, stają się nieaktywne, ponieważ nowe przypisanie unieważnia znaczenie wyrażeń podrzędnych używających starej wartości.
Więc to, co robisz, to przechodzenie przez drzewo we własnym kodzie, takim jak na przykład drzewo wyrażeń w kodzie źródłowym. Na przykład wywołaj istniejące węzły XNodes.
Więc dla każdego XNode musisz zdecydować, jak dodać go do DAG i istnieje możliwość, że jest już w DAG.
To bardzo prosty pseudokod. Nie jest przeznaczony do kompilacji.
Więc to jest jeden sposób patrzenia na to. Podstawowy spacer po drzewie i po prostu dodawanie i odwoływanie się do węzłów Dag na bieżąco. Korzeń dag jest tym, co DagNode zwraca korzeń drzewa, na przykład.
Oczywiście przykładowa procedura może być podzielona na mniejsze części lub utworzona jako podklasy z funkcjami wirtualnymi.
Jeśli chodzi o sortowanie Dag, przechodzisz przez każdy DagNode od lewej do prawej. Innymi słowy, podążaj za lewą krawędzią DagNodes, a następnie za prawą krawędzią boczną. Numery są przypisywane odwrotnie. Innymi słowy, kiedy osiągniesz DagNode bez dzieci, przypisz temu węzłowi bieżący numer sortowania i zwiększ numer sortowania, aby rekurencja rozwinęła liczby przypisane w kolejności rosnącej.
Ten przykład obsługuje tylko drzewa z węzłami, które mają zero lub dwoje dzieci. Oczywiście niektóre drzewa mają węzły z więcej niż dwojgiem dzieci, więc logika jest nadal taka sama. Zamiast obliczać od lewej do prawej, obliczaj od lewej do prawej itd.
źródło
Jeśli wiesz, jakie drzewa są w programowaniu, wtedy DAG w programowaniu są podobne, ale pozwalają węzłowi mieć więcej niż jednego rodzica. Może to być przydatne, gdy chcesz, aby węzeł znajdował się pod czymś więcej niż tylko jednym rodzicem, ale nie masz problemu z zawiązanym bałaganem na ogólnym wykresie z cyklami. Nadal możesz łatwo nawigować po DAG, ale istnieje wiele sposobów, aby wrócić do katalogu głównego (ponieważ może być więcej niż jeden rodzic). Pojedynczy DAG może generalnie mieć wiele korzeni, ale w praktyce lepiej jest trzymać się jednego korzenia, jak drzewo. Jeśli rozumiesz dziedziczenie pojedyncze i wielokrotne w OOP, znasz drzewo kontra DAG. Odpowiedziałem już na to tutaj .
źródło
Nazwa mówi ci większość tego, co powinieneś wiedzieć o jego definicji: jest to wykres, na którym każda krawędź płynie tylko w jednym kierunku, a kiedy zejdziesz po krawędzi, twoja ścieżka nigdy nie wróci do wierzchołka, który właśnie opuściłeś.
Nie mogę mówić o wszystkich zastosowaniach (Wikipedia pomaga w tym), ale dla mnie DAG są niezwykle przydatne przy określaniu zależności między zasobami. Na przykład mój silnik gry reprezentuje wszystkie załadowane zasoby (materiały, tekstury, shadery, zwykły tekst, przeanalizowany plik JSON itp.) Jako pojedynczy DAG. Przykład:
Materiał to programy N GL, z których każdy potrzebuje dwóch shaderów, a każdy shader potrzebuje źródła shadera w postaci zwykłego tekstu. Reprezentując te zasoby jako DAG, mogę łatwo przeszukiwać wykres pod kątem istniejących zasobów, aby uniknąć podwójnych obciążeń. Załóżmy, że chcesz, aby kilka materiałów korzystało z programów do cieniowania wierzchołków z tym samym kodem źródłowym. Ponowne ładowanie źródła i rekompilowanie shaderów do każdego użycia jest marnotrawstwem, gdy można po prostu ustanowić nową przewagę istniejącego zasobu. W ten sposób możesz również użyć wykresu, aby określić, czy cokolwiek zależy od zasobu, a jeśli nie, usunąć go i zwolnić pamięć, w rzeczywistości dzieje się to prawie automatycznie.
W związku z tym DAG są przydatne do wyrażania potoków przetwarzania danych. Acykliczny charakter oznacza, że możesz bezpiecznie pisać kod przetwarzania kontekstowego, który może podążać za wskaźnikami w dół po krawędziach od wierzchołka, bez ponownego napotkania tego samego wierzchołka. Wizualne języki programowania, takie jak VVVV , Max MSP lub interfejsy oparte na węzłach Autodesk Maya, opierają się na DAG.
źródło
Skierowany graf acykliczny jest przydatny, gdy chcesz przedstawić ... skierowany graf acykliczny! Przykładem kanonicznym jest drzewo genealogiczne lub genealogia.
źródło