cpp hogyan lehet összehasonlítani a térképekkel


Válasz 1:

Matematikailag a Map olyan modell, amely kulcsot vesz és válaszol egy értékkel. A készlet a Térkép speciális esete, ahol a kulcs megegyezik azzal az értékkel, amelyhez leképezi. Ez a koncepció e két objektum C ++ megvalósítására is kiterjed.

Mikor hasznos az std :: map: Vegyünk egy felhasználói fiókokat tároló adatbázist, tegyük fel, hogy ezek netflix-fiókok. A netflix-felhasználók ezen táblázatát ábrázoló térkép felhasználói azonosítót kaphat, és visszaadhatja az adott azonosítószámhoz tartozó felhasználói objektumot. Ezután felhasználhatjuk az azonosítót a felhasználói fiók O (1) idő alatt történő lekérésére az egyedi felhasználói azonosító beillesztésével a fiókba, és fiók kereséséhez csak az azonosítóra lesz szükséged, hogy visszanyerje ezeket a felhasználói adatokat.

Meg tudjuk ezt csinálni az std :: set paranccsal? Hogyan valósíthatnánk meg ezt az előző példát egy halmazgal? Beilleszthetünk felhasználói fiókokat az std :: set-be, de amikor felhasználói fiókot akarunk keresni, akkor a teljes felhasználói fiókra lesz szükségünk a felhasználói rekordunk kereséséhez. Várjon egy percet, ha már rendelkezünk a felhasználói fiókkal kapcsolatos információkkal, miért kellene rákeresnünk? Szintén mi van, ha csak a felhasználói azonosító számunk van, a fiókot már nem tudjuk lekérni O (1) idő alatt, az egész táblázatot iterálnunk kell, hogy megtaláljuk a megfelelő fiókot, és ez O (N) lesz.

Mikor érdemes használni az std :: map és mikor az primitívek számára az std :: map alkalmazást? Vegyünk egy olyan struktúrát, amely az összes prímszámot valamilyen tetszőleges N érték alatt tárolja. Ha egyszerűen meg akarjuk tudni, hogy egy szám tagja-e a prímhalmaznak, akkor az std :: setnek van értelme, egyszerűen meg kell vizsgálnunk, hogy tetszőleges egész szám van-e. A 'k' érték létezik a készletünkben, és előfordulhat, hogy nem foglalkozunk egy index vagy egy kulcs fogalmával. Ha azonban érdekel a prímek sorrendje, akkor érdemes lehet kulcs-érték párosításra. Talán szeretnénk modellezni a p = {2, 3, 5, 7, 11,…} szekvenciát, és szeretnénk tudni, hogy p [j] = k a j & k néhány tetszőleges értékére. Ez utóbbi esetben érdemes megvizsgálni az std :: map-ot (bár az std :: vector is jó választás lehet).

Tehát röviden:

  1. A beállított adatstruktúra a térképi adatstruktúra speciális típusa, ahol a kulcs == érték, és a C ++ STL definíciók ezt a fogalmat tükrözik
  2. Az std :: map, mint az std :: set általában hasznosabb, mivel az std :: map gyors kulcs keresést biztosít az összesített értékek (egész objektumok helyett primitívek) számára.
  3. Az std :: set gyakran hasznosabb a primitíveknél, mivel a k-> k primitív érték feltérképezése meglehetősen önkényes

Válasz 2:

Sok válasz nem érinti a térkép és a C ++ 17 konténerek beállítása megvalósításának változását, még akkor is, ha ez releváns, ezért kizárólag erre térek ki.

Hogyan lehet egy csomópontot áthelyezni egyik tárolóból a másikba?

Hogyan lehet megváltoztatni a térképcsomópont kulcsát?

Ha mozgatható, de nem másolható adatokat helyezett el egy térképbe vagy készletbe, hogyan hozhatja vissza újra?

Ezekre a C ++ 17-ben válaszolunk egy új, átlátszatlan adatstruktúra hozzáadásával ... a csomópont-fogantyúval ... egy csomópont-fogantyúba állítva, és egy új túlterhelés a beszúrás miatt, amely egy csomópontot vesz ki a csomópont-fogantyúból és beszúrja egy térképbe vagy halmazba. Van egy új kényelmi módszer, az egyesítés is, amely az összes nem duplikált csomópontot áthelyezi az egyik térképbe vagy a másikba.

Csomópont fogantyú (C ++ 17)

A csomópont-fogantyúnak több tulajdonsága van. A kibontott csomópont pontosan ugyanúgy rendelkezik, mint az std :: unique_ptr, és így mozgatható is, de nem másolható. Ha egy csomópont-fogantyú birtokában van egy csomópont, amikor megsemmisül, akkor a csomópont megsemmisül és elosztásra kerül… ami azt jelenti, hogy rendelkeznie kell a tárolóban a lefoglaláshoz használt allokátor egy másolatával is. Ez azt jelenti, hogy a két tárolóban használt allokátoroknak meg kell egyezniük az egyenlő értékekkel (= = operátor = true adja vissza) az egyik tárolóból a másikba mozgatandó csomópontot. Minden alapértelmezett lefoglaló egyenlő, tehát ez általában nem jelent problémát.

