Diskuze: Zápis - Max a min
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Člen

Zobrazeno 8 zpráv z 8.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
V tomhle případě bych asi udělal pomocné pole čísel, kam bych ukládal minima a maxima - tady by vypadalo nějak takhle:
{ 10, 0, 7, 2}
Výhodu to má, že s tím můžeš dál pracovat a snadno můžeš kód upravit, kdybys ty maxima nepotřeboval 2, ale třeba 2000.
Jestli potřebuješ rozlišit, co je maximum a minimum, tak to zase uděláš druhým pomocným polem, a to s hodnotami typu bool.
Možná by ale nebylo od věci slít všechno do jednoho pole a udělat si z dvojice int:bool (hodnota:max/min) strukturu (struct) a tu ukládat do jednoho pomocného pole. Určitě by to šlo více způsoby.
Vytvoříš dynamicky alokované jednorozměrné pole celých čísel, do kterého budeš postupně ukládat společně minima a maxima ze zadaného pole. Porovnáváním sousedních prvků zadaného pole zjišťuješ, zda-li je průběh rostoucí čí klesající. Postupným porovnáváním sousedních prvků zjišťuješ udržení rostoucí nebo klesající tendence. Pokud se tendence mění, zapisuješ hodnotu do dynamicky alokovaného pole. Toto pole dle potřeby zvětšuješ. Pokud pole obsahuje jeden prvek (ten první), pak výsledkem je konstantní průběh. Pokud pole obsahuje více než jeden prvek, pak porovnáním prvního a druhého prvku zjišťuješ, zda-li je jako první průběh rostoucí nebo klesající. Na základě tohoto určíš, zda-li prvním prvkem je minimum nebo maximum. Z důvodu střídající tendence postačí vytvoření pouze jednoho výše uvedeného dynamicky alokovaného pole.
Já bych to udělal nějak takhle:
static void Main(string[] args)
{
int[] array = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2 };
split(array.ToList(), Array.IndexOf(array, array.Max()), true, 4);
Console.ReadKey();
}
static void split(List<int> array, int index, bool max_min, int count)
{
if (count > 0)
{
Console.WriteLine(array.toString());
Console.WriteLine($"{(max_min ? "Maximum" : "Minimum")}: {array[index]}");
array.RemoveRange(0, index + 1);
if (array.Count > 0)
split(array, array.IndexOf(!max_min ? array.Max() : array.Min()), !max_min, count - 1);
}
}
Pokaždé zjistim index MAX/MIN v poli a vše co je před indexem, už nepotřebuju ... smažu
Dobrosrdeční lidé ti už tady dali rady či kusy kódu. Já ti neporadím
přímo, ale dokázal bys ty lokální špičky (minima a maxima) najít ty sám
(jako člověk)? Pokud ano, máš algoritmus, který si jen potřebuješ
nakreslit na papír (pro uvědomění si) a pak už jen převést do
příslušného programovacího jazyku.
Hint: když ty špičky hledáš ty osobně, jaké informace si musíš
poznačit (ať už v paměti nebo na papír)?
Těší mě že jsem předal dobře myšlenku a všichni chápete co mám na mysli. Avšak jsem tak trochu začátečník takže pokud by se tady našel někdo kdo by mi svoji ideu vysvětlil víc polopaticky.
Kód od Michala funguje ovšem pouze na tento zadaný příklad. Od Petra se mi líbí ta myšlenka škálovatelnosti, protože přesně to bych v budoucnu potřeboval. Jak poznávám "špičky"? Tak ze ty čísla převedu do grafu.
Měl bych uvést jak to přesně je. Reálně je to pole typu double o
velikosti cca 200 hodnot.
A hodnoty se střídají. tzn že nemusí jít chronologicky za sebou. V mém
příkladě to může vypadat takto.
10,9,8,7, 7.5,7,8,
6,5,4,3,2,1,0,1,2,3,4,5,6,7,6,5,4,3,2.
Potřebuji zjistit větší max a min tzn. aby kód ignoroval nějaké menší odchylky.
Mě napadlo že využiji samotné číslo indexu. Tzn pokud číslo 10 je v indexu na místě 25, tak od 25 místa hledej minimum. Až najde minimum tak od této hodnoty hledej maximum atd...
A co takový "trend funkce"? Sprostý výraz? Vážně není!
Uvědom si, co ty sám provádíš, když "skenuješ" sekvenci a ty špičky
hledáš. Najdeš trend funkce a bod jeho změny prohlásíš za lokální
maximum (tedy pokud budeme ignorovat "záchvěvy").
Trošku lidštěji:
0tý index: z jednoho bodu trend nepoznáš - jsi v pytli a musíš si
zapamatovat fakt, že trend zatím neznáš.
1ní index: už máš dvě hodnoty a z nich už dokáš určit trend
(klesající/stoupající). Paráda.
2hý index: splňuje prvek trend? Ano->pokračuješ ve skenu.
Ne->Předchozí prvek prohlásíš za lokální maximum, poznačíš si
opačný trend, pokračuješ ve skenu.
No není to easy?
Pokud chceš zapracovat ignoraci zákmitů, musíš si určit jeho max velikost
a zvětšit peek scan (česky asi dopředný scan). Taky by se hodila znalost
rekurze (i když to jde I bez ní). Krásně ji použil Michael.
Co třeba něco takového? Procházíš pole a kontroluješ aktuální prvek s předchozím a následujícím s tím, že první a poslední prvek přidáš automaticky do výsledného listu.
static void Main(string[] args)
{
double[] array={ 10, 9, 8, 7, 7.5, 7, 8, 6, 5, 4, 3, 2, 1,0, 1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2};
List<double> extrems = new List<double>();
for (int i = 0; i < array.Length; i++)
if (i == 0 || i == array.Length - 1) extrems.Add(array[i]);
else if ((array[i + 1] > array[i] && array[i - 1] > array[i]) || (array[i + 1] < array[i] && array[i - 1] < array[i]))
extrems.Add(array[i]);
Console.WriteLine(string.Join(", ", extrems));
}
Výpis:
10, 7, 7,5, 7, 8, 0, 7, 2
Zobrazeno 8 zpráv z 8.