Portál AbcLinuxu, 6. listopadu 2025 04:22
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.