Míg egy csomópont az nh csomópont-fogantyú tulajdonában van, akkor olyan módon lehet üzemeltetni, amely nem lehetséges, amíg egy térképen vagy halmazon belül van. Például egy kibontott térképcsomópont kulcsát megváltoztathatja az nh.key () hozzárendelésével, és az átmásolhatatlan leképezett értéket az std :: move (nh.mapped ()) segítségével mozgathatja ki. A kibontott halmaz csomópontja átmásolhatatlan értéket helyezhet el az std :: move (nh.value ()) használatával.


Válasz 3:

Jelenleg a C ++ 8 szabványt kínál

asszociatív konténerek

ezen a téren:

  • std :: set
  • std :: multiset
  • std :: rendezetlen_készlet
  • std :: rendezetlen_multiset
  • std :: térkép
  • std :: multimap
  • std :: rendezetlen_térkép
  • std :: rendezetlen_multimap

Észreveheti, hogy itt 3 tengely van:

  • készlet kontra térkép.
  • rendezett vs rendezetlen.
  • egyedi kulcs és több kulcs.

A set vs. map-ról kérdeztél; azonban érdemes tudni, hogyan válasszon mind a 8 kombináció közül.

készlet kontra térkép

Egy készlet kulcsok készletét tartalmazza. Beilleszthet és eltávolíthat kulcsokat a készletből, tesztelheti, hogy a kulcs van-e a készletben, és iterálhat az összes kulcs halmaza felett. Miután egy kulcsot beillesztettek a készletbe, a kulcs megváltoztathatatlan. A kulcs behelyezése után nem módosítható. Inkább törölnie kell, és be kell helyeznie az új kulcsot, ha meglévő kulcsot szeretne megváltoztatni.

A térkép minden kulcshoz társít egy értéket. Az értékek elkülönülhetnek a kulcstól. Rendszerint az értékek is változtathatóak. Meg tudok keresni egy értéket a kulcsával, és megváltoztathatom az értéket, ha megtalálom.

Akkor használja a set alkalmazást, ha csak a meglévő kulcsok miatt aggódik. Akkor használja a térképet, ha egy csomó érték nyomon követésével foglalkozik, amelyekhez kulcsok vannak társítva.

Tegyük fel például, hogy nyomon akartam tartani az értekezleten részt vevő összes embert. Egy készlet alkalmas lehet arra. Minden résztvevő tagja a készletnek, és én megismételhetem a készlet minden tagját, hogy létrehozzak egy listát a résztvevőkről.

Tegyük fel, hogy a találkozómat ellátják, és szeretném nyomon követni az értekezletemen részt vevő összes ember étkezési preferenciáit. Most azt szeretném, ha a résztvevők térképe az étkezés preferenciáját illeti. A kulcs ebben az esetben a résztvevő, és az érték az étkezési preferencia. Módosíthatja az egyes résztvevők étkezési preferenciáit anélkül, hogy módosítanák a résztvevőket. (Így kevésbé kínos ...)

rendezett vs rendezetlen

Az asszociatív konténerek anélkül

rendezetlen

a névajánlatban

O (\ lg n)

hozzáférési idő. Olyan kulcsokat igényelnek, amelyek vannak

Hasonló

és

Szigorú Gyenge Rendelt.

Általában kiegyensúlyozott bináris kereső fákból épülnek fel. Ha az összes elemet ismétli, akkor a kulcsokat nem csökkenő sorrendben fogja felkeresni. (Vagy nem növekvő sorrend, ha fordított iterátorokat használ.)

A névben rendezetlen asszociatív tárolók amortizált O (1) hozzáférési időt kínálnak, feltéve, hogy létrehozhat egy O (1) kivonatoló funkciót a kulcsához. Köznyelven ezeket hash-tábláknak nevezik. A rendezetlen tárolók hatékony működéséhez hatékony hasító funkcióra van szükség. Ha az összes elemet iterálja, akkor tetszőleges sorrendben fogja felkeresni a kulcsokat.

Mikor kell használni a rendezett és a nem rendezetteket? Ez néhány dologtól függ:

  • Gyakran kell determinisztikus sorrendben meglátogatnia az összes kulcsot? Ha igen, a megrendelt konténer ésszerű választás lehet.
  • Gyorsabb vagy lassabb az összehasonlítás, mint a keverés? Ha sokkal gyorsabb, akkor a megrendelt is jobb lehet. Ha sokkal lassabb, akkor a rendezetlen is gyorsabb lehet.
  • Tudja előre a tartály hozzávetőleges teljes méretét? A rendezetlen konténer átméretezése drága lehet, míg a rendezett konténerbe történő behelyezés nem szokott vad teljesítmény ingadozásokat okozni.
  • Milyen memória lábnyomot tud elviselni? A rendezetlen konténerek nagysága a sebesség szempontjából nagyobb.

