Syvä sukellus grafiikan kulkemiseen

Maailmanlaajuisesti aktiivisia Facebook-käyttäjiä on yli 2,07 miljardia kuukaudessa ympäri maailmaa vuoden 2017 kolmannella neljänneksellä. Tärkein Facebook-verkon osa on käyttäjien välinen sosiaalinen sitoutuminen. Mitä enemmän ystäviä käyttäjällä on, sitä mielenkiintoisimmista keskusteluista tulee viesteihin liittyviä kommentteja, viestejä jne. Jos olet käyttänyt Facebookia melko säännöllisesti, sinun on tiedettävä ystäväsuositusominaisuudesta.

Facebook suosittelee joukko ihmisiä, jotka voimme lisätä ystävinä. Useimmiten nämä ovat ihmisiä, joista emme ole koskaan kuulleet aiemmin. Mutta silti Facebook ajattelee, että meidän pitäisi lisätä ne. Kysymys kuuluu: kuinka Facebook keksii joukon suosituksia tietylle henkilölle?

Yksi tapa tehdä tämä perustuu keskinäisiin ystäviin. Esimerkiksi: - Jos käyttäjä A ja C eivät tunne toisiaan, mutta heillä on yhteinen ystävä B, niin todennäköisesti A: n ja C: n pitäisi olla myös ystäviä. Entä jos A: lla ja C: llä on 2 keskinäistä ystävää ja A: lla ja D: llä on 3 keskinäistä ystävää? Kuinka ehdotusten tilaaminen tulee olemaan?

Tässä tapauksessa näyttää melko itsestään selvältä ehdottaa D: tä C: ltä A: lle, koska heillä on enemmän keskinäisiä ystäviä ja he ovat todennäköisemmin yhteydessä toisiinsa.

Kahdella ihmisellä ei kuitenkaan välttämättä ole aina keskinäisiä ystäviä, mutta heillä voi olla yhteisiä toisen asteen tai kolmannen asteen yhteyksiä.

N: n asteen yhteydet

  • A ja B ovat ystäviä. (0 astetta)
  • A ja B ovat 1. asteen ystäviä, mikä tarkoittaa, että heillä on keskinäinen ystävä.
  • A ja B ovat toisen asteen ystäviä, jos heillä on ystävä, joka on ensimmäisen asteen ystävä toisen henkilön kanssa. esimerkiksi: - A - C - D - B, niin A ja B ovat toisen asteen ystäviä.
  • Samoin A ja B ovat n. Asteen ystäviä, jos niiden välillä on N-yhteys. esimerkiksi: - A - X1 - X2 - X3 ... .. - XN - B.

Tarkasteltaessa tätä lähestymistapaa suosituksen saamiseksi on löydettävä ystävyysaste, joka kahdella tietyllä käyttäjällä on Facebookissa.

Syötä kuvaajan kulkutiedot

Nyt kun tiedämme kuinka ystäväsuosituksia voidaan antaa, toistetaan tämä ongelma, jotta voimme tarkastella sitä algoritmisesta näkökulmasta.

Kuvailkaamme kaikkien Facebookin käyttäjien suuntaamaton kaavio, jossa kärkipisteet V edustavat käyttäjiä ja reunat E edustavat ystävyyttä. Toisin sanoen: jos käyttäjät A ja B ovat ystäviä Facebookissa, kärkien A ja B välillä on reuna. Haasteena on selvittää kahden käyttäjän välinen yhteysaste.

Muodollisemmin meidän on nähtävä lyhyin etäisyys kahden solmun välillä suunnatussa, painottamattomassa kuvaajassa.

Tarkastellaan kahta huippua tässä suuntaamattomassa kuvaajassa A ja C. C: n saavuttamiseksi on kaksi erilaista reittiä:

1. A → B → C ja
2. A → G → F → E → D → C

Haluamme selvästi, että käytämme pienintä tietä yrittäessään nähdä kahden henkilön välisen yhteyden aste sosiaalisessa verkostossa.

Toistaiseksi niin hyvä.

Katsotaanpa ennen tämän jatkamista tämän ongelman monimutkaisuus. Kuten aiemmin todettiin, Facebookilla on noin 2,07 miljardia käyttäjää vuoden 2017 kolmannen neljänneksen jälkeen. Tämä tarkoittaa, että kaaviomme sisältää noin 2,07 miljardia solmua ja vähintään (2,07 miljardia - 1) reunaa (jos jokaisella henkilöllä on ainakin yksi ystävä).

Tämä on valtava mittakaava tämän ongelman ratkaisemiseksi. Lisäksi näimme myös, että kaaviossa voi olla useita reittejä päästäksesi tietystä lähdehuipusta kohdepisteeseen ja haluamme lyhimmän ratkaista ongelmamme.

