(3 kwiecień 2014) Marika Pankowska Kamila Pietrzak
Wyszukiwanie liniowe (ang. linear search), zwane również sekwencyjnym (ang. sequential search) polega na przeglądaniu kolejnych elementów zbioru Z. Jeśli przeglądany element posiada odpowiednie własności (np. jest liczbą o poszukiwanej wartości), to zwracamy jego pozycję w zbiorze i kończymy. W przeciwnym razie kontynuujemy poszukiwania aż do przejrzenia wszystkich pozostałych elementów zbioru Z. Problem W n-elementowym zbiorze Z wyszukać element posiadający pożądane własności.
W przypadku pesymistycznym, gdy poszukiwanego elementu nie ma w zbiorze lub też znajduje się on na samym końcu zbioru, algorytm musi wykonać przynajmniej n obiegów pętli sprawdzającej poszczególne elementy. Wynika z tego, iż pesymistyczna klasa złożoności obliczeniowej jest równa O(n), czyli jest liniowa stąd pochodzi nazwa metody wyszukującej. Często chcemy znaleźć wszystkie wystąpienia w zbiorze poszukiwanej wartości elementu. W takim przypadku algorytm na wejściu powinien otrzymywać dodatkowo pozycję (indeks) elementu, od którego ma rozpocząć wyszukiwanie. Pozycję tę przy kolejnym przeszukiwaniu podajemy zawsze o 1 większą od ostatnio znalezionej. Dzięki temu nowe poszukiwanie rozpocznie się tuż za poprzednio znalezionym elementem.
Algorytmy wyszukiwania liniowego/sekwencyjnego Lista kroków: K01: Dla i = p,p+1,...,n-1: wykonuj K02 - przeglądamy kolejne elementy w zbiorze; K02: Jeśli Z[i] = k, to zakończ z wynikiem i - jeśli napotkamy poszukiwany element, zwracamy jego pozycję; K03: Zakończ z wynikiem -1 - jeśli elementu nie ma w tablicy, zwracamy -1; Wejście: n - liczba elementów w tablicy Z, n N Z - tablica zawierająca elementy do przeszukania. Indeksy elementów rozpoczynają się od 0, a kończą na n-1 p - indeks pierwszego elementu Z, od którego rozpoczniemy poszukiwania p C k - poszukiwana wartość, czyli tzw. klucz, wg którego wyszukujemy elementy w Z. Wyjście : Pozycja elementu zbioru Z o kluczu k lub -1 w przypadku nieznalezienia elementu. Zmienne pomocnicze: i - przebiega przez kolejne indeksy elementów Z. i C
Program #include <iostream> using namespace std; int Szukaj(int T[], int n, int k, int p) for(int i = p; i < n; i++) if(t[i] == k) return i; return -1; int main() int * Z,n,k,i; cin >> n; Z = new int [n]; for(i = 0; i < n; i++) cin >> Z[i]; cin >> k; cout << endl << Szukaj(Z,n,k,0) << endl << endl; delete [] Z; system("pause"); return 0; Program odczytuje z pierwszego wiersza liczbę n. Z następnych n wierszy odczytywane jest n danych całkowitych. W ostatnim wierszu odczytywana jest liczba k, którą należy wyszukać wśród podanych n liczb. Program wypisuje numer pozycji w odczytanym ciągu liczb, na której znajduje się liczba k lub -1, jeśli liczby nie odnaleziono.
#include <iostream> #include <cstdlib> #include <time.h> using namespace std; int main() int Z[100],i,w; bool L[100]; srand((unsigned)time(null)); for(i = 0; i < 100; i++) Z[i] = rand() % 10; w = rand() % 10; for(i = 0; i < 100; i++) L[i] = (Z[i] == w); cout << w << endl << endl; for(i = 0; i < 100; i++) if(l[i]) cout << " ->"; else cout << " "; cout << Z[i]; cout << endl; system("pause"); return 0; Program Program wypełnia 100 elementową tablicę Z całkowitymi liczbami pseudolosowymi z zakresu od 0 do 9. Następnie losuje nową liczbę pseudolosową z tego samego zakresu i znajduje wszystkie jej wystąpienia w Z przy pomocy wyszukiwania liniowego. Na końcu wyświetla wylosowaną liczbę oraz zawartość Z z zaznaczonymi jej wystąpieniami. Do zapamiętywania wystąpień służy druga tablica L o elementach logicznych. Jeśli i- ty element tej tablicy zawiera true, to w i-tym elemencie tablicy Z znajduje się poszukiwany element.
Problem W n-elementowym zbiorze Z znaleźć element o maksymalnej (minimalnej) wartości. Zadanie znajdowania elementu maksymalnego lub minimalnego jest typowym zadaniem wyszukiwania, które rozwiązujemy przy pomocy algorytmu wyszukiwania liniowego. Za tymczasowy maksymalny (minimalny) element przyjmujemy pierwszy element zbioru. Następnie element tymczasowy porównujemy z kolejnymi elementami. Jeśli któryś z porównywanych elementów jest większy (mniejszy) od elementu tymczasowego, to za nowy tymczasowy element maksymalny (minimalny) przyjmujemy porównywany element zbioru. Gdy cały zbiór zostanie przeglądnięty, w elemencie tymczasowym otrzymamy element maksymalny (minimalny) w zbiorze. Poniżej podajemy algorytm wyszukiwania max. Wyszukiwanie min wykonuje się identycznie, zmianie ulega tylko warunek porównujący element tymczasowy z elementem zbioru w kroku K03.
Algorytm wyszukiwania elementu maksymalnego w zbiorze Wyjście: n - liczba elementów w tablicy Z, n N Z - tablica zawierająca elementy do zliczania. Indeksy elementów rozpoczynają się od 0, a kończą na n-1. Wyjście: Wartość największego elementu zbioru. Zmienne pomocnicze: i przebiega przez kolejne indeksy elementów Z. i C max Z tymczasowy element maksymalny. Lista kroków: K01: max Z Z[0] - za tymczasowy element maksymalny bierzemy pierwszy element; K02: Dla i = 1,2,...,n-1 wykonuj K03 ; - przeglądamy następne elementy zbioru; K03: Jeśli Z[i] > max Z, to max Z Z[i] ; - jeśli natrafimy na większy od max Z, to zapamiętujemy go w max Z ; K04: Zakończ z wynikiem max Z
#include <iostream> Program #include <iomanip> #include <cstdlib> #include <time.h> using namespace std; const int N = 15; int main() int Z[N],i,maxZ,minZ; srand((unsigned)time(null)); for(i = 0; i < N; i++) Z[i] = rand() % 10000; maxz = minz = Z[0]; Program generuje 15 liczb pseudolosowych z zakresu od 0 do 9999. Wygenerowane liczby zapisuje w tablicy Z. Następnie wyszukuje liczbę najmniejszą i największą. Jako wynik jest wypisywana zawartość całej tablicy w 15 kolejnych wierszach, a w wierszu 17 liczba najmniejsza i największa. for(i = 1; i < N; i++) if(z[i] > maxz) maxz = Z[i]; if(z[i] < minz) minz = Z[i]; for(i = 0; i < N; i++) cout << setw(5) << Z[i] << endl; cout << endl << setw(5) << minz << setw(5) << maxz << endl << endl; system("pause"); return 0;
Czasami zależy nam nie na wartości elementu maksymalnego (minimalnego), lecz na jego pozycji w zbiorze. W tym przypadku musimy, oprócz wartości samego elementu maksymalnego (minimalnego), zapamiętywać jego pozycję, którą na końcu zwracamy jako wynik pracy algorytmu. Algorytm wyszukiwania pozycji elementu maksymalnego w zbiorze Wejście: n - liczba elementów w tablicy Z, n N Z - tablica zawierająca elementy do zliczania. Indeksy elementów rozpoczynają się od 0, a kończą na n - 1. Wyjście: Pozycja (indeks) elementu maksymalnego. W max Z jest wartość elementu maksymalnego. Zmienne pomocnicze: i - przebiega przez kolejne indeksy elementów Z. i C max Z - tymczasowy element maksymalny max p - pozycja tymczasowego elementu maksymalnego
Lista kroków: K01: max Z Z[0] - za tymczasowy element maksymalny bierzemy pierwszy element; K02: max p 0 - zapamiętujemy jego pozycję; K03: Dla i = 1,2,...,n-1 wykonuj K04...K06 - przeglądamy następne elementy zbioru; K04: Jeśli Z[i] max Z, to następny obieg pętli K03 - sprawdzamy, czy trafiliśmy na element większy od max Z ; K05: max Z Z[i] - jeśli tak, to zapamiętujemy wartość elementu w max Z ; K06: max p i - oraz jego pozycję w max p ; K07: Zakończ z wynikiem max p - zwracamy zapamiętaną pozycję.
Program #include <iostream> #include <iomanip> #include <cstdlib> Program generuje 15 liczb #include <time.h> pseudolosowych z zakresu od 0 do using namespace std; const int N = 15; 9999. Wygenerowane liczby zapisuje w int main() tablicy Z. Następnie wyszukuje liczbę najmniejszą i największą. Jako wynik int Z[N],i,maxZ,maxp,minZ,minp; srand((unsigned)time(null)); jest wypisywana zawartość całej tablicy for(i = 0; i < N; i++) Z[i] = rand() % 10000; w 15 kolejnych wierszach, a w wierszu maxz = minz = Z[0]; 17 podana zostaje pozycja elementu maxp = minp = 0; najmniejszego i największego for(i = 0; i < N; i++) if(z[i] < minz) minz = Z[i]; minp = i; if(z[i] > maxz) maxz = Z[i]; maxp = i; for(i = 0; i < N; i++) cout << setw(2) << i << " : " << setw(4) << Z[i] << endl; cout << endl << minp << ":" << maxp << endl << endl; system("pause"); return 0;
Problem W n-elementowym zbiorze Z znaleźć element maksymalny i minimalny. Jeśli do wyszukiwania elementu max i min zastosujemy standardowy algorytm, to otrzymamy: Wejście: n - liczba elementów w tablicy Z, n N Z - tablica zawierająca elementy do zliczania. Indeksy elementów rozpoczynają się od 0, a kończą na n - 1. Wyjście: Wartość najmniejszego i największego elementu w tablicy Z. Zmienne pomocnicze: i - przebiega przez kolejne indeksy elementów Z. i C max Z - tymczasowy element maksymalny min Z - tymczasowy element minimalny
Numer Operacja Liczba wykonań 1 min Z Z[0] 1 2 max Z Z[0] 1 3 i 1 1 4 Jeśli i = n, to idź do 9 n 5 Jeśli Z[i] < min Z, to min Z Z[i] n - 1 6 Jeśli Z[i] > max Z, to max Z Z[i] n - 1 7 i i + 1 n - 1 8 Idź do 4 n - 1 9 Pisz min Z, max Z 1 10 Zakończ 1
Zastanówmy się, czy można uzyskać lepszy wynik. Algorytm porównuje każdy element zbioru z min Z oraz z max Z. Tutaj tkwi nieefektywność. Obie operacje nr 5 i 6 są wykonywane po n - 1 razy, co daje w sumie 2n - 2 porównania w całym zbiorze. Wyobraźmy sobie, iż ze zbioru bierzemy parę 2 elementów i porównujemy je ze sobą. Element większy nie może być minimalnym, zatem nie musimy go już porównywać z min Z. Wystarczy porównanie z max Z. To samo dotyczy elementu mniejszego porównujemy go tylko z min Z. Otrzymujemy zysk poprzednio dwa elementy wymagały wykonania 4 porównań (każdy z min Z i max Z ). Teraz mamy: Jedno porównanie dwóch elementów, które rozdzieli je na element mniejszy i element większy. Element mniejszy porównujemy z min Z. Element większy porównujemy z max Z.
Daje to 3 porównania zamiast 4. Ponieważ ze zbioru pobieramy po dwa kolejne elementy, to ich liczba musi być parzysta. Jeśli zbiór ma nieparzystą liczbę elementów, to po prostu dublujemy ostatni element i dostaniemy parzystą liczbę elementów. Porównanie pary elementów dzieli zbiór na dwa podzbiory zbiór elementów większych i mniejszych. W podzbiorze elementów większych szukamy elementu maksymalnego, a w podzbiorze elementów mniejszych szukamy minimalnego. Ponieważ ich liczebność jest o połowę mniejsza od liczebności zbioru wejściowego, to wykonamy mniej operacji porównań. Metoda rozwiązywania problemów przez podział na mniejsze części w informatyce nosi nazwę Dziel i Zwyciężaj (ang. Divide and Conquer). Dzięki niej często udaje się zmniejszyć złożoność obliczeniową wielu algorytmów.
Algorytm jednoczesnego wyszukiwania max i min w zbiorze Wejście: n - liczba elementów w tablicy Z, n N Z - tablica zawierająca elementy do zliczania. Indeksy elementów rozpoczynają się od 0, a kończą na n - 1. Tablica musi umożliwiać dodanie elementu, jeśli n jest nieparzyste. Wyjście: Element minimalny i maksymalny w tablicy Z. Zmienne pomocnicze: i - przebiega przez kolejne indeksy elementów Z. i C max Z - tymczasowy element maksymalny max p - pozycja tymczasowego elementu maksymalnego.
Lista kroków: K01: Jeśli n mod 2 = 1, Z[n] Z[n-1] - jeśli nieparzysta liczba elementów, dublujemy ostatni; K02: min Z największa liczba całkowita - inicjujemy min Z i max Z ; K03: max Z najmniejsza liczba całkowita K04: i 0 K05: Dopóki i < n wykonuj K06...K12 - wybieramy pary kolejnych elementów; K06: Jeśli Z[i] > Z[i+1], to idź do K10 - rozdzielamy je na element mniejszy i większy; K07: Jeśli Z[i] < min Z, to min Z Z[i] - Z[i] - mniejszy, Z[i+1] większy; K08: Jeśli Z[i+1] > max Z, to max Z Z[i+1] K09: Idź do K12 K10: Jeśli Z[i] > max Z, to max Z Z[i] - Z[i] - większy, Z[i+1] mniejszy; K11: Jeśli Z[i+1] < min Z, to min Z Z[i+1] K12: i i + 2 - przechodzimy do następnej pary elementów; K13: Pisz min Z, max Z - wyprowadzamy wyniki; K14: Zakończ
Program #include <iostream> #include <iomanip> #include <cstdlib> #include <time.h> using namespace std; const int N = 15; int main() int Z[N+1],minZ,maxZ,i; srand((unsigned)time(null)); for(i = 0; i < N; i++) Z[i] = rand() % 10000; if(n % 2) Z[N] = Z[N-1]; minz = 10000; maxz = -1; for(i = 0; i < N; i += 2) if(z[i] > Z[i+1]) if(z[i] > maxz) maxz = Z[i]; if(z[i+1] < minz) minz = Z[i+1]; else if(z[i] < minz) minz = Z[i]; if(z[i+1] > maxz) maxz = Z[i+1]; for(i = 0; i < N; i++) cout << setw(4) << Z[i] << endl; cout << endl << minz << " : " << maxz << endl << endl; system("pause"); return 0; Program generuje 15 liczb pseudolosowych z zakresu od 0 do 9999. Wygenerowane liczby zapisuje w tablicy Z. Następnie wyszukuje liczbę najmniejszą i największą. Jako wynik jest jest wypisywana zawartość całej tablicy w 15 kolejnych wierszach, a w wierszu 17 podane zostają element minimalny i maksymalny.
Problem Posortować rosnąco n-elementowy zbiór Z. Zadanie sortowania polega na takim ułożeniu elementów zbioru Z, aby zachodził pomiędzy nimi porządek zdefiniowany odpowiednią relacją porządkującą. Porządek rosnący oznacza, iż w miarę posuwania się w głąb zbioru, wartości elementów stają się coraz większe nie napotkamy elementu mniejszego od któregokolwiek z elementów go poprzedzających w zbiorze. Relacją porządkującą jest relacja < lub przy dopuszczeniu elementów o równych wartościach jednakże wtedy nie jest określona kolejność elementów równych.
Istnieje bardzo wiele różnych algorytmów sortowania (ang. Sorting Algorithms). W tym rozdziale przedstawimy bardzo prosty algorytm, który wykorzystuje liniowe wyszukiwanie (ang. linear search) elementu minimalnego w zbiorze sortowanie przez wybór (ang. Selection Sort). Zasada pracy tego algorytmu jest następująca: Wyszukujemy w zbiorze Z najmniejszy element min Z. Element najmniejszy w zbiorze posortowanym powinien znaleźć się na pierwszej pozycji. Zatem znaleziony element wymieniamy z elementem pierwszym. Dalej postępujemy identycznie ze zbiorem Z pomniejszonym o pierwszy element.. Znajdujemy kolejny element minimalny i wymieniamy go z elementem na pozycji drugiej. Sortowanie tym samym sposobem kontynuujemy dla kolejnych podzbiorów Z. Gdy otrzymamy podzbiór jednoelementowy (czyli gdy wykonamy n - 1 wyborów elementów minimalnych). Kolejno znajdowane elementy minimalne tworzą ciąg niemalejący to wyjaśnia skuteczność tej metody przy sortowaniu zbioru.
Algorytm sortowania przez wybór Wejście: n liczba elementów w tablicy Z, n N Z tablica zawierająca elementy do posortowania. Wyjście: Tablica Z z posortowanymi rosnąco elementami Zmienne pomocnicze: i,j przebiegają przez kolejne indeksy elementów Z. i,j C min Z tymczasowy element minimalny min p pozycja tymczasowego elementu minimalnego, min p C
Lista kroków: K01: Dla i = 0,1,...,n-2 wykonuj K02...K08 K02: min Z Z[i] - tymczasowy element minimalny; K03: min p i - oraz jego tymczasowa pozycja; K04: Dla j = i+1,i+2,...,n-1 wykonuj K05...K07 - w pozostałych elementach szukamy minimalnego; K05: Jeśli Z[j] min Z, to kolejny obieg pętli K04...K07 K06: min Z Z[j] - znaleźliśmy, uaktualniamy min Z oraz min p; K07: min p j K08: Z[i] Z[min p ] - zamieniamy znaleziony element z i-tym. K09: Zakończ
#include <iostream> #include <iomanip> #include <cstdlib> #include <time.h> using namespace std; const int N = 200; int main() int Z[N],minZ,minp,i,j,x; srand((unsigned)time(null)); for(i = 0; i < N; i++) Z[i] = rand() % 1000; // Przed sortowaniem for(i = 0; i < N; i++) cout << setw(4) << Z[i]; cout << endl; // Sortowanie przez wybór for(i = 0; i < N - 1; i++) minz = Z[i]; minp = i; for(j = i + 1; j < N; j++) if(z[j] < minz) minz = Z[j]; minp = j; x = Z[i]; Z[i] = Z[minp]; Z[minp] = x; Program Program wypełnia 200 elementową tablicę liczbami pseudolosowymi od 0 do 999. Następnie wyświetla zawartość tej tablicy przed sortowaniem, sortuje ją opisanym algorytmem sortowania przez wybór i na koniec wyświetla tablicę posortowaną. // Po sortowaniu for(i = 0; i < N; i++) cout << setw(4) << Z[i]; cout << endl; system("pause"); return 0;
Problem W n-elementowym zbiorze Z znaleźć wartość występującą najczęściej.
Rozwiązanie nr 1 Problem wyszukiwania najczęstszej wartości (ang. searching for the most frequent value), czyli tzw. dominanty zbioru, możemy rozwiązać na kilka różnych sposobów. Pierwszym, najprostszym podejściem jest metoda bezpośrednia naiwna: Przeglądamy kolejne elementy zbioru i zliczamy liczbę wystąpień ich wartości w zbiorze. Można to robić tak zapamiętujemy i-ty element i ustawiamy licznik wystąpień na 0. Następnie przeglądamy cały zbiór i, jeśli trafimy na element o takiej samej wartości, to licznik zwiększamy o 1. Po wykonaniu tej operacji porównujemy zawartość licznika z tymczasową maksymalną liczbą wystąpień (na początku algorytmu jest ona ustawiana na 0). Jeśli stan licznika jest większy, to zapamiętujemy go w tymczasowej maksymalnej liczbie wystąpień oraz zapamiętujemy wyszukiwaną wartość elementu. Gdy przeglądniemy w ten sposób i zliczymy wystąpienia wartości wszystkich elementów w zbiorze Z, to otrzymamy element powtarzający się najczęściej oraz ilość tych powtórzeń. Klasa złożoności obliczeniowej tak zdefiniowanego algorytmu jest równa O(n 2 ). Jeśli elementów jest niewiele (do około 5000) i szybkość działania nie gra istotnej roli, to rozwiązanie naiwne jest do przyjęcia tak właśnie było w przypadku zadania maturalnego.
Algorytm znajdowania najczęstszej wartości Wejście: n - liczba elementów w tablicy Z, n N Z - tablica do wyszukania najczęstszego elementu Elementy są liczbami całkowitymi. Indeksy od 0 do n - 1.. Wyjście: Element występujący najczęściej w Z oraz liczba jego wystąpień. Jeśli jest kilka elementów o takiej samej maksymalnej liczbie wystąpień, to algorytm zwraca pierwszy z nich, który został napotkany w zbiorze. Zmienne pomocnicze: i, j - przebiega przez kolejne indeksy elementów Z. i,j C L - licznik wystąpień wartości elementu, L C W - wartość elementu, której liczbę wystąpień w Z zliczamy. max W - najczęstsza wartość elementów tablicy Z max L - liczba wystąpień wartości najczęstszej. max L C
Lista kroków: K01: max L 0 -zerujemy maksymalną liczbę wystąpień; K02: Dla i = 0,1,...,n - 1 wykonuj K03...K09 - przeglądamy kolejne elementy tablicy Z K03: W Z[i] - zapamiętujemy; poszukiwaną wartość elementu; K04: L 0 - zerujemy jej licznik wystąpień; K05: Dla j = 0,1,...,n - 1 wykonuj K06 - zliczamy wystąpienia W; K06: Jeśli Z[j] = W, to L L + 1 K07: Jeśli L max L, to następny obieg pętli K2 - sprawdzamy, czy W jest tymczasowo najczęstsze; K08: max L L - jeśli tak, zapamiętujemy liczbę wystąpień; K09: max W W - oraz wartość W; K10: Pisz max W, max L - wypisujemy wyniki; K11: Zakończ
Program #include <iostream> #include <iomanip> #include <cstdlib> #include <time.h> using namespace std; int main() const int N = 400; int Z[N],i,j,L,W,maxL,maxW; // Generujemy zawartość Z[] srand((unsigned)time(null)); for(i = 0; i < N; i++) Z[i] = rand() % 100; // Wyszukujemy najczęstszą wartość maxl = 0; for(i = 0; i < N; i++) W = Z[i]; L = 0; for(j = 0; j < N; j++) if(z[j] == W) L++; if(l > maxl) maxl = L; maxw = W; // Wypisujemy tablicę for(i = 0; i < N; i++) if(z[i] == maxw) cout << " >" << setw(2) << Z[i]; else cout << setw(4) << Z[i]; Program umieszcza w tablicy Z 400 liczb pseudolosowych z zakresu od 0 do 99, wyznacza wartość występującą najczęściej, wyświetla zawartość tej tablicy zaznaczając wartości najczęstsze i wypisuje tę wartość oraz liczbę jej wystąpień. // Wypisujemy najczęstszy element // oraz liczbę wystąpień cout << endl << maxw << " : " << maxl << endl << endl; system("pause"); return 0;
Rozwiązanie nr 2 Podany powyżej algorytm jest bardzo prymitywny i wykonuje wiele niepotrzebnych działań. Postarajmy się je wyeliminować. 1. Ze zbioru bierzemy KAŻDY element Z[i] i zliczamy wystąpienia jego wartości W w CAŁYM zbiorze Z. W ten sposób najczęstsza wartość max W zostanie zliczona max L 2 razy. Zatem pierwsze ulepszenie będzie polegało na tym, iż pobrany element W zbioru zliczamy tylko wtedy, gdy jest on różny od max W. Wynika z tego, iż na początku pracy algorytmu do max W musimy wpisać wartość różną od Z[0] (dlaczego?). 2. Każdy element Z[i] zliczamy w całym zbiorze. Tymczasem, jeśli wartość i- tego elementu wystąpiła wcześniej w zbiorze, to jest już zliczona. Jeśli nie wystąpiła wcześniej, to nie ma sensu jej tam szukać, nieprawdaż? W obu przypadkach wystarczy, jeśli zliczanie rozpoczniemy od pozycji i + 1 do końca zbioru. Elementy zliczone po prostu zliczymy ponownie, lecz w mniejszym zakresie. Elementy nowe zliczymy poprawnie, od miejsca ich pierwszego wystąpienia. 3. Jeśli w trakcie działania algorytmu w max L mamy chwilową maksymalną liczbę wystąpień pewnej wartości max W, to zliczanie nowych elementów możemy przerwać po osiągnięciu pozycji n - max L. Jeśli nowy element występuje na tej lub dalszej pozycji w zbiorze Z, to liczba wystąpień jego wartości nie będzie już większa od max L, gdyż braknie elementów.
Algorytm znajdowania najczęstszej wartości wersja nr 2 Wejście: n - liczba elementów w tablicy Z, n N Z - tablica do wyszukania najczęstszego elementu Elementy są liczbami całkowitymi. Indeksy od 0 do n - 1.. Wyjście: Element występujący najczęściej w Z oraz liczba jego wystąpień. Jeśli jest kilka elementów o takiej samej maksymalnej liczbie wystąpień, to algorytm zwraca pierwszy z nich, który został napotkany w zbiorze Zmienne pomocnicze: i, j - przebiega przez kolejne indeksy elementów Z. i,j C L - licznik wystąpień wartości elementu, L C W - wartość elementu, której liczbę wystąpień w Z zliczamy. max W - najczęstsza wartość elementów tablicy Z max L - liczba wystąpień wartości najczęstszej. max L C
Lista kroków: K01: max L 0 - licznik wystąpień najczęstszej wartości K02: max W Z[0] - 1 - najczęstsza wartość - musi być różna od Z[0]! ; K03: i 0 - rozpoczynamy zliczanie wartości elementów ; K04: Dopóki i < n - max L, wykonuj K05...K13 - zliczamy do n-max L ; K05: W Z[i] - zapamiętujemy wartość bieżącego elementu; K06: Jeśli W = max W, to idź do K13 - jeśli jest równa max W, to pomijamy element Z[i]; K07: L 1 - Z[i] raz zliczony; K08: Dla j = i+1,i+2,...,n-1 wykonuj K09 - zliczanie rozpoczynamy od następnych elementów; K09: Jeśli Z[j] = W, to L L + 1 K10: Jeśli L max L, to idź do K13 - zliczyliśmy więcej niż max L? ; K11: max L L - jeśli tak, zapamiętujemy L w max L ; K12: max W W ; oraz W w max W K13: i i + 1 - przechodzimy do kolejnego elementu Z[i] ; K14: Pisz max W,max L - wyprowadzamy wyniki; K15: Zakończ
Program #include <iostream> #include <iomanip> #include <cstdlib> #include <time.h> using namespace std; int main() const int N = 400; int Z[N],i,j,L,W,maxL,maxW; // Generujemy zawartość Z[] srand((unsigned)time(null)); for(i = 0; i < N; i++) Z[i] = rand() % 100; // Wyszukujemy najczęstszą wartość maxl = 0; maxw = Z[0] - 1; for(i = 0; i < N - maxl; i++) W = Z[i]; if(maxw!= W) L = 1; for(j = i + 1; j < N; j++) if(z[j] == W) L++; if(l > maxl) maxl = L; maxw = W; Program umieszcza w tablicy Z 400 liczb pseudolosowych z zakresu od 0 do 99, wyznacza wartość występującą najczęściej, wyświetla zawartość tej tablicy zaznaczając wartości najczęstsze i wypisuje tę wartość oraz liczbę jej wystąpień. // Wypisujemy tablicę for(i = 0; i < N; i++) if(z[i] == maxw) cout << " >" << setw(2) << Z[i]; else cout << setw(4) << Z[i]; // Wypisujemy najczęstszy element // oraz liczbę wystąpień cout << endl << maxw << " : " << maxl << endl << endl; system("pause"); return 0;
Rozwiązanie nr 3 Jeśli elementy zbioru tworzą spójny przedział wartości i przedział ten nie jest specjalnie duży, to do wyszukania wartości najczęstszej można zastosować następującą metodę. Tworzymy tablicę L, której elementy będą pełniły rolę liczników wystąpień wartości elementów z tablicy Z. Zakres indeksów w L możemy znaleźć wyszukując w tablicy Z wartość minimalną i maksymalną (można też z góry przydzielić odpowiednią liczbę liczników, gdy znamy zakres wartości elementów w przeszukiwanej tablicy Z). Zerujemy wszystkie liczniki w L i przeglądamy tablicę Z zwiększając o 1 liczniki w L, które odpowiadają wartościom przeglądanych elementów. W efekcie po zakończeniu przeglądania tablicy Z w L będziemy mieli informację o liczbie wystąpień każdej z wartości. Wyznaczamy w L element maksymalny. Wynikiem jest indeks, który określa wartość występującą najczęściej w Z oraz zawartość elementu L o tym indeksie, która określa ile razy dana wartość wystąpiła w Z. Tak określony algorytm wyszukiwania najczęstszego elementu posiada liniową klasę złożoności obliczeniowej O(m + n), gdzie m jest liczbą wartości elementów przeszukiwanego zbioru, a n jest liczbą jego elementów.
Algorytm znajdowania najczęstszej wartości wersja nr 3 Wejście: n - liczba elementów w tablicy Z, n N Z - tablica do wyszukania najczęstszego elementu Elementy są liczbami całkowitymi. Indeksy od 0 do n - 1.. min Z - minimalna wartość w Z. max Z - maksymalna wartość w Z. Wyjście: Element występujący najczęściej w Z oraz liczba jego wystąpień. Jeśli jest kilka elementów o takiej samej maksymalnej liczbie wystąpień, to algorytm w tej wersji zwraca najmniejszy z nich (jeśli pozostałe elementy są istotne, to można je odczytać z tablicy L porównując liczbę wystąpień z maksymalną). Zmienne pomocnicze: i - przebiega przez kolejne indeksy elementów Z. i C L - tablica liczników wystąpień wartości elementów z Z. max L - tymczasowy element maksymalny w L max p - pozycja tymczasowego elementu maksymalnego w L
Lista kroków: K01: Utwórz L o rozmiarze max Z - min Z + 1 -przygotowujemy liczniki wartości; K02: Wyzeruj L -liczniki ustawiamy na 0; K03: Dla i = 0,1,...,n-1 wykonuj K04 -zliczamy wystąpienia wartości elementów; K04: Zwiększ o 1 L[Z[i] - min Z ] -w odpowiednich licznikach ; K05: max L L[0] -szukamy max w L; K06: max p 0 K07: Dla i = 1,2,...,max Z -min Z wykonuj K08...K10 K08: Jeśli L[i] max L, to następny obieg pętli K07 K09: max L L[i] -zapamiętujemy wartość maksymalną; K10: max p i -oraz jej pozycję; K11: Pisz max p + min Z, max L -wyprowadzamy najczęstszy element oraz liczbę jego wystąpień; K12: Zakończ
Program #include <iostream> #include <iomanip> #include <cstdlib> #include <time.h> using namespace std; const int N = 80; int main() int Z[N], * L,i,nL,maxZ,minZ,maxL,maxp; srand((unsigned)time(null)); // Przygotowujemy tablicę Z[] for(i = 0; i < N; i++) Z[i] = -9 + (rand() % 19); // Wyświetlamy tablicę Z[] for(i = 0; i < N; i++) cout << setw(4) << Z[i]; // Wyszukujemy w Z[] min i max if(z[0] > Z[1]) minz = Z[1]; maxz = Z[0]; else minz = Z[0]; maxz = Z[1]; for(i = 2; i < N; i += 2) if(z[i] > Z[i+1]) if(z[i] > maxz) maxz = Z[i]; if(z[i+1] < minz) minz = Z[i+1] ; Program umieszcza w tablicy Z 80 liczb pseudolosowych z zakresu od -9 do 9, wyświetla zawartość tej tablicy i wyznacza w niej wartość występującą najczęściej. Program wypisuje tę wartość oraz liczbę jej wystąpień w tablicy Z.
else if(z[i] < minz) minz = Z[i]; if(z[i+1] > maxz) maxz = Z[i+1]; // Przygotowujemy liczniki nl = maxz - minz + 1; L = new int[nl]; for(i = 0; i < nl; i++) L[i] = 0; // Zliczamy wystąpienia wartości z Z[] for(i = 0; i < N; i++) L[Z[i] - minz]++; // Szukamy najczęstszej wartości w L[] maxl = L[0]; maxp = 0; for(i = 0; i < nl; i++) if(l[i] > maxl) maxl = L[i]; maxp = i; // Wyświetlamy wyniki cout << endl << (maxp + minz) << " : " << maxl << endl << endl; delete [] L; system("pause"); return 0;
Rozwiązanie nr 4 Zbiór Z możemy posortować rosnąco. Wtedy elementy o równych wartościach znajdą się obok siebie. Teraz wystarczy przeglądnąć zbiór Z od początku do końca, zliczać powtarzające się wartości i zapamiętać tę wartość, która powtarza się najczęściej. Klasa złożoności obliczeniowej algorytmu w tej wersji zależy od zastosowanego algorytmu sortującego zbiór Z. Samo przeglądnięcie zbioru i wyłonienie najczęstszej wartości ma liniową klasę złożoności obliczeniowej O(n). Zaletą tego algorytmu jest to, iż elementy tablicy Z nie muszą być koniecznie liczbami całkowitymi. Mogą to być obiekty dowolnego typu.
Algorytm znajdowania najczęstszej wartości wersja nr 4 Wejście: n - liczba elementów w tablicy Z, n N Z - tablica do wyszukania najczęstszego elementu Elementy są liczbami całkowitymi. Indeksy od 0 do n. Tablica powinna być posortowana rosnąco. Na końcu tablicy element Z[n] powinien być umieszczony wartownik o wartości innej niż wartość ostatniego elementu Z[n-1]. Wyjście: Element występujący najczęściej w Z oraz liczba jego wystąpień. Jeśli jest kilka elementów o takiej samej maksymalnej liczbie wystąpień, to algorytm w tej wersji zwraca najmniejszy z nich. Zmienne pomocnicze: i - przebiega przez kolejne indeksy elementów Z. i C max L - liczba wystąpień najczęstszego elementu w Z, max L C max W - wartość najczęstszego elementu w Z L - licznik równych elementów, L C
Lista kroków: K02: max L 0 - inicjujemy liczbę wystąpień na 0; K03: L 1 - w L zliczamy pierwszy element; K04: Dla i = 1,2,...,n wykonuj K05...K10 - przeglądamy kolejne elementy aż do wartownika; K05: Jeśli Z[i] = Z[i - 1], to idź do K10 - dla równych elementów zwiększamy L o 1; K06: Jeśli L max L, to idź do K09 - elementy nie są równe, sprawdzamy licznik L; K07: max L L - jeśli L > max L, to zapamiętujemy L; K08: max W Z[i - 1] - oraz wartość elementu ; K09: L 0 - dla nowego elementu licznik L wystartuje od 1; K10: L L + 1 - zliczamy elementy równe ; K11: Pisz max W, max L - wypisujemy wyniki ; K12: Zakończ
#include <iostream> #include <iomanip> #include <cstdlib> #include <time.h> using namespace std; const int N = 200; int main() int Z[N + 1],maxL,maxW,minZ,minp,L,i,j,x; srand((unsigned)time(null)); // Inicjujemy tablicę Z[] for(i = 0; i < N; i++) Z[i] = rand() % 10; // Sortujemy tablicę Z[] for(i = 0; i < N - 1; i++) minz = Z[i]; minp = i; for(j = i + 1; j < N; j++) if(z[j] < minz) minz = Z[j]; minp = j; x = Z[i]; Z[i] = Z[minp]; Z[minp] = x; // Wyświetlamy tablicę Z[] for(i = 0; i < N; i++) cout << setw(2) << Z[i]; cout << endl; // Dodajemy wartownika Z[N] = Z[N - 1] - 1; Program Program umieszcza w tablicy Z 200 liczb pseudolosowych z zakresu od 0 do 9, sortuje tablicę algorytmem sortowania przez wybór, wyświetla ją oraz wyznacza najczęstszą wartość. Program wyświetla tę wartość oraz liczbę jej wystąpień.
// Szukamy najczęstszej wartości maxl = 0; L = 1; for(i = 1; i <= N; i++) if(z[i]!= Z[i - 1]) if(l > maxl) maxl = L; maxw = Z[i - 1]; L = 0; L++; // Wyświetlamy wyniki cout << maxw << " : " << maxl << endl << endl; system("pause"); return 0;