2010-02-07 15 views
5

Mam strukturę wykresu w C i chcę wykonać jej głęboką kopię (w tym węzły i krawędzie).Głęboka kopia struktury wykresu

struktura wygląda następująco:

struct li_list { 
    struct li_node n; 
}; 

struct li_node { 
    struct li_node *next, *prev; 
}; 

struct gr_graph { 
    struct li_list nodes; 
    int nodecount; 
}; 

struct gr_node { 
    struct li_node node; 
    struct gr_graph *graph; 
    int pred_count, succ_count; 
    struct li_list pred, succ; 
}; 

struct gr_edge { 
    struct li_node succ, pred; 
    struct gr_node *from, *to; 
    unsigned long marks; 
}; 

te kodowanym nie istnieją jako siebie, ale „dziedziczona” w innej struktury, tak:

struct ex_node { 
    struct gr_node _; // "Superclass" 
    int id; 
    struct ex_node *union_find_parent; 
    ... 
} 

Czy istnieje eleganckie rozwiązanie tworzenie głębokiej kopii takiej struktury, w tym aktualizowanie odniesień do kopii?

Uwaga: Członkowie zagnieżdżonych kodowanym nie wskazują na struktury korzenia zawiera, ale ich powiązanej zagnieżdżonej struktury (np ex_node._.pred.n.next wskazuje na ex_edge._.pred). Oznacza to arytmetykę żmudnego wskaźnika, gdy trzeba je zaktualizować.

Moje rozwiązanie do tej pory jest

  1. Memcopy wszystkie kodowanym
  2. iterację wszystkich kopiach
  3. połączeń grono makr dla wszystkich pól, które zawierają odniesienia (Z powodu braku RTTI w C, pewnie nie przyjdzie około tego)
  4. makra używać
    • offsetof obliczyć adres struktury korzenia
    • Odzyskaj adres skopiowany odpowiednik
    • offsetof aby punkt wskaźnik do prawidłowego zagnieżdżonej struktury

Czy istnieje łatwiejszy sposób to zrobić? Obawiam się również, że zapomniałem dodać makro, gdy dodam więcej pól.

Odpowiedz

1

Nie sądzę, że można zrobić głęboki egzemplarz per se, ponieważ wskaźniki będą miały adres pamięci przypisany do wskaźników, najlepszym sposobem, w jaki mogę myśleć o głębokiej kopii jest po prostu przydzielenie nowego wykresu strukturyzuj i kopiuj dane (nie wskaźniki) i stwórz je stamtąd przez malloc nowych wskaźników i dopasuj wskaźniki w strukturze ex_node. To byłoby bardziej szczegółowe rozwiązanie ...

Mam nadzieję, że to pomoże, Pozdrawiam, Tom.

+0

Jak to jest lepsze niż rozwiązanie, które przedstawiłem? – Meinersbur

+0

@Meinersbur: Myślałem, że "offsetof" ma na celu oszacowanie przesunięcia w bajtach do elementu struktury i zwrócenie liczby bajtów jako wartości size_t, więc nie jestem pewien, czy użycie przesunięcia jest sposobem, aby to zrobić .. .przy okazji, nie zgadzałem się z twoim rozwiązaniem, moją odpowiedzią jest abstrakcyjny widok tego, co robisz ... – t0mm13b

1

Brzmi ok. My $ ,02:

  • Nie wiem, dlaczego trzeba zarówno li_list i li_node. Co więcej, nie potrzebujesz członka danych dla li_node?
  • Ogólna struktura wygląda nieco skomplikowane (oczywiście, nie wiem swoje wymagania) i pachnie C++ styl projektowania (pardon, jeśli się mylę)
  • memcpy nie jest wymagane. Wystarczy proste zadanie.
  • Definiowanie elementu wskaźnik funkcji dla każdej struktury z członkami wskaźnik, tak że można zrobić:

Więc:

struct foo { 
    int datum; 
    int *p; 
    foo_copy pfoo; 
}; 

typedef void (*foo_copy)(const struct foo *src, struct foo *dst); 

void foo_cp(const struct foo *src, struct foo *dst) 
{ 
    *dst = *src; // copy non-pointer data 
    dst->p = malloc(sizeof *dst->p); 
    dst->p = *src->p; 
} 


// somewhere else 
struct foo s; 
// initalize 
struct foo *t = malloc(sizeof *t); 
s.copy(&s, &t); 

i zagnieżdżone typy wywołać odpowiednie metody członkiem kopiowania ...

+0

'li_list' jest" kontenerem "' li_node', 'n' jest wartownikiem # ## li_list, gr_graph pochodzą z biblioteki; tylko ex_ * jest przeze mnie. Jest przeznaczony do użycia w ten sposób. Technika jest opisana tutaj: http://stackoverflow.com/questions/326202/generic-list-manipulation-function-in-c#327665 ### Twoje rozwiązanie działa tylko dla drzew, a nie dla wykresów. – Meinersbur

+0

@Meinersbur: Masz na myśli cykle? – dirkgently

+0

Nie tylko cykle, ale również DAG: elementy, do których odwołujemy się dwukrotnie, byłyby kopiowane dwukrotnie. – Meinersbur

1

zapisz wszystkie struktury i utwórz posortowaną listę, w której każdy wpis zawiera adres oryginalnej struktury i adres kopii struktury.

Teraz przejrzyj wszystkie kopie. Dla każdego wskaźnika zmienne we wszystkich skopiowanych strukturach wyszukaj wskaźnik na posortowanej liście i zastąp go adresem jego kopii.

+0

Mam o wiele prostsze rozwiązanie tego problemu (co jest dla mnie wystarczające): Każdy 'ex_ *' ma członka 'copy', gdzie przechowuje referencję do kopii. Kiedy mam odniesienie do oryginału, mam także odnośnik do kopii, bez konieczności wyszukiwania (sortowania) listy. – Meinersbur

+0

Dla struktur zdefiniowanych dla ciebie to działa. Ale weź struktury dostarczone przez bibliotekę. Załóżmy, że nie ma bezpośredniego odniesienia do twoich zdefiniowanych struktur? W takim przypadku musisz przechowywać gdzieś odniesienie do kopii takich struktur. –

0

Tak, istnieje eleganckie rozwiązanie wykorzystujące drzewa opasujące i wzór dekoratora.

-Pierwsze, zbuduj drzewo opinające wykres. Możesz użyć DFS (Głębokie pierwsze wyszukiwanie) lub BFS (pierwsze wyszukiwanie szerokości), aby to osiągnąć. Użyj wzoru dekoratora, aby każdy z odwiedzonych węzłów miał niepowtarzalny identyfikator.

-Dalej (lub w tym samym czasie) przemierzać drzewo rozpinające od początku do końca i rozpocząć budowanie swojego drugiego drzewa poprzez przydzielenie nowych węzłów i podłączenie krawędzie, które tworzą drzewa rozpinającego.

-Wreszcie, jeszcze jeden przechodzą przez drzewa rozpinającego, a za pomocą zsynchronizowanych identyfikatory, podłącz pozostałe brakujące krawędzie w nowym wykresie, tak aby dopasować łączność starego wykresu. (np. Jeśli węzeł5 na wykresie 1 ma krawędzie łączące się z węzłem 7 i węzłem 11, wówczas korzysta z kolejności wykresu 2 do połączenia węzła5 z węzłem7 i 11.)