Tarkastelemme kahta klassista kuvaajan läpikulkualgoritmia ongelman ratkaisemiseksi:

1. Syvyyshaku ja
2. Leveys ensimmäinen haku.

Syvyys ensimmäinen haku

Kuvittele, että olet juuttunut tällaiseen labyrinttiin.

Sinun on päästävä jotenkin ulos. Reittejä lähtöpisteestä lähtöä kohti voi olla useita. Luonnollinen tapa päästä pois labyrintistä on kokeilla kaikkia polkuja.

Oletetaan, että sillä hetkellä, kun seisot, on kaksi vaihtoehtoa. Ilmeisesti et tiedä kumpi johtaa labyrintistä. Joten päätät tehdä ensimmäisen valinnan ja siirtyä eteenpäin labyrintissä.

Jatkat liikkeitä ja jatkat eteenpäin ja pääset umpikujaan. Nyt haluat mieluiten kokeilla erilaista polkua, ja sitten palaat takaisin edelliseen tarkistuspisteeseen, jossa olet tehnyt jonkin vaihtoehdoista, ja kokeilet sitten uutta, ts. Erilaista polkua tällä kertaa.

Jatkat tätä, kunnes löydät poistumisen.

Tiettyjen polkujen rekursiivinen kokeilu ja jälkiseuranta ovat kaksi komponenttia, jotka muodostavat syvyyden ensimmäisen haun algoritmin (DFS).

Jos mallintamme sokkelo-ongelman kuvaajana, kärjet edustaisivat henkilön sijaintia labyrintissä ja kahden solmun väliset suunnatut reunat edustaisivat yhtä siirtoa paikasta toiseen. DFS: n avulla henkilö yritti kaikkia mahdollisia reittejä, kunnes poistuminen löytyy.

Tässä on näyte pseudokoodi samalle.

1 menettely DFS (G, v):
2 merkki v löydetyksi
3 kaikille reunoille v: sta w: hen G.adjacentEdges (v): ssä
4, jos huippua w ei ole merkitty löydetyksi
Soita rekursiivisesti DFS (G, w)

Tutustu syvemmälle tähän algoritmiin:

Ajan monimutkaisuus: O (V + E)

Ensimmäinen haku

Kuvittele tarttuva tauti, joka leviää vähitellen alueelle. Joka päivä ihmiset, joilla on sairaus, tartuttavat uusia ihmisiä, joiden kanssa he ovat fyysisesti yhteydessä. Tällä tavoin tauti tekee eräänlaisen leveyden ensin -haun (BFS) väestöstä. "Jono" on joukko ihmisiä, jotka ovat juuri saaneet tartunnan. Kaavio on alueen fyysinen yhteysverkko.

Kuvittele, että sinun täytyy simuloida taudin leviämistä tämän verkon kautta. Haun juurisolmu on potilas nolla, ensimmäinen tunnettu taudin kärsijä. Aloitat vain heillä taudilla, eikä kukaan muu.

Nyt iteroit niiden ihmisten suhteen, joiden kanssa he ovat yhteydessä. Jotkut tarttuvat tautiin. Nyt toista niiden kaikkien suhteen. Antakaa ihmisille, jotka ovat myös kosketuksissa tautiin, ellei heillä ole sitä jo ollut. Jatka, kunnes olet saanut tartunnan kaikkiin tai saanut tartunnan tavoiteasi. Sitten olet valmis. Näin leveys ensin -haku toimii.

BFS-hakualgoritmi tutkii huipputasoja kerros kerrokselta alkaen ensimmäisestä kärkipisteestä ja siirtyy seuraavaan kerrokseen vasta, kun kaikki nykyisen kerroksen kärjet on käsitelty.

Tässä on esimerkki pseudokoodista BFS: lle.

