Sekvenční kontejner (C ++) - Sequence container (C++)
![]() | Tento článek může vyžadovat vyčištění setkat se s Wikipedií standardy kvality. Specifický problém je: Podívejte se na rozhovorProsinec 2011) (Zjistěte, jak a kdy odstranit tuto zprávu šablony) ( |
Standardní knihovna C ++ |
---|
Kontejnery |
C standardní knihovna |
Ve výpočetní technice, sekvenční kontejnery odkazují na skupinu kontejner šablony tříd v standardní knihovna z Programovací jazyk C ++ které implementují ukládání datových prvků. Bytost šablony, lze je použít k ukládání libovolných prvků, jako jsou celá čísla nebo vlastní třídy. Jedna společná vlastnost všech sekvenčních kontejnerů je, že k prvkům lze přistupovat sekvenčně. Stejně jako všechny ostatní standardní součásti knihovny jsou umístěny jmenný prostor std.
V aktuální revizi standardu C ++ jsou definovány následující kontejnery: pole
, vektor
, seznam
, forward_list
, deque
. Každý z těchto kontejnerů implementuje různé algoritmy pro ukládání dat, což znamená, že mají různé záruky rychlosti pro různé operace:[1]
pole
implementuje nezměnitelné pole v době kompilace.vektor
implementuje pole rychle náhodný přístup a schopnost automaticky měnit velikost při připojování prvků.deque
implementuje a oboustranná fronta s poměrně rychlým náhodným přístupem.seznam
implementuje a dvojnásobně propojený seznam.forward_list
implementuje a jednotlivě propojený seznam.
Protože každý z kontejnerů musí být schopen kopírovat své prvky, aby správně fungoval, musí typ prvků splňovat CopyConstructible
a Přiřaditelné
požadavky.[2] U daného kontejneru musí všechny prvky patřit stejnému typu. Například nelze ukládat data ve formě obou char a int ve stejné instanci kontejneru.
Dějiny
![]() | Tato sekce potřebuje expanzi. Můžete pomoci přidávat k tomu. (Prosinec 2011) |
Původně pouze vektor
, seznam
a deque
byly definovány. Do standardizace jazyka C ++ v roce 1998 byly součástí Standardní knihovna šablon (STL), publikoval SGI.
The pole
kontejner se nejprve objevil v několika knihách pod různými jmény. Později byl začleněn do Zvýšit knihovny a bylo navrženo pro zařazení do standardní knihovny C ++. Motivace pro začlenění pole
bylo, že řeší dva problémy pole ve stylu C: nedostatek rozhraní podobného STL a neschopnost být kopírován jako jakýkoli jiný objekt. Nejprve se objevil v C ++ TR1 a později byla začleněna do C ++ 11.
The forward_list
kontejner byl přidán do C ++ 11 jako prostorově efektivní alternativa k seznam
když není potřeba reverzní iterace.
Vlastnosti
pole
, vektor
a deque
všechny podporují rychlý náhodný přístup k prvkům. seznam
podporuje obousměrnou iteraci, zatímco forward_list
podporuje pouze jednosměrnou iteraci.
pole
nepodporuje vložení nebo vyjmutí prvku. vektor
podporuje rychlé vložení nebo vyjmutí prvku na konci. Jakékoli vložení nebo odebrání prvku, který není na konci vektoru, vyžaduje kopírování prvků mezi pozicí vložení a koncem vektoru. The iterátory k ovlivněným prvkům jsou tedy zneplatněny. Ve skutečnosti může jakékoli vložení potenciálně zneplatnit všechny iterátory. Také, pokud přidělené úložiště v vektor
je příliš malý na vložení prvků, je přiděleno nové pole, všechny prvky jsou zkopírovány nebo přesunuty do nového pole a staré pole je uvolněno. deque
, seznam
a forward_list
všechny podporují rychlé vkládání nebo vyjímání prvků kdekoli v kontejneru. seznam
a forward_list
zachovává platnost iterátorů pro tuto operaci, zatímco deque
zruší platnost všech z nich.
Vektor
Prvky a vektor
jsou uloženy souvisle.[3] Jako všichni dynamické pole implementace, vektory mají nízké využití paměti a dobré referenční lokalita a datová mezipaměť využití. Na rozdíl od jiných kontejnerů STL, jako jsou deques a seznamy vektory umožňují uživateli označit počáteční kapacitu kontejneru.
Vektory umožňují náhodný přístup; to znamená, že na prvek vektoru lze odkazovat stejným způsobem jako na prvky polí (pomocí indexů pole). Propojené seznamy a sady, na druhou stranu nepodporují náhodný přístup ani aritmetiku ukazatele.
Struktura vektorových dat je schopna rychle a snadno alokovat potřebnou paměť potřebnou pro uložení konkrétních dat a je schopna tak učinit v amortizované konstantní době. To je zvláště užitečné pro ukládání dat v seznamech, jejichž délka nemusí být známa před vytvořením seznamu, ale kde je odstranění (jiné než, možná na konci) vzácné. Vymazání prvků z vektoru nebo dokonce úplné vymazání vektoru nemusí nutně uvolnit paměť spojenou s tímto prvkem.
Kapacita a přerozdělení
Typická vektorová implementace se interně skládá z ukazatele na a dynamicky přiděleno pole,[1] a případně datové členy, které drží kapacitu a velikost vektoru. Velikost vektoru odpovídá skutečnému počtu prvků, zatímco kapacita odpovídá velikosti vnitřního pole.
Když se při vkládání nových prvků zvětší nová velikost vektoru nad jeho kapacitu, přerozdělení dojde.[1][4] To obvykle způsobí, že vektor přidělí novou oblast úložiště, přesune dříve držené prvky do nové oblasti úložiště a uvolní starou oblast.
Protože adresy prvků se během tohoto procesu změní, jakékoli odkazy nebo iterátory prvky ve vektoru budou zneplatněny.[5] Použití zneplatněných referenčních příčin nedefinované chování.
Operaci rezervy () lze použít k zabránění zbytečnému přerozdělování. Po volání rezervy (n) je kapacita vektoru zaručena minimálně n.[6]
Vektor udržuje určité pořadí svých prvků, takže když se nový prvek vloží na začátek nebo do středu vektoru, následující prvky se posunou dozadu, pokud jde o jejich operátor přiřazení nebo kopírovací konstruktor. V důsledku toho se odkazy a iterátory na prvky za kurzorem zneplatní.[7]
Vektory C ++ nepodporují záměrné přerozdělení paměti na místě; tj. při realokaci vektoru bude paměť, kterou drží, vždy zkopírována do nového bloku paměti pomocí konstruktoru kopírování jejích prvků a poté uvolněna. To je neúčinné pro případy, kdy vektor drží prostá stará data a pro přidělení je k dispozici další souvislý prostor za zadrženým blokem paměti.
Specializace na bool
Standardní knihovna definuje specializaci vektor
šablona pro bool
. Popis této specializace naznačuje, že implementace by měla zabalit prvky tak, aby každý bool
používá pouze jeden bit paměti.[8] To je obecně považováno za chybu.[9][10] vector
nesplňuje požadavky a Standardní knihovna C ++ kontejner. Například a kontejner
musí být pravda lhodnota typu T
. To není případ vector
, což je třída proxy převoditelný na bool
.[11] Podobně vector
nepřináší a bool &
když odhlášeno. Mezi Výborem pro standardy C ++ a Pracovní skupinou pro knihovny existuje obecná shoda vector
by měl být zastaralý a následně odstraněn ze standardní knihovny, zatímco funkce bude znovu zavedena pod jiným názvem.[12]
Seznam
The seznam
datová struktura implementuje a dvojnásobně propojený seznam. Data se nekontinuálně ukládají do paměti, což umožňuje struktuře dat seznamu zabránit přerozdělení paměti, které může být nezbytné u vektorů, když jsou do seznamu vloženy nové prvky.
Struktura dat seznamu přiděluje a uvolňuje paměť podle potřeby; proto nepřiděluje paměť, kterou aktuálně nepoužívá. Paměť se uvolní, když je prvek odstraněn ze seznamu.
Seznamy jsou účinné při vkládání nových prvků do seznamu; tohle je úkon. Není nutné žádné řazení, jako u vektorů.
Seznamy nemají schopnost náhodného přístupu jako vektory ( úkon). Přístup k uzlu v seznamu je operace, která vyžaduje procházení seznamu k nalezení uzlu, ke kterému je třeba přistupovat.
U malých datových typů (například ints) je režie paměti mnohem významnější než u vektoru. Každý uzel zabírá velikost (typ) + 2 * velikost (typ*)
. Ukazatele jsou obvykle jedno slovo (obvykle čtyři bajty v 32bitových operačních systémech), což znamená, že seznam čtyř bajtových celých čísel zabírá přibližně třikrát více paměti než vektor celých čísel.
Přeposlat seznam
The forward_list
datová struktura implementuje a jednotlivě propojený seznam.
Deque
deque
je šablona třídy kontejneru, která implementuje a oboustranná fronta. Poskytuje podobné výpočetní složitost na vektor
pro většinu operací, s výraznou výjimkou, kterou poskytuje amortizovaná konstantní doba vkládání a vyjímání z obou konců sekvence prvků. Na rozdíl od vektor
, deque
používá nesouvislé bloky paměti a neposkytuje žádné prostředky ke kontrole kapacity kontejneru a okamžiku přerozdělení paměti. Jako vektor
, deque
nabízí podporu pro iterátory náhodného přístupu a vložení a odebrání prvků zruší platnost všech iterátorů deque.
Pole
pole
implementuje nezměnitelnou dobu kompilace pole. Velikost je určena v době kompilace parametrem šablony. Konstrukčně kontejner nepodporuje alokátory. Na rozdíl od ostatních standardních kontejnerů pole
neposkytuje konstantní čas vyměnit.
Přehled funkcí
Kontejnery jsou definovány v záhlavích pojmenovaných za názvy kontejnerů, např. vektor
je definován v záhlaví <vector>
. Všechny kontejnery splňují požadavky Kontejner pojem, což znamená, že mají začít()
, konec()
, velikost()
, max_size ()
, prázdný()
, a vyměnit ()
metody.
Členské funkce
Funkce | pole (C ++ 11 ) | vektor | deque | seznam | forward_list (C ++ 11 ) | Popis |
---|---|---|---|---|---|---|
Základy | (implicitní) | (konstruktér) | (konstruktér) | (konstruktér) | (konstruktér) | Konstruuje kontejner z různých zdrojů |
(destruktor) | (destruktor) | (destruktor) | (destruktor) | Zničí kontejner a obsažené prvky | ||
operátor = | operátor = | operátor = | operátor = | Přiřadí hodnoty kontejneru | ||
N / A | přiřadit | přiřadit | přiřadit | přiřadit | Přiřadí hodnoty kontejneru | |
Alokátory | get_allocator | get_allocator | get_allocator | get_allocator | Vrátí alokátor použitý k alokaci paměti pro prvky | |
Živel přístup | na | na | na | N / A | N / A | Přistupuje k zadanému prvku s kontrolou hranic. |
operátor[ ] | operátor[ ] | operátor[ ] | Přistupuje k zadanému prvku bez kontroly hranic. | |||
přední | přední | přední | přední | přední | Přistupuje k prvnímu prvku | |
zadní | zadní | zadní | zadní | N / A | Přistupuje k poslednímu prvku | |
data | data | N / A | N / A | Přistupuje k podkladovému poli | ||
Iterátory | začít | začít | začít | začít | začít | Vrátí iterátor na začátek kontejneru |
konec | konec | konec | konec | konec | Vrátí iterátor na konec kontejneru | |
rbegin | rbegin | rbegin | rbegin | N / A | Vrátí zpětný iterátor na zadní začátek kontejneru | |
rend | rend | rend | rend | Vrátí zpětný iterátor na zadní konec kontejneru | ||
Kapacita | prázdný | prázdný | prázdný | prázdný | prázdný | Zkontroluje, zda je kontejner prázdný |
velikost | velikost | velikost | velikost | N / A | Vrátí počet prvků v kontejneru. | |
max_size | max_size | max_size | max_size | max_size | Vrátí maximální možný počet prvků v kontejneru. | |
N / A | rezervovat | N / A | N / A | N / A | Rezervuje skladování v kontejneru | |
kapacita | Vrátí počet prvků, které lze zadržet v aktuálně přiděleném úložišti | |||||
shrink_to_fit | shrink_to_fit | Snižuje využití paměti uvolněním nevyužité paměti (C ++ 11 ) | ||||
Modifikátory | Průhledná | Průhledná | Průhledná | Průhledná | Vymaže obsah | |
vložit | vložit | vložit | N / A | Vloží prvky | ||
umístit | umístit | umístit | Vytváří prvky na místě (C ++ 11 ) | |||
vymazat | vymazat | vymazat | Vymaže prvky | |||
N / A | push_front | push_front | push_front | Vloží prvky na začátek | ||
emplace_front | emplace_front | emplace_front | Vytváří prvky na místě na začátku (C ++ 11 ) | |||
pop_front | pop_front | pop_front | Odebere první prvek | |||
zatlačit zpátky | zatlačit zpátky | zatlačit zpátky | N / A | Vloží prvky na konec | ||
emplace_back | emplace_back | emplace_back | Konstruuje prvky na místě na konci (C ++ 11 ) | |||
pop_back | pop_back | pop_back | Odebere poslední prvek | |||
N / A | N / A | N / A | insert_after | Vloží prvky po zadané poloze (C ++ 11 ) | ||
emplace_after | Vytvoří prvky na místě po zadané poloze (C ++ 11 ) | |||||
erase_after | Vymaže prvky na místě po určené poloze (C ++ 11 ) | |||||
změnit velikost | změnit velikost | změnit velikost | změnit velikost | Změní počet uložených prvků | ||
vyměnit | vyměnit | vyměnit | vyměnit | vyměnit | Zamění obsah za jiný kontejner stejného typu | |
vyplnit | N / A | N / A | N / A | N / A | Vyplní pole zadanou hodnotou |
Existují další operace, které jsou k dispozici jako součást třídy seznamu, a existují algoritmy, které jsou součástí C ++ STL (Algoritmus (C ++) ), které lze použít s seznam
a forward_list
třída:
Operace
seznam :: sloučit
aforward_list :: sloučit
- Sloučí dva seřazené seznamyseznam :: spoj
aforward_list :: splice_after
- Přesune prvky z jiného seznamuseznam :: odebrat
aforward_list :: remove
- Odstraní prvky rovnající se dané hodnotěseznam :: remove_if
aforward_list :: remove_if
- Odstraní prvky splňující specifická kritériaseznam :: zpět
aforward_list :: reverse
- Obrátí pořadí prvkůseznam :: jedinečný
aforward_list :: unique
- Odstraní po sobě jdoucí duplicitní prvkyseznam :: seřadit
aforward_list :: sort
- Seřadí prvky
Nečlenské funkce
Příklad použití
Následující příklad ukazuje různé techniky zahrnující vektor a Standardní knihovna C ++ zejména algoritmy míchání, třídění, hledání největšího prvku a mazání z vektoru pomocí vymazat-odstranit idiom.
#zahrnout <iostream>#zahrnout <vector>#zahrnout <array>#zahrnout <algorithm> // řazení, max_element, random_shuffle, remove_if, lower_bound #zahrnout <functional> // větší#zahrnout <iterator> // začátek, konec, cbegin, cend, vzdálenost// zde se pro větší pohodlí používá uvážlivě v reálných programech. použitím jmenný prostor std;použitím jmenný prostor std::zástupné symboly;auto hlavní(int, char**) -> int{ pole<int,4> přílet{ 1, 2, 3, 4 }; // inicializuje vektor z pole vektor<int> čísla( cbegin(přílet), postoupit(přílet) ); // vloží více čísel do vektoru čísla.zatlačit zpátky(5); čísla.zatlačit zpátky(6); čísla.zatlačit zpátky(7); čísla.zatlačit zpátky(8); // vektor aktuálně obsahuje {1, 2, 3, 4, 5, 6, 7, 8} // náhodně zamíchá prvky random_shuffle( začít(čísla), konec(čísla) ); // vyhledejte největší prvek, O (n) auto největší = max_element( cbegin(čísla), postoupit(čísla) ); cout << „Největší počet je“ << *největší << " n"; cout << "Je umístěn na indexu" << vzdálenost(největší, cbegin(čísla)) << " n"; // seřadit prvky třídit( začít(čísla), konec(čísla) ); // najdi pozici čísla 5 ve vektoru auto Pět = lower_bound( cbegin(čísla), postoupit(čísla), 5 ); cout << „Číslo 5 se nachází v indexu“ << vzdálenost(Pět, cbegin(čísla)) << " n"; // smaže všechny prvky větší než 4 čísla.vymazat( remove_if(začít(čísla), konec(čísla), svázat(větší<>{}, _1, 4) ), konec(čísla) ); // vytiskne všechna zbývající čísla pro(konst auto& živel : čísla) cout << živel << " "; vrátit se 0;}
Výstup bude následující:
Největší počet je 8 Je umístěn na indexu 6 (podle implementace). Číslo 5 je umístěn na indexu 41 2 3 4
Reference
- William Ford, William Topp. Datové struktury s C ++ a STL, Druhé vydání. Prentice Hall, 2002. ISBN 0-13-085850-1. Kapitola 4: Vektorová třída, str. 195–203.
- Josuttis, Nicolai M. (1999). Standardní knihovna C ++. Addison-Wesley. ISBN 0-201-37926-0.
Poznámky
- ^ A b C Josuttis, Nicolai (1999). C ++ standardní knihovna - výuka a reference. Addison-Wesley.
- ^ ISO /IEC (2003). ISO / IEC 14882: 2003 (E): Programming Languages - C ++ §23.1 Požadavky na kontejner [lib.container.requirements] odst. 4
- ^ ISO /IEC (2003). ISO / IEC 14882: 2003 (E): Programming Languages - C ++ §23.2.4 Vektor šablony třídy [lib.vector] odst. 1
- ^ ISO /IEC (2003). ISO / IEC 14882: 2003 (E): Programming Languages - C ++ §23.2.4.3 vektorové modifikátory [lib.vector.modifiers] odst. 1
- ^ ISO /IEC (2003). ISO / IEC 14882: 2003 (E): Programming Languages - C ++ §23.2.4.2 vektorová kapacita [lib.vector.capacity] odst. 5
- ^ ISO /IEC (2003). ISO / IEC 14882: 2003 (E): Programming Languages - C ++ §23.2.4.2 vektorová kapacita [lib.vector.capacity] odst. 2
- ^ ISO /IEC (2003). ISO / IEC 14882: 2003 (E): Programming Languages - C ++ §23.2.4.3 vektorové modifikátory [lib.vector.modifiers] odst. 3
- ^ ISO /IEC (2003). ISO / IEC 14882: 2003 (E): Programming Languages - C ++ §23.2.5 Vektor třídy
[lib.vector.bool] odst. 1 - ^ „vector
: Další problémy, lepší řešení“ (PDF). Srpna 1999. Citováno 28. listopadu 2017. - ^ "Specifikace k zastarání vektoru
" . Březen 2007. Citováno 28. listopadu 2017. - ^ ISO /IEC (2003). ISO / IEC 14882: 2003 (E): Programming Languages - C ++ §23.2.5 Vektor třídy
[lib.vector.bool] odst. 2 - ^ "96. Vector
není kontejner" . Citováno 28. června 2018.