tania reprezentacja grafu C++

0

Witam,
Możecie zaproponować mi jakąś tanią (w sensie pamięciożerności) reprezentację grafu ?
Graf może mieć pętle, krawędzie wielokrotne. Jest skierowany.
Zwykłe vector <int> G[N] odpada - za ciężkie jak na warunki zadania.

LU
  • Rejestracja:około 12 lat
  • Ostatnio:ponad 7 lat
0

Według mnie najlepiej na liście sąsiedztwa

0

A jak coś takiego napisać efektywnie i elegancko ?

LU
Dragon wszystko Ci pięknie opisał ;)
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
1

Jeżeli ilość krawędzi jest mała w stosunku do możliwej ilości krawędzi to lista sąsiedztwa:

Kopiuj
struct Edge { size_t from,to; double weight; };
list<Edge> LS;

Jeżeli duża to macierz sąsiedztwa:

Kopiuj
vector<vector<list<double> > > MS(NodeCount,vector<list<double> >(NodeCount));

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
edytowany 1x, ostatnio: _13th_Dragon
0

Witam.
Możesz też zaglądnąć do źródeł otwartych bibliotek grafowych. W którejś widziałem chyba takie rozwiązanie:

  • liczba wierzchołków
  • tablica o długości równej liczbie wierzchołków, przechowująca indeks ostatniej krawędzi wychodzącej z wierzchołka
  • tablica o długości równej liczbie krawędzi, przechowująca indeks wierzchołka do którego prowadzi krawędź
    Można sporo zaoszczędzić, zwłaszcza jeśli indeksy wierzchołków i/lub krawędzi mogą być mniejsze od wskaźnika. Graf nie jest też rozsiany po pamięci. Problemem jest jednak wydajne modyfikowanie takiego grafu, chyba że chodzi o stworzenie poprzez dodawanie kolejnych wierzchołków (których ilość też dobrze aby byłą znana z góry), wraz z wychodzącymi z nich krawędziami. Napisz jakie operacje chcesz wykonywać na tym grafie, to może uda się jakoś lepiej pomóc.
0

Chciałbym móc budować dynamiczne ten graf. Tzn wiem ile będzie maxymalnie krawędzi i werzchołków(wierzchołków milion, tyle samo krawędzi)
Graf skierowany - wszystkie krawędzie dozwolone. Dynamicznie, czyli dodając po krawędzi (losowa kolejność).
Ile by mniej więcej ważył Twój graf?
Chciałbym też ten graf przechodzić DFSem i BFSem.

0
maturzysta2013 napisał(a):

Chciałbym móc budować dynamiczne ten graf. Tzn wiem ile będzie maksymalnie krawędzi i werzchołków(wierzchołków milion, tyle samo krawędzi)
Graf skierowany - wszystkie krawędzie dozwolone. Dynamicznie, czyli dodając po krawędzi (losowa kolejność).

Nie znam wydajnego sposobu budowania tej struktury jeśli krawędzie nie są posortowane po wierzchołku źródłowym. Jeśli jesteś zainteresowany mogę spróbować poszukać biblioteki, które jej używała, może tam znalazło by się jakieś rozwiązanie.

Ile by mniej więcej ważył Twój graf?

(liczba_wierzchołków + 1) * rozmiar_indeksu_dla_wierzchołka + liczba_krawędzi * rozmiar_indeksu_dla krawędzi
Skoro milion, można użyć indeksów 4 bajtowych, więc około 8MB.
Można też kosztem wydajności i skomplikowania upychać liczby na 20 bitach co dało by około 5MB.

Chciałbym też ten graf przechodzić DFSem i BFSem.

Do tego nadaje się dobrze, ale musisz doliczyć jeszcze miejsce na atrybuty, można je trzymać w kolejnych tablicach, lub jeśli nie upychał być wszystkiego na 20 bitach upchnąć na niewykorzystanych bitach wierzchołków i krawędzi.

Skoro miejsce na poprzedników jest potrzebne po wczytaniu grafu, to można na początku wczytywać do niej wierzchołki źródłowe, a później posortować tą tablice, przemieszczając jednocześnie dane w tablicy wierzchołków docelowych, następnie na jej podstawie zbudować tablicę z liczbą krawędzi wychodzących z danego wierzchołka i problem wydajnego wczytywania rozwiązany.
Równa ilość wierzchołków i krawędzi może sugerować, że autorzy zadania chcieli ułatwić implementacje czegoś takiego:)

0

A jak można to upychać na 20 bitach ?

JS
  • Rejestracja:około 14 lat
  • Ostatnio:około miesiąc
  • Postów:417
0

Wykorzystujesz pola bitowe: http://4programmers.net/C/Pola_bitowe

0

A to będzie trudne takie korzystanie z tych pól bitowych ?

LU
Wszystko to kwestia Twojej pracy i zrozumienia problemu :)
0

No ok.
Ale czemu sizeof zwraca ten sam rozmiar dla:
struct T{
int T;
int Q;
}
T[10^6]
struct O{
int T:20;
int W:20;
}
O [10^6]

Jaka jest przyczyna, że sizeof(T) = sizeof(O) ?

DU
dopelnienie całej struktury do wilokrotnosci 8 bitów lub 16, lub 32 zalezy na jaka maszynę kompilujesz.
IE
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 7 lat
  • Postów:32