Ha gondosan írja be a kódot, megpróbálhat váltani a megrendelt és a nem rendezett tárolók között az összehasonlításhoz, amely jobban teljesít az adott munkaterhelés szempontjából.

Egy általam írt alkalmazás a megrendelt és rendezetlen konténerek érdekes keverékével zárult, éppen ilyen benchmarking alapján. Kicsit meglepődtem, hogy melyik konténerek hol nyertek, és ez hogyan változott, amikor megváltoztattam a kulcsok tulajdonságait. Különösen az std :: string-ről egész számokkal indexelt string-táblára való áttérés érezhetően megváltoztatta a hash függvények költségeit.

egyedi kulcs és többkulcsos

Az asszociatív tárolók, amelyekben a név nem tartalmaz több nevet, csak egyetlen példányt engedélyeznek a tárolóban lévő kulcsok közül. Vagyis minden kulcsnak egyedinek kell lennie. Ez hasonló szemantikát nyújt, mint egy 1-D tömb, ahol minden index egy elemet tartalmaz. A tárolóban már létező kulcs beszúrása logikai hiba.

Az asszociatív tárolók, amelyekben a neve több, lehetővé teszik az egyes kulcsok több példányát. Az egyes kulcsokat annyiszor helyezheti be, ahányszor csak akarja. Az ismételt kulcsok beszúrási sorrendben maradnak.

Megjegyzés: Ez még a multiset esetében is fontos, mivel az összehasonlítási kritériumok megkülönböztetik az egyenértékű és az egyenlő értéket. Két kulcs egyenértékű, ha egyik sem hasonlít kevesebbet, mint a másik; Az összehasonlító függvény azonban nem szükséges a kulcsobjektum összes mezőjének figyelembe vételéhez.

Melyiket válassza? Ez valóban attól a problémától függ, amelyet megpróbál megoldani. Anekdotikus módon ritkán volt szükségem multisetekre vagy multimapokra.

Ha nyomon kell követnie a „kulcs” összes példányát, függetlenül attól, hogy egyesek összehasonlítják-e vagy sem, akkor a multiset vagy multimap a megfelelő választás. Ellenkező esetben valószínűleg a nem multi halmazokat vagy térképeket akarja.

Az std :: multiset vagy az std :: multimap egyik érdekes felhasználása kiemelt sor. Használja a prioritást kulcsként. A begin () által visszaküldött elem a legfontosabb prioritás. Az elemek listáját rendezett sorrendben vezetik, így egy iterátorra mutatva, amely egy elemre mutat, gyorsan meghatározhatja, mi van közvetlenül előtte és közvetlenül utána. Különösen, ha a prioritást ténylegesen az idő képviseli - vagyis ez a prioritási sor tulajdonképpen egy idő szerint rendezett eseménysor -, akkor olcsón meghatározhatja, hogy egy bizonyos idő közelében milyen eseményeket ütemeznek.

Ez azonban csak a megrendelt multiset és a rendezett multimap esetén működik.

std :: prioritás_kód

jobb választás lehet, ha csak gyors hozzáférésre van szükséged a legmagasabb prioritású elemhez, és nem használod ki a multiset vagy multimap teljesen rendezett jellegét. (Lát

std :: prioritás_kód

további részletekért.)


Válasz 4:

Nos erre válaszolhatok.

Térképek

A térképekhez kulcsok szükségesek. Minden kulcshoz megad egy bizonyos típusú értéket.

Most egy kulcs lehet bármi, egész szám, karakterlánc vagy akár objektum (további összehasonlítási funkcióval rendelkezik). Így lehetnek az értékek.

Ezt nézd:

térkép M; // egész szám - egész számM [3] = 2;térkép S; // string kulcs - egész értékS ["ahar"] = 26;

Ez lenyűgöző.

Tegyük fel, hogy tárolni szeretné barátai születésnapját. Csak deklarálsz egy térképet és csak egyszerű feladat elvégzésével tárolják a nevüket és születési dátumukat. Olyan, mint a szótár a Pythonban.

Készletek

A készletek esetében ez nem így van. A halmazokhoz nincs szükség (kulcs, érték) párosításra. Csak olyan értékeket tartalmaznak (természetesen összehasonlító funkciókkal vagy az operátor túlterhelésével, ha szükséges), amelyeket tartalmazni akarnak. Például:

készlet S;S.betét (13);készlet T;S. beszúrás ("ahar");készlet X;S.betét (yourObject);