1 menettely BFS (G, v):
2 q = jono ()
3 q.enqueue (v)
4 kun q ei ole tyhjä:
5 v = q.arvo ()
6, jos v: tä ei käydä:
7 merkitse v käytetyksi (// käsittele solmu)
8 kaikille reunoille v: sta w: hen G.adjacentEdges (v) -tehtävissä
9 q.enqueue (w)

Tutustu tähän artikkeliin saadaksesi syvällisemmän kuvan BFS: stä.

Ajan monimutkaisuus: O (V + E)

Lyhimmät polut

Siirrytään eteenpäin ja ratkaistaan ​​alkuperäinen ongelmamme: löytää lyhyin polku kahden annetun kärkipisteen välillä suunnatusta kuvaajasta.

Kun tarkastellaan näiden kahden algoritmin aika monimutkaisuutta, emme voi todella tehdä eroa näiden kahden välillä tässä ongelmassa. Molemmat algoritmit löytävät polun (tai pikimmin lyhyimmän) määränpäähän määrätystä lähteestä.

Katsotaanpa seuraavaa esimerkkiä.

Oletetaan, että haluamme selvittää lyhimmän polun solmusta 8-10. Katsotaanpa solmut, joita DFS ja BFS tutkivat ennen määränpäähän saapumista.

DFS

  • Prosessi 8 → Prosessi 3 → Prosessi 1.
  • Takaisin 3: een.
  • Prosessi 6 → Prosessi 4.
  • Takaisin 6: een.
  • Prosessi 7.
  • Takaisin 6: een → Takaisin 3: een → Takaisin 8: een.
  • Prosessi 10.

Täällä käsitellään yhteensä 7 solmua ennen määränpään saavuttamista. Katsotaan nyt, kuinka BFS tekee asiat.

BFS

  • Prosessi 8 → Valitse 3, 10
  • Prosessi 3 → Valitse 1,6
  • Prosessi 10.

Woah, se oli nopeaa! Vain 3 solmua oli käsiteltävä ja olimme määränpäässämme.

Selitys tälle nopeutukselle, jonka voimme nähdä BFS: ssä, ei DFS: ssä, johtuu siitä, että DFS vie tietyn polun ja kulkee loppuun asti, ts. Kunnes se osuu umpikujaan ja sitten takaisin.

Tämä on DFS-algoritmin suurin kaatuminen. Sen on ehkä laajennettava tuhansien tasojen tasoja (valtavassa verkossa, kuten Facebook, vain siksi, että se on valinnut huonon prosessoitavan prosessin alusta alkaen) ennen kuin pääsee reittiämme sisältävään polkuun. BFS ei kohtaa tätä ongelmaa, joten se on paljon nopeampi ongelmallemme.

Lisäksi, vaikka DFS löytää kohteen, emme voi olla varmoja, että DFS: n kulkema polku on lyhin. Voi olla myös muita polkuja.

Tämä tarkoittaa, että DFS: n joudutaan joka tapauksessa lyhyimmän reitin ongelman kattamaan koko kuvaaja saadakseen lyhyin reitti.

BFS: n tapauksessa kohdesolmun ensimmäinen esiintyminen varmistaa kuitenkin, että se on lyhin etäisyys lähteestä.

johtopäätös

Toistaiseksi keskustelemme Facebookin ystäväsuosituksen ongelmasta ja keksi sen ongelmaksi löytää kahden käyttäjän välisten yhteyksien aste verkkokaaviossa.

Sitten keskustelimme kahdesta mielenkiintoisesta Graph Traversal -algoritmista, joita käytetään hyvin yleisesti. Lopuksi tarkastelimme, mikä algoritmi toimii parhaiten ongelman ratkaisemiseksi.

Leveys ensimmäinen haku on algoritmi, jota haluat käyttää, jos joudut löytämään lyhyimmän etäisyyden kahden solmun välillä suunnattavassa, painottamattomassa kuvaajassa.

Katsotaanpa tätä hauskaa ongelmaa kuvaamaan ero kahden algoritmin välillä.

Oletetaan, että olet lukenut ongelmalausunnon huolellisesti, kokeilemme ensin mallintaa tätä kuvaajaongelmana.

Olkoon kaikista mahdollisista merkkijonoista solmut kuvaajassa ja meillä on reuna kahden kärkipisteen välillä, jos niiden välillä on yksi mutaatio.

Helppoa, eikö?

Meille annetaan aloitusjono (lue lähdekärkiteksti), esim .: - “AACCGGTT”, ja meidän on päästävä kohdemerkkijonoon (lue kohdekärkipiste) “AACCGGTA” pienimmällä mutaatioiden lukumäärällä (lue vähimmäisvaiheiden lukumäärä) siten, että kaikki väliketjut (solmujen) tulisi kuulua annettuun sanapankkiin.

Kokeile ja ratkaise tämä ongelma itse, ennen kuin katsot alla olevaa ratkaisua.

Jos yrität ratkaista sen DFS: n avulla, keksit varmasti ratkaisun, mutta on olemassa testitapauksia, jotka ylittävät LeetCode-alustalle varatun määräajan. Tämä johtuu edellä kuvatusta ongelmasta, miksi DFS vie niin kauan (prosessi 7 solmua kuin 3 BFS: ssä) päästäksesi kohdepisteeseen.

Toivottavasti sait pääidean kahden pääkäyrän läpikäynnin takana ja niiden välisen eron, kun sovellus on lyhin reittejä suuntaamattomassa painottamattomassa kuvaajassa.

Ole hyvä ja suosittele (❤) tätä viestiä, jos arvelet siitä olevan hyötyä jollekin!