0

Pakowanie pól bitowych w pamięci jest zależne od kompilatora (niestety). Jeśli chcesz mieć maksymalną możliwą oszczędność to musisz ręcznie wyciągać z pamięci co Cię interesuje.

0

W takim razie można coś zdziałać tymi polami bitowymi czy nie ?

JS
  • Rejestracja:około 14 lat
  • Ostatnio:około miesiąc
  • Postów:417
0

Ja kiedyś przepchałem jedno zadanie dzięki użyciu pól bitowych, a kompilator na sprawdzarce to był g++, a taki jest w sumie na każdym automatycznym serwisie sprawdzającym, więc można - próbuj.

edytowany 1x, ostatnio: JumpSmerf
0

Rozmiar pojedynczego elementu tablicy (struktura) bedzie wyrownany do wielokrotnosci inta niezaleznie od struktury pol bitowych. Absolutne minimum to wyrownanie do bajtow, chyba nie wyobrazacie sobie umieszczenia obiektu pod adresem XYZ i 5/8?

0
maturzysta2013 napisał(a):

A jak można to upychać na 20 bitach ?

Operować nie na tablicy liczb, tylko na tablicy bajtów, używać przesunięć bitowych tam gdzie bajty nie są równe, tak aby rozłożyć je w pamięci co 20 bitów, czyli 2,5 bajta. Łatwiej będzie jeśli można na każdy indeks poświęcić całe 3 bajty, ewentualnie rozbijając na dwie tablice (16+8). Można opakować sobie w klasę z przeciążonym operatorem[] , to nawet by się wygodnie tym operowało.

W ile pamięci musisz się zmieścić? Czy limit przekracza już sama struktura, czy razem z innymi danymi (atrybuty, itp.)? Może lepiej poszukać pamięci gdzie indziej? Takie upakowanie danych może bardzo negatywnie wpłynąć na wydajność.

0

W takim razie zrobię to wszystko inaczej, skoro tak nie idzie.

_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
0

Rozmiar każdej struktury jest dobijany do pewnego ustalonego rozmiaru najczęściej to rozmiar int'a (jest nieco bardziej skomplikowane, poczytaj o data allignment).
Czyli struct BF { int A:16; int B:16; }; już będzie miała mniejszy rozmiar.
Dynamicznie dobrze zadziała pierwsza struktura którą podałem.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
0

Struktura przechowująca indeksy wierzchołków źródłowych i docelowych będzie zajmowała tyle samo pamięci w przypadku gdy liczba wierzchołków jest równa liczbie krawędzi, jeśli przechowywane będą w tablicy, a nie liście. Problemem będzie jednak wydajne pobranie listy sąsiadów celem przeszukania grafu.

_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
1
witold napisał(a):

Struktura przechowująca indeksy wierzchołków źródłowych i docelowych będzie zajmowała tyle samo pamięci w przypadku gdy liczba wierzchołków jest równa liczbie krawędzi, jeśli przechowywane będą w tablicy, a nie liście.
Chrzani waść.
Załóżmy że mamy 3 wierzchołki oraz 3 krawędzi. W macierze mamy 33sizeof(Value) w liście mamy 3*(2sizeof(Index)+sizeof(Value))
Dla index'u 32 bitowego zaś Value typu double mamy:
Macierz: 3
38=72
Lista: 3
(2*4+8)=48
Przy większych ilościach wierzchołków różnica będzie jeszcze większa.

witold napisał(a):

Problemem będzie jednak wydajne pobranie listy sąsiadów celem przeszukania grafu.
Nigdy nie było to problemem, chyba że beznadziejnie zorganizowany graf, np wybrano macierz sąsiedztwa.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
0
_13th_Dragon napisał(a):

Załóżmy że mamy 3 wierzchołki oraz 3 krawędzi. W macierze mamy 33sizeof(Value)

Nie pisałem nic o macierzy sąsiedztwa.

_13th_Dragon napisał(a):

w liście mamy 3*(2*sizeof(Index)+sizeof(Value))

Tyle mamy w tablicy, w liście mamy jeszcze wskaźniki na poprzednie i następne elementy. O tej różnicy właśnie pisałem.

witold napisał(a):

Problemem będzie jednak wydajne pobranie listy sąsiadów celem przeszukania grafu.
Nigdy nie było to problemem, chyba że beznadziejnie zorganizowany graf, np wybrano macierz sąsiedztwa.</quote>
W strukturze którą podałeś, dostęp do listy sąsiadów danego wierzchołka wymaga wyszukania ich na podstawie wartości pola source, co jest niepotrzebnym narzutem którego można by uniknąć wybierając strukturę lepiej dostosowaną do takiej operacji.
W takim razie zostaje mi założyć, że nie jest problemem zaimplementowanie BFS i DFS bez iterowania po sąsiadach danego wierzchołka. Czy mógłbyś podzielić się rozwiązaniem?

_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
0

Problem w tym że ja odpowiadam na pytanie: - "... tanią (w sensie pamięciożerności) reprezentację grafu ..."
A u ciebie na myśli efektywność wykorzystania, dla tego się nie rozumiemy.
Czasami ma sens w jednym programie wykorzystywać kilka różnych reprezentacji.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)