Az előadás szempontjából hasonlóságok vannak. A keresés, beillesztés, törlés stb

O (logn)

mindkettőjükben (köszönet illeti

Piros fekete fa

, amitől féltél az Adatszerkezet tanfolyamon: P). De a megvalósítás és a használati különbségek miatt lehetnek bizonyos általános költségek.

További megjegyzés:

Ha megfigyel, megállapítja, hogy az alapvető strukturális szempontból a halmazok és a térképek különböznek egymástól. Tehát a feltett kérdés egy kicsit érdekesebb lehet, ha úgy gondolja, hogy a készleteket használhatja térképek alternatívájaként és fordítva.

Ez érdekes kérdéshez vezethet minket: mi a különbség a halmaz között > és térképet ? Ez eléggé érvényes kérdés, mert ebben a forgatókönyvben a pár első elemére gondolhat a halmazban, amely megegyezik a térkép kulcsával!

Például:

térkép M;M. beszúrás ({"motta", 13});készlet > S;S. beszúrás ({"motta", 13});

Láthatja, hogy a fent írt halmaz potenciális alternatívája lehet a térképnek.

Tehát egyenértékűek? Hát nem.

Először is, a térkép nem tartalmazhat más egész számot ugyanazon kulcshoz, mint azt fentebb deklaráltuk. De meg lehet.

Így,

M. beszúrás ({"ahar", 13)};S. beszúrás ({"ahar", 13});M. beszúrás ({"ahar", 26});S. beszúrás ({"ahar", 26});

a halmaz mérete 2, de a térkép esetében 1.

Másodszor, már tudnia kell, hogy ezek a C ++ konténerek iterátorokat használnak, amelyek az elemek tárolására szolgálnak ezekben a konténerekben. Ha egyszerűen meg akarjuk gondolni, akkor az iterátorokra van szükség, hogy hozzáférhessenek ezekben a tárolókban lévő adatokhoz.

Most nézze meg ezt:

készlet > S;S. beszúrás ({"ahar", 26});auto it = S.kezdés (); // most iterátor a ("ahar", 26) számára

Valamilyen oknál fogva 26-ról 13-ra kívánja változtatni a megfelelő iterált pár értékét. Ezt megpróbálja:

it-> másodperc = 13;

Umm ... na. Nem tudod megcsinálni.

Az ok némileg bonyolult. Egyszerűen fogalmazva, a C ++ halmaz iterátorai olyanok, mint az állandó iterátorok. Tehát nem csak a megfelelő adatértéket módosíthatja helyben. Törölnie kell a készletből, majd hozzá kell adnia az új értékét, például:

S.erase (it);pár p = {"ahar", 13};S.inzert (p);

: |

Térképek esetében ez teljesen érvényes:

térkép M;M. beszúrás ({"motta", 13});auto it = M.begin ();it-> másodperc = 26;

Remélem, hogy minden rendben van. : P

Köszönöm, hogy elolvasta.


Válasz 5:

A térkép olyan adatszerkezet, amelyet kulcsok alapján keresnek az értékek alapján, míg a halmaz csak értékek gyűjteménye.

A megvalósítás szempontjából általában nem másképp hajtják végre őket, és mindkettő általában vörös-fekete fákat használ a motorháztető alatt, hogy a legtöbb művelethez logaritmikus időbonyolultságot kapjon. A megvalósításoktól függően az egyik különbség az, hogy egy halmaz az elemek vörös-fekete fája, míg a térkép a kulcs (érték, érték) duplaszemek vörös-fekete fája lesz, az első elem (kulcs) szerint rendezve. tuple.


Válasz 6:

A térkép az egyik objektumot egy másikhoz térképezi fel. A halmaz objektumok rendezett halmaza. A térképet gyakran használják az objektumok index általi elérésére oly módon, hogy az objectMap [i] tartalmazza az i indexű objektumot. Egy halmaz használható objektumok tárolására, azzal a további előnnyel, hogy a halmaz azonosítja, hogy egy objektum már benne van-e, és csak az objektumok egyetlen entitását tárolja. Azonban egy halmaz objektumaihoz csak akkor férhet hozzá, ha iterál rajta, vagy megszerzi a halmaz első vagy utolsó elemét.


Válasz 7:

Az std :: map asszociatív, rendezett tömb. Ez azt jelenti, hogy tárol párok és a kulcs segítségével elérheti az értéket. Ismételheti a párok és az iteráció a kulcsok megfelelő rendezését követi.

Az std :: set csak értékek gyűjteménye. Ismét lehet iterálni rajta, és ismét az iteráció követi az értékek megfelelő sorrendjét. De a fentihez hasonló asszociáció nincs, csak olyan kérdéseket tehet fel, mint „ez az érték a készletben van?” Ehhez pedig már rendelkeznie kell a kérdéses értékkel.