Hej alla.
I denna anteckning har jag beslutat att lista de viktigaste datastrukturerna som anvÀnds för att lagra grafer inom datavetenskap, samt att jag Àven kommer att berÀtta om ett par andra sÄdana strukturer som av nÄgon anledning har "kristalliserats" fram för mig.
SĂ„, vi börjar. Men inte frĂ„n början â jag tror att vi alla redan vet vad en graf Ă€r och vilka typer som finns (riktade, oriktade, viktade, oviktade, med multipla kanter och slingor eller utan).
SÄ, lÄt oss köra. Vilka alternativ har vi dÄ för datastrukturer för "graflagring"?
1. Matristrukturer
1.1 NĂ€rliggande matris. En nĂ€rliggande matris Ă€r en matris dĂ€r rad- och kolumnrubrikerna motsvarar numren pĂ„ grafens noder, och vĂ€rdet för varje element a(i,j) bestĂ€ms av nĂ€rvaron eller frĂ„nvaron av kanter mellan noderna i och j (det Ă€r uppenbart att för en oriktad graf kommer en sĂ„dan matris att vara symmetrisk, eller sĂ„ kan vi komma överens om att vi endast lagrar vĂ€rden ovanför huvuddiagonalen). För oviktade grafer kan a(i,j) definieras som antalet kanter frĂ„n i till j (om det inte finns nĂ„gon sĂ„dan kant, dĂ„ a(i,j) = 0), och för viktade grafer Ă€r det ocksĂ„ â vikten (den totala vikten) av de nĂ€mnda kanterna.
1.2 Incidensmatris. I detta fall lagras vĂ„r graf ocksĂ„ i en tabell, dĂ€r radnumren vanligtvis motsvarar numren pĂ„ dess noder och kolumnnumren â förnumrerade kanter. Om en nod och en kant Ă€r incidenta mot varandra, skrivs ett icke-nollvĂ€rde in i den motsvarande cellen (för oriktade grafer skrivs 1 vid incident av noden och kanten; för riktade grafer skrivs "1" om kanten "gĂ„r ut" frĂ„n noden och "-1" om den "gĂ„r in" i den (det Ă€r ganska lĂ€tt att komma ihĂ„g, eftersom tecknet "minus" ocksĂ„ "gĂ„r in" i numret "-1")). För viktade grafer kan man Ă„terigen ange den totala vikten av kanten istĂ€llet för 1 och -1.
2. UpprÀknande datastrukturer
2.1 NÀrliggande lista. HÀr verkar det vara ganska enkelt. Till varje toppunkt i grafen kan man i allmÀnhet koppla en valfri upprÀkningsstruktur (lista, vektor, array, ...) dÀr nummer pÄ alla toppunkter som Àr angrÀnsande till den aktuella samlas. För riktade grafer kommer vi endast att lÀgga till de toppunkter i en sÄdan lista för vilka det finns en "riktad" kant frÄn den utvalda toppunkten. För vikta grafer kommer implementeringen att vara mer komplex.
2.2 Lista över kanter. En ganska populÀr datastruktur. En lista över kanter, som Kapten Upplysning pÄpekar, utgör faktiskt en lista över grafens kanter, dÀr var och en definieras av en starttoppunkt, en Àndtoppunkt (för icke-riktade grafer Àr ordningen hÀr oviktig, Àven om man för enhetlighet kan anvÀnda olika regler, till exempel ange toppunkterna i stigande ordning) och vikt (endast för vikta grafer).
För mer information om de upprÀknade listorna-matriserna kan man titta nÀrmare (och med illustrationer), till exempel .
2.3 NÀrliggande array. Inte den vanligaste strukturen. I grunden utgör den en form av "packning" av angrÀnsande listor i en enda upprÀkningsstruktur (array, vektor). De första n (enligt antalet toppunkter i grafen) elementen i denna array innehÄller startindex för samma array, frÄn vilken alla angrÀnsande toppunkter till den aktuella Àr listade i följd.
HÀr hittade jag den mest förstÄeliga (för mig) förklaringen:
3. NÀrliggande vektor och Associativ nÀrliggande array
Det visade sig att författaren till dessa rader, utan att vara en professionell programmerare, dock periodiskt har haft att göra med grafer, oftast har jobbat med kanlistor. Det Àr verkligen praktiskt om grafen har flera slinga och kanter. SÄ, i utvecklingen av klassiska kanlistor, vill jag Àgna uppmÀrksamhet Ät deras "utveckling/kvistande/modifiering/mutation", nÀmligen: nÀrliggande vektor och associativ nÀrliggande array.
3.1 NĂ€rliggande vektor
Fall (a1): oviktad graf
Vi kommer att kalla en nĂ€rliggande vektor för en oviktad graf en sorterad uppsĂ€ttning ett jĂ€mnt antal heltal (a[2i], a[2i+1], âŠ, dĂ€r i numreras frĂ„n 0), dĂ€r varje talpar a[2i], a[2i+1] definierar en kant i grafen mellan toppunkterna a[2i] och a[2i+1] respektive.
Detta inspelningsformat innehÄller inga uppgifter om huruvida grafen Àr riktad (bÄda varianterna Àr möjliga). NÀr formatet anvÀnds för en ortograf antas kanten vara riktad frÄn a[2i] till a[2i+1]. HÀr och framöver: för icke-riktade grafer kan, vid behov, krav pÄ ordning av vertexer tillÀmpas (till exempel sÄ att vertexen med det lÀgre tilldelade numret kommer först).
I C++ Àr det lÀmpligt att anvÀnda std::vector för att definiera nÀrliggande vektorer, dÀrav namnet pÄ denna datatyp.
Fall (a2): icke-vÀgd graf, kantvikter Àr heltal
I enlighet med fall (a1) kallas en nĂ€rliggande vektor för en vĂ€gd graf med heltalsvikter en ordnad uppsĂ€ttning (dynamisk array) av nummer (a[3i], a[3i+1], a[3i+2], âŠ, dĂ€r i numreras frĂ„n 0), dĂ€r varje "triplet" av nummer a[3i], a[3i+1], a[3i+2] anger en kant mellan vertexerna med numren a[3i] och a[3i+1], och vĂ€rdet a[3i+2] Ă€r vikten av denna kant. En sĂ„dan graf kan ocksĂ„ vara bĂ„de riktad och icke-riktad.
Fall (b): icke-vÀgd graf, kantvikter Àr icke-heltal
Eftersom man inte kan lagra heterogena element i en enda array (vektor) kan det exempelvis finnas följande implementering. Grafen lagras i ett par vektorer, dÀr den första vektorn Àr en nÀrliggande vektor för grafen utan att ange vikter, och den andra vektorn innehÄller motsvarande vikter (möjlig implementering för C++: std::pair). SÄledes, för en kant definierad av vertexpar under indexerna 2i, 2i+1 i den första vektorn, Àr vikten lika med elementet under index i i den andra vektorn.
Men varför behövs detta?
NÄvÀl, för författaren av dessa rader verkade detta vara ganska anvÀndbart för att lösa en rad problem. Ur ett formellt perspektiv finns det sÄdana fördelar hÀr:
- En nÀrliggande vektor, precis som vilken annan "upprÀkning" struktur som helst, Àr tillrÀckligt kompakt, tar mindre minne Àn en nÀrliggande matris (för glesa grafer), och Àr relativt enkelt att implementera.
- Vertexer i grafen kan i princip mÀrkas med negativa tal. Kanske kan sÄdana "avvikelser" behövas.
- Grafer kan innehÄlla multipla kanter och multipla loopar, Àven med olika vikter (positiva, negativa, till och med noll). Det finns inga begrÀnsningar hÀr.
- Och ribbor kan ocksĂ„ tilldelas olika egenskaper â men se punkt 4.
Det mÄste erkÀnnas att snabb Ätkomst till en kant inte Äsyftas av denna "listform". Och hÀr kommer den Associativa samarbetetsmatrisen till hjÀlp, vilket beskrivs nedan.
3.2 Associativ matris för samband
SĂ„, om Ă„tkomsten till en specifik kant, dess vikt och andra egenskaper Ă€r kritiska för oss, och minneskraven inte tillĂ„ter anvĂ€ndning av en sambandsmatris, lĂ„t oss tĂ€nka pĂ„ hur vi kan Ă€ndra sambandsvektorn för att lösa detta problem. SĂ„, nyckeln Ă€r kanten av grafen, som kan anges som ett ordnat par av hela tal. Vad liknar det hĂ€r? Ăr det inte en nyckel i en associativ matris? Om sĂ„ Ă€r fallet, varför inte implementera det? LĂ„t oss ha en sĂ„dan associativ matris dĂ€r varje nyckel â ett ordnat par av hela tal â motsvarar ett vĂ€rde â ett helt eller flyttal som anger vikten pĂ„ kanten. I C++ Ă€r det rimligt att implementera denna struktur baserat pĂ„ containern std::map (std::map <std::pair , int> eller std::map <std::pair , double>), eller std::multimap, om flera kanter förvĂ€ntas. SĂ„ hĂ€r, vi har fĂ„tt en struktur för att lagra grafer som tar upp mindre minne jĂ€mfört med "matrisstrukturer", kan representera grafer med flera loopar och kanter och har inte ens strikta krav pĂ„ icke-negativitet för vertices nummer (jag vet inte vem som behöver det, men Ă€ndĂ„).
4. Datatyper ska vara "fulla" men nÄgot saknas
Det Àr sant: vid lösning av en rad problem kan det uppstÄ behov av att tilldela grafrör nÄgot kÀnnetecken och dÀrmed lagra dem. Om dessa kÀnnetecken entydigt kan reduceras till hela tal, kan sÄdana "grafer med extra kÀnnetecken" lagras med hjÀlp av utvidgade versioner av sambandsvektor och associativa sambandsmatriser.
SĂ„, lĂ„t oss anta att vi har en oviktad graf, dĂ€r varje kant mĂ„ste lagra till exempel 2 ytterligare attribut, angivna med heltal. I det hĂ€r fallet kan vi definiera dess nĂ€rhetsvektor som en ordnad uppsĂ€ttning av inte "par", utan "kvartetter" av heltal (a[2i], a[2i+1], a[2i+2], a[2i+3]âŠ), dĂ€r a[2i+2] och a[2i+3] kommer att definiera egenskaperna för den aktuella kanten. För en graf med heltalsvikter Ă€r ordningen i stort sett densamma (skillnaden kommer att vara att egenskaperna kommer att följa efter kanten vikt och anges av elementen a[2i+3] och a[2i+4], och kanten kommer att definieras av inte 4 utan 5 ordnade heltal). För en graf med icke-heltalsvikter kan egenskaperna skrivas in i dess oviktade komponent.
Vid anvÀndning av en associativ nÀrhetsmatris för grafer med heltalsvikter Àr det möjligt att som vÀrde ange inte ett separat tal, utan en array (vektor) av tal som definierar, utöver kantens vikt, alla dess andra nödvÀndiga egenskaper. Denna situation innebÀr dock en nackdel för fallet med icke-heltalsvikter, dÄ det Àr nödvÀndigt att ange egenskapen som ett flyttal (ja, detta Àr en nackdel, men om det inte finns sÄ mÄnga sÄdana egenskaper, och om man inte gör dem för "kluriga" med double, kan det kanske gÄ bra). SÄledes kan utvidgade associativa nÀrhetsmatriser i C++ definieras som: std::map <std::pair , std::vector> eller std::map <std::pair , std::vector, dÀr det första vÀrdet i "vektorn-vÀrdet-för-nyckeln" kommer att vara vikten för kanten, och dÀrefter anges de numeriska beteckningarna för dess egenskaper.
Litteratur:
Om grafer och algoritmer i allmÀnhet:
1. Cormen, Thomas H., Leiserson, Charles E., Rivest, Ronald L., Stein, Clifford. Algoritmer: Konstruktion och analys, 2:a upplagan: Ăvers. frĂ„n engelska â Moskva: Förlagshuset "Williams", 2011.
2. Harari, Frank. Grafteori. Moskva: Mir, 1973.
Författarens rapport om just denna vektor och associativa nÀrhetsmatris:
3. ЧДŃĐœĐŸŃŃ
ĐŸĐČ S.A. Vektor för nĂ€rstĂ„ende och associativ matris som sĂ€tt att representera och lagra grafer / S.A. Chernouhov. NĂ€rstĂ„ende vektor och nĂ€rstĂ„ende karta som datatyper för att representera en graf // Samling av artiklar frĂ„n den internationella vetenskapligt-praktiska konferensen "Problem med implementering av resultat frĂ„n innovativa utvecklingar och vĂ€gar för att lösa dem" (Saratov, 14.09.2019). â Sterlitamak: AMI, 2019, s. 65-69
Nyttiga internetkÀllor i Àmnet:
4.
5.
KĂ€lla: habr.com
