Portál AbcLinuxu, 14. května 2025 22:58
Před řazením: { {"data 0", 0}, {"data 1", 1}, {"data 2", 2} } Po řazení podle toho řetězce opačně: { {"data 2", 0}, {"data 1", 1}, {"data 0", 2} }
struct Prvek { // nejaka data size_t index_v_poli; };Pak mám pole těch prvků, resp. v poli budou nakonec ukazatele na dané prvky, protože chci, aby se neměnila jejich adresa:
{ { /* ... */, 0 }, { /* ... */, 1 }, { /* ... */, 2 }, { /* ... */, 3 }, { /* ... */, 4 }, }Z pole si někam třeba uložim položku s indexem 2, dostanu
Prvek*
, ukazující na { /* ... */, 2 }. Pak třeba do pole něco přidám, nebo ho nějak jinak seřadím. Chci, aby se index ve vráceném prvku patřičně aktualizoval, aby měl správný index a já pak mohl říct třeba "smaž prvek Prvek*" a nemusel ho v poli vyhledávat v O(n).
Tak tady je ještě obecnější řešení než níže uvedené. Třídit můžeš implicitně pomocí std::set
a std::map
. Implementace jsou vyvážené stromy a nikde tam ani náhodou nehrozí hledání v O(n). Můžeš si podle potřeby udržovat několik různě setříděných „pohledů“ do téže datové struktury.
#include <map> #include <set> #include <string> struct Something { std::string blah; size_t index; }; static std::ostream& operator <<(std::ostream &out, const Something &sth) { out << "{\"" << sth.blah << "\", " << sth.index << "}"; return out; } struct CompareSomething { bool operator ()(const Something *const &left, const Something *const &right) const { return left->blah > right->blah; } }; template<template<typename ... Args> class M, typename ... Args> static void printmap(const M<Args...> &map, const std::string &message) { const auto end{map.cend()}; auto i{map.cbegin()}; std::cout << message << std::endl << '{'; if (i != end) { std::cout << '{' << i->first << ", " << i->second << '}'; for (++i; i != end; ++i) std::cout << ", " << '{' << i->first << ", " << i->second << '}'; } std::cout << '}' << std::endl; } int main() { std::map<size_t, Something> indexmap{ {0, {"data 0", 0}}, {1, {"data 1", 1}}, {2, {"data 2", 2}}}; std::set<const Something*, CompareSomething> sortedview; for (const auto &pair : indexmap) sortedview.insert(&pair.second); printmap(indexmap, "Původní stav:"); auto first{sortedview.cbegin()}; indexmap.erase((*first)->index); sortedview.erase(first); printmap(indexmap, "Stav po odebrání prvního podle třídění:"); indexmap.emplace(3, Something{"data 3", 3}); sortedview.insert(&indexmap[3]); printmap(indexmap, "Stav po přidání dalšího prvku:"); auto second{sortedview.cbegin()}; ++second; indexmap.erase((*second)->index); sortedview.erase(second); printmap(indexmap, "Stav po odebrání druhého podle třídění:"); return 0; }
Dlužno dodat, že v tomto případě by bylo výrazně jednodušší použít místo Something
jednoduše rovnou std::pair<size_t, std::string>
. Tím by zmizela jedna úroveň zanoření struktur. Výše uvedený program vypíše:
Původní stav: {{0, {"data 0", 0}}, {1, {"data 1", 1}}, {2, {"data 2", 2}}} Stav po odebrání prvního podle třídění: {{0, {"data 0", 0}}, {1, {"data 1", 1}}} Stav po přidání dalšího prvku: {{0, {"data 0", 0}}, {1, {"data 1", 1}}, {3, {"data 3", 3}}} Stav po odebrání druhého podle třídění: {{0, {"data 0", 0}}, {3, {"data 3", 3}}}
Ano, je na to standardní algoritmus zvaný std::sort()
. Aktualizaci indexů si pak už musíš napsat sám, což ale není nijak extra těžké:
#include <algorithm> #include <iostream> #include <string> struct Something { std::string blah; size_t index; bool operator <(const Something &right) const { return blah > right.blah; } }; static std::ostream& operator <<(std::ostream &out, const Something &sth) { out << "{\"" << sth.blah << "\", " << sth.index << "}"; return out; } template<typename T, size_t N> void printarray(const T(&array)[N], const std::string &message) { const auto begin{std::begin(array)}, end{std::end(array)}; std::cout << message << std::endl << '{'; if (begin < end) { std::cout << *begin; for (auto i{begin + 1}; i < end; ++i) std::cout << ", " << *i; } std::cout << '}' << std::endl; } int main() { Something array[]{{"data 0", 0}, {"data 1", 1}, {"data 2", 2}}; printarray(array, "Počáteční stav:"); std::sort(std::begin(array), std::end(array)); printarray(array, "Stav po std::sort():"); size_t counter{0}; for (Something &s : array) s.index = counter++; printarray(array, "Stav po aktualizaci indexů:"); return 0; }Výše uvedený program vypíše následující:
Počáteční stav: {{"data 0", 0}, {"data 1", 1}, {"data 2", 2}} Stav po std::sort(): {{"data 2", 2}, {"data 1", 1}, {"data 0", 0}} Stav po aktualizaci indexů: {{"data 2", 0}, {"data 1", 1}, {"data 0", 2}}
Tiskni
Sdílej:
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.