Ahoj, potřebovala bych pomoct s úkolem: (pokud možno nějaký jednoduchý program v C).
Na vstup programu je dána posloupnost max. 50 celých čísel (pole). Napište funkci, která vrátí druhé nejmenší ze zadaných čísel. Dále napište funkci, která vypíše (na základě vrácené hodnoty předchozí funkce) na obrazovku všechny pozice v poli, kde se nachází nalezené druhé nejmenší číslo.
V programu zavolej výše uvedené funkce.
(příklad: pole: 2, 5, 4, 2, 8, 9, 45, 2, 6, 2, 1 funkce vrátí: Druhé nejmenší číslo: 2 funkce vypíše na obrazovku: Pozice: 1, 4, 8, 10
Fórum › C / C++
Druhé nejmenší číslo v poli
Druhá funkce je snažší: projdu pole a vypisuji indexy (s polem pracuji pomocí indexů) prvků shodných se zadaným číslem - první číslo má index 0. Pokud by pan učitel trval na tom, že jsou pozice číslovány 1 až 50, stačí k indexu čísla přičíst 1.
První funkce
- "hrubou silou": Zkopíruji dané pole a seřadím ho např. buble sortem. Pak je druhý prvek seřazeného pole druhým nejmenším číslem
- trochu inteligentněji: v poli hledám dvě nejmenší čísla (abych věděl, které je druhé nejmenší, potřebuji vědět, které je nejmenší). Vezmu si první dva prvky pole, seřadím je podle velikosti a budu je prozatím považovat za dvě nejmenší čísla - nazvěme to mezivýsledek. Projdu zbylou část pole a budu každý prvek porovnávat s mezivýsledkem:
a) pokud je prvek pole menší než menší číslo mezivýsledku, menší číslo mezivýsledku se stane větším číslem mezivýsledku a prvek se stane menším číslem mezivýsledku
b)pokud je prvek pole menší než větší číslo mezivýsledku, stává se prvek větším číslem mezivýsledku
po projití celého pole vracím větší číslo mezivýsledku
hu
Má to nějaké drobnosti - pokud budou hned první dvě čísla nebo všechna čísla v poli stejná, nebude to fungovat správně. Ale pro inspiraci:
//funkce musi dostat pole obsahujici nejmene 2 cisla
int NajdiDruheNejmensi(int* Pole, int PocetCisel)
{
int mezivysledek[2];
int i;
//prvni dva prvky pole seradim podle velikosti a pouziju jako mezivysledek
if (Pole[0] < Pole[1]) {
mezivysledek[0] = Pole[0];
mezivysledek[1] = Pole[1];
}
else {
mezivysledek[0] = Pole[1];
mezivysledek[1] = Pole[0];
}
//projdu zbylou cast pole
for (i = 2; i < PocetCisel; i++) {
if (Pole[i] < mezivysledek[0]) {
//prvek pole je mensi nez mensi cislo mezivysledku
mezivysledek[1] = mezivysledek[0];
mezivysledek[0] = Pole[i];
}
else
if ((Pole[i] < mezivysledek[1]) && (Pole[i] > mezivysledek[0])) {
//prvek pole je mensi nez vetsi cislo mezivysledku
mezivysledek[1] = Pole[i];
}
}
//v mezivysledku jsou dve nejmensi cisla
return mezivysledek[1];
}
//*************************************************************
void VypisPozice(int* Pole, int PocetCisel, int Cislo)
{
int i;
char c = 0x20; //mezera
printf("pozice cisla %i jsou:", Cislo);
for (i = 0; i < PocetCisel; i++) {
if (Cislo == Pole[i]) {
printf("%c%i", c, i+1);
c = ',';
}
}
}
//*************************************************************
int _tmain(int argc, _TCHAR* argv[])
{
int cisla[] = {2, 5, 4, 2, 8, 9, 45, 2, 6, 2, 1};
int pocet = 11;
int druhe;
druhe = NajdiDruheNejmensi(cisla, pocet);
printf ("Druhe nejmensi je %i\r", druhe);
VypisPozice(cisla, pocet, druhe);
return 0;
}
hu
ta funkce "druhenejmenší" mě přijde moc složitá.
takhle by to mělo stačit:
#include <limits.h>
int DruheNejmensi(unsigned int velikost_pole, int *pole)
{
int ok = INT_MAX;
int min_val = INT_MAX;
for(unsigned int i=0; i<velikost_pole; i++)
{
if(pole[i]<min_val)
{
ok = min_val;
min_val = pole[i];
}
else if(pole[i]>min_val && ok>pole[i])ok=pole[i];
}
//if(ok == INT_MAX && pole[0]<INT_MAX)return pole[0];
return ok;
}
doufám, že jsem nic neopomněl :)
#5 Matěj Andrle
Vůbec neplníš zadání. Cílem není seřadit pole, ale najít druhé nejmenší číslo v poli. V takovém případě je zkopírování a seřazení pole neefektivní. Najít druhé nejmenší číslo lze na jedno projití stávajícího pole.
Kromě toho vracení autovariable result: paměť pro tuto proměnnou je uvolňována při návratu funkce.
int result[length]; ti v čistém C neprojde.
hu
#7 Matěj Andrle
Kopírovat musíš, podle zadání je potřeba mít původní pole pro funkci výpisu pozic. To je jeden cyklus. Řazení obsahuje uvnitř minimálně další cyklus (buble sort obsahuje tuším 2 vnořené cykly). Seřazení má ještě další nevýhodu - představ si, že nejmenší číslo se v poli bude opakovat:
pole[] = {5, 48, 7, 5, 11};
Po seřazení dostaneš 5, 5, 7, 11, 48. Druhé nejmenší (číslo 7) tedy není automaticky prvkem s indexem 1. Musely by se odstranit stejné prvky pole - každé číslo se smí vyskytnou pouze 1x. Druhá možnost je procházet seřazené pole dokud nenarazím na jiné číslo než je první prvek pole - to je další cyklus.
hu
#7 Matěj Andrle
jedinej problem je, ze kdyz si prectes zadani, tak chteji unikatni nejmensi. Takze nejen O(log n) pro sort - pokud je to quicksort, ale jeste to budes dal zpracovavat. Takze jeden cyklus, kde se vse udela rovnou je rychlejsi nez si to seradit.
Pak vracis pointer na promennou na stacku - coz by melo zminit aspon warning, v lepsim pripade error a v nejhorsim pripade se ti jen pri volani cehokoliv dalsiho zahadne zmeni hodnoty v poli...
Kromě toho ta dlouhá nudle obsahuje celou úlohu - obě funkce i funkci main s jejich použitím. Ještě jsem si pohrál s těma opomenutýma drobnostma a funkce by vypadala takto (není přezkoušená):
//funkce vrati nenulove cislo pokud lze najit druhe nejmensi
//druhe nejmensi je ulozeno do promenne na kterou ukazuje Vysledek
int NajdiDruheNejmensi(int* Pole, int PocetCisel, int* Vysledek)
{
int mezivysledek[2];
int i, j, priznak = 0;
if (PocetCisel < 2) {
return 0;
}
//prvni dva ruzne prvky pole seradim podle velikosti a pouziju jako mezivysledek
for (j = 1; j < PocetCisel; j++) {
if (Pole[0] < Pole[j]) {
mezivysledek[0] = Pole[0];
mezivysledek[1] = Pole[j];
priznak = 1;
break;
}
else
if (Pole[0] > Pole[j]) {
mezivysledek[0] = Pole[j];
mezivysledek[1] = Pole[0];
priznak = 1;
break;
}
}
if (!priznak) {
return 0;
}
//projdu zbylou cast pole
for (i = 2; i < PocetCisel; i++) {
if (Pole[i] < mezivysledek[0]) {
//prvek pole je mensi nez mensi cislo mezivysledku
mezivysledek[1] = mezivysledek[0];
mezivysledek[0] = Pole[i];
}
else
if ((Pole[i] < mezivysledek[1]) && (Pole[i] > mezivysledek[0])) {
//prvek pole je mensi nez vetsi cislo mezivysledku
mezivysledek[1] = Pole[i];
}
}
//v mezivysledku jsou dve nejmensi cisla
*Vysledek = mezivysledek[1];
return 1;
}
A použití:
int _tmain(int argc, _TCHAR* argv[])
{
int cisla[] = {2, 5, 4, 2, 8, 9, 45, 2, 6, 2, 1};
int pocet = 11;
int druhe;
if (NajdiDruheNejmensi(cisla, pocet, &druhe)) {
printf ("Druhe nejmensi je %i\r", druhe);
VypisPozice(cisla, pocet, druhe);
}
else {
printf ("Nejde najit druhe nejmensi cislo");
}
return 0;
}
hu
Ještě by se návratová hodnota funkce dala upravit tak, aby vyjadřovala příčinu, proč nemá druhé nejmenší číslo - málo čísel v poli nebo všechna jsou stejná. I bez toho si myslím, že už teď tazatelce "jde hlava kolem".
hu
#13 ondrej39
zkusil jsem, co se stane, když v poli budou stejná čísla:
int _tmain(int argc, _TCHAR* argv[])
{
int cisla[] = {2, 2, 2};
int pocet = 3;
int druhe;
druhe = DruheNejmensi(pocet,cisla);
printf ("Druhe nejmensi je %i\r", druhe);
}
a výsledek byl 2147483647, naprostý nesmysl. Nedetekuje zadání všech stejných čísel v poli. Proto jsem funkci upravoval tak, aby návratová hodnota bylo "existuje / neexistuje" druhé nejmenší číslo a pokud existuje, druhé nejmenší číslo se zapíše do proměnné na kterou funkce dostala ukazatel jako třetí parametr. Po drobné úpravě by funkce mohla vracet chybový kód a rozlišovat existuje / všechna čísla v poli jsou stejná / je málo čísel v poli.
hu
#15 hlucheucho
Že nastane situace, kdy budou všechna čísla stejně velká, mě nenapadlo. Pokud takovou situaci vezmu v úvahu, pak funkce bude o něco složitější, ale myslím si, že tvá stejně zbytečně implementuje druhý for cyklus.
EDIT: No nic, radši budu zticha, ta moje funkce neměla ověřenou jednu podmínku :D.
EDIT2: Tak jsem na chybu přišel, chyběla mi jedna podmínka :).
bool druheNejmensi(const int* pole, int velikost, int &vysledek)
{
int nejmensi = INT_MAX;
int druheNejmensi = INT_MAX;
int zmena = 0;
int i;
for (i = 0; i < velikost; i++)
{
if (pole[i] < nejmensi)
{
if (zmena != 2) zmena++;
druheNejmensi = nejmensi;
nejmensi = pole[i];
continue;
}
else if (pole[i] < druheNejmensi && pole[i] > nejmensi)
{
if (zmena != 2) zmena++;
druheNejmensi = pole[i];
}
}
vysledek = druheNejmensi;
if (zmena != 2) return false;
return true;
}
Teď by ta f-ce měla najít druhé nejmenší číšlo pouze v případě, že se tam takové číslo nachází (když najde, vrací true, když nenajde, vrací false), a to i v případě, kdyby se v poli nacházely pouze dvě číselné hodnoty, číslo nejmenší a číslo druhé nejmenší.
Kdyz sme u toho reseni :D Tak prikladam jedno pro bezne smrtelniky hure stravitelne :D
#include <stdio.h>
#define POS 2
int * findPOSMin(int * arr, int count) {
int * min[POS] = {NULL};
int * end = arr+count;
for (; arr < end; ++arr) {
int * act = arr;
int i;
for (i=0; i<POS; ++i) {
if ((act != NULL) && (min[i]!=NULL) && (*act == *(min[i]))) break;
if ((min[i] == NULL) || ((act != NULL) && (*(min[i]) > *act))) {
int * tmp = act;
act = min[i];
min[i] = tmp;
}
}
}
return min[POS-1];
}
int main(void) {
int pole[] = {2, 5, 4, 2, 8, 9, 45, 2, 6, 2, 1, 5, 4, 3};
int * pos = findPOSMin(pole,sizeof(pole)/sizeof(int));
if (pos) {
int *i;
printf("%d. nejmensi %d\n", POS, *pos);
printf("Pozice: %ld", (pos-pole)+1);
for (i=pos+1; i<pole+11; ++i) {
if (*pos==*i) printf(", %ld", (i-pole)+1);
}
printf("\n");
} else {
printf("%d. nejmensi: nenalezeno\n", POS);
}
return 0;
}
Samo s troskou dynamiky by to mohlo byt jako parametr funkce misto define, ci rovnou programu :)
#20 hlucheucho
v tomhle smeru neni jasna ani ukazka ani zadani.. Ale kdyz chteji vypisovat i vyskyty toho sameho 2. cisla, tak predpokladam, ze se berou vsechny jako 2. a ne jako 2. 3. 4. 5. To ze se muzu plest je proste chyba nejasneho zadani :D
#23 hlucheucho
V běžném C není bool? :O Že tam nebude vector, to tak nějak předpokládám, ale bool považuji celkem za základ. A modifikátory const a tak v C jsou? Pokud ano, tak by pole funkci mělo být ještě předáváno jako konstantní ukazatel na první prvek, pro zamazení modifikace s ním.
Nicméně pokud jsou toto dvě chyby, nahradit ampersand za hvězdičku a vracet 1 0 namísto true/false je pro opravení to nejmenší :).
#22 KIIV
teď ti nerozumím.
Zadání připouští vícenásobný výskyt druhého nejmenšího čísla v poli. Pokud mám 3, 2, 3, 3, 3, 9 tak mám druhé nejmenší číslo 3 na pozicích 1, 3, 4 a 5. Pokud mám 7, 7, 7, 7 tak druhé nejmenší číslo v poli neexistuje, protože všechna čísla jsou stejná. Podobně když bude jen jedno číslo.
hu
#28 hlucheucho
No proste prvni if s tim break se postara o preskoceni cisel, ktery tam uz jsou
Druhy to prohodi s act, pokud je aktualni minimum null nebo je mensi nez act (a act jeste nesmi byt null)
Vyhoda je, ze to funguje iteracne, nevyhoda je, ze to neni tak dobre videt pres ty vsechny pointery.
Vyhoda je, ze to funguje iteracne, nevyhoda je, ze to neni tak dobre videt pres ty vsechny pointery.
na tom jsem si vylámal zuby. Teď budu mít komplex méněcennosti
hu
#30 hlucheucho
z toho si nic nedelej, ja sem v tom mel po napsani presne dve chyby - chybel mi ten end (jsem prubezne posouval konec a slo to do segfaultu) a druha chyba bylo to, ze mi chybel ten prvni if :) (bez nej to sice fungovalo na tech vzorovejch datech na zacaku, ale samozrejme to pak vkladalo stejny cisla vicekrat)
Dokázal jsi vymyslet princip a pak to i odladit.
Asi je poznat, že jsem začínal hodně pozdě a mám málo praxe.
hu
Z hlediska rychlosti, nebylo by lepsi pouzit misto scitani, odcitani pouze incrementovani?
Treba, kdyz mam cyklus kod neco jako
a = 7;
b = 30;
for(i=0;i<a+10;i++) {pole[b - i];}
Tak misto toho pouzit
a = 7;
b = 30;
c = a+10;
d = b;
for(i=0;i<c;i++) {pole[d--];}
Ja jen, ze pri milionech cyklu, kdyz musi pokazde prepocitavat podminku ve for "i<a+10" a pokazde odcitat "b-i", tak to sezere more casu.
#34 peter
To bys musel zkompilovat do assembleru a porovnat podle vystupu pri nejaky vhodny urovni optimalizace..
Kazdopadne to muze klidne skoncit v sekci: "premature optimalisation is root of all evil" :D
#14 hlucheucho
v mém příkladu jsem zakomentoval
if(ok == INT_MAX && pole[0]<INT_MAX)return pole[0];
kdyby někomu vadilo, že bude funkce vracet číslo INT_MAX, které v poli není..
on je skoro stejný nesmysl vracet jakékoliv číslo jako druhé nejmenší, když jsou všechna čísla shodná
ps, ani nevím jestli lze nazvat posloupností, pole stejných čísel
#15 hlucheucho
před lety jsem se učil základy C pouze podle této knihy (tehda jsem ani neměl přístup na net):
http://knihy.cpress.cz/programovaci-jazyk-c.html
for(int i=0;... se tam používalo běžně, tak proto..
Dnes píšu stylem guláš (C C++), tak přesně ani nevím kde jsou hranice.
#37 BDS
C99 standard uz for (int i=0;;) dovoluje, ale na skolach se vetsinou jede strict verze, ktera ti snad nedovoli ani deklarace promennych smichane s kodem.. proste musi byt na zacatku bloku, pred samotnym kodem.
Jinak ja jsem taky primarne c++ programator, ale nejak zvlast se mi to neplete - asi jak jsem zacinal na striktni specce C.
#39 hlucheucho
já jsem to právě včera psal jen tak, bez IDE.
tak tady máš opravený kód, doufám už se vším co patří k C a pouze k C
#include <stdio.h>
#include <limits.h>
//---------------------------------------------------------------------------
int DruheNejmensi(unsigned int velikost_pole, int *pole)
{
int ok = INT_MAX;
int min_val = INT_MAX;
unsigned int i=0;
for(; i<velikost_pole; i++)
{
if(pole[i]<min_val)
{
ok = min_val;
min_val = pole[i];
}
else if(pole[i]>min_val && ok>pole[i])ok=pole[i];
}
//if(ok == INT_MAX && pole[0]<INT_MAX)return pole[0];
return ok;
}
//---------------------------------------------------------------------------
void Vypis(int value, unsigned int velikost_pole, int *pole)
{
unsigned int i=0;
unsigned char cnt = 0;
for(; i<velikost_pole; i++)
{
if(value==pole[i])
{
if(cnt==0)
{
printf("Pozice cisla %i: %u", value, i+1);
cnt++;
}
else printf(", %u", i+1);
}
}
}
//---------------------------------------------------------------------------
int main()
{
const unsigned int velikost = 11;
int vstup[] = {2, 5, 4, 2, 8, 9, 45, 2, 6, 2, 1};
int druhe;
druhe = DruheNejmensi(velikost, vstup);
if(druhe==INT_MAX)printf("V poli se nachazeji pouze cisla s hodnotou %i\n", vstup[0]);
else
{
printf("Druhe nejmensi je cislo %i\n", druhe);
Vypis(druhe, velikost, vstup);
}
getchar();
return 0;
}
//---------------------------------------------------------------------------
#40 BDS
Slo by to aj jednoduhsie:
int DruheNejmensi(unsigned velikost_pole, const int *pole){ assert(pole); assert(velikost_pole >= 1); int min_val = pole[0]; int ok = min_val; for(unsigned i = 1; i < velikost_pole; ++i){ if(pole[i] < min_val){ ok = min_val; min_val = pole[i]; } }
//edit: if(min_val == ok)return INT_MAX; return ok; }
#51 vitamin
1: http://programujte.com/forum/vlakno/28803-druhe-nejmensi-cislo-v-poli/#p198873
2: když bude první číslo nejmenší tak tvá funkce vrátí jej
protože tam máš toto: if(pole[i] < min_val)
Má pravdu předsedo: pokud první číslo pole bude nejmenší, ve všech iteracích cyklu bude podmínka vyhodnocena false. Funkce nenajde druhé nejmenší ačkoliv třeba existuje. Vyzkoušej si to na seřazeném poli např 1, 2, 3, 4, 5. Z tohoto důvodu moje funkce nejdříve hledala první dva různé prvky pole a ty seřadila podle velikosti a pak je použila pro další práci.
hu
Od C99 nemusi byt deklaracia premennej na zaciatku bloku.
ne každý překladač tak pracuje, platí to i o novějších verzích
hu
trapas, až dnes jsem si uvědomil, že tam mám chybu:
if(druhe==INT_MAX)printf("V poli se nachazeji pouze cisla s hodnotou %i\n")
v případě, že budou v poli pouze hodnoty INT_MAX a INT_MAX-1 nebude vyhodnocení této podmínky v pořádku
teď snad už konečně...
#include <stdio.h>
#include <limits.h>
//---------------------------------------------------------------------------
char DruheNejmensi(unsigned int velikost_pole, int *pole, int *druhe_nejm)
{
int min_val = INT_MAX;
unsigned int i=0;
char ret = 0x00;
*druhe_nejm = INT_MAX;
for(; i<velikost_pole; i++)
{
if(pole[i]<min_val)
{
*druhe_nejm = min_val;
min_val = pole[i];
ret = 0x02;
}
else
{
if(pole[i]>=min_val && *druhe_nejm>pole[i])
{
*druhe_nejm=pole[i];
ret = 0x01;
}
}
}
if(*druhe_nejm == min_val)ret = 0x00;
return ret;
}
//---------------------------------------------------------------------------
void Vypis(int value, unsigned int velikost_pole, int *pole)
{
unsigned int i=0;
unsigned char cnt = 0;
for(; i<velikost_pole; i++)
{
if(value==pole[i])
{
if(cnt==0)
{
printf("Pozice cisla %i: %u", value, i+1);
cnt++;
}
else printf(", %u", i+1);
}
}
}
//---------------------------------------------------------------------------
int main()
{
const unsigned int velikost = 11;
int vstup[] = {2, 5 ,4, 2, 8, 9, 45, 2, 6, 2, 1};
int druhe;
if(DruheNejmensi(velikost, vstup, &druhe)==0x00)printf("V poli se nachazeji pouze cisla s hodnotou %i\n", vstup[0]);
else
{
printf("Druhe nejmensi je cislo %i\n", druhe);
Vypis(druhe, velikost, vstup);
}
getchar();
return 0;
}
//---------------------------------------------------------------------------
to zadání s funkcí vracející hodnotu se to bez úplného vychytání všech možností nedá udělat
Přidej příspěvek
Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku
×Vložení zdrojáku
×Vložení obrázku
×Vložení videa
Uživatelé prohlížející si toto vlákno
Podobná vlákna
Nejmenší a největší číslo — založil W4RDON
Druhé největší číslo posloupnosti — založil John324
Posloupnost, která vyhosnotí nejmenší a největší číslo! — založil Martin
Unikátní číslo v poli — založil MaxDJs
Jak zjistit nejbližší číslo v poli — založil Krusty
Moderátoři diskuze