Dominanta ze 100 elementowej tablicy

Dominanta ze 100 elementowej tablicy
MI
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 4 lata
  • Postów:29
0

Witajcie. Mam już posortowaną 100 elementową tablicę , do której losowane są liczby z zakresu 1-10. Jak wskazuje nazwa tematu, mam znaleźć liczbę, która wystepuje najczęściej. No i niby wiem jak to zrobić, ale sposób ten jest bardzo prymitywny. Można przechodzić po wszystkich elementach tablicy i zwiększał licznik dopóki tab[i] < tab[i+1] . No ale wtedy trzeba byłoby zrobić 10 takich liczników, i na tym polega prymitywizm tej "mojej metody" :D Macie jakieś inne pomysły na zminimalizowanie i zoptymalizowanie rozwiązania tego problemu? Pozdrawiam!

hauleth
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:13 dni
0

Sortujesz i wybierasz tę, która występuje najczęściej. Masz wtedy tylko 2 zmienne.


MM
  • Rejestracja:około 12 lat
  • Ostatnio:6 miesięcy
  • Postów:91
0

dla dziesięciu tysięcy rekordów to ja bym się nie wysilał - może to odpowiedź jakaś jest...

MI
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 4 lata
  • Postów:29
0

One już są posortowane, teraz chodzi o to w jaki sposób je porównać. Winefresh, właśnie chodzi mi o to jak wybrać i znaleźć tę która występuje najczęściej.

ŁF
Moderator
  • Rejestracja:ponad 22 lata
  • Ostatnio:2 dni
0

W C#, bo mam wstręt do C++, myślę, że połapiesz się jaka jest myśl przewodnia:

Kopiuj
var random = new Random((int)DateTime.Now.Ticks);
var histogram = new byte[10];
var data = Enumerable.Repeat(0, 10000).Select(r => random.Next(1, 10)).ToArray();

foreach (var d in data) ++histogram[d - 1]; // korzystam z przyjemnej właściwości danych wejściowych do zliczenia ile jest których

var max = histogram.Select((count, index) => new { Count = count, Index = index}).OrderByDescending(el => el.Count).First().Index + 1;

Edit: jeśli są posortowane, to możesz to zrobić jeszcze szybciej - dla każdej z liczb metodą bisekcji wyszukujesz prawego sąsiada, wiedząc gdzie sąsiad się zaczyna masz ilość wystąpień danej liczby, potem powtarzasz to dla prawego sąsiada i tak aż do końca. Złożoność obliczeniowa to O(n*log2(m)), m - ilość danych, n - ilość różnych liczb. Złożoność obliczeniowa mojego kodu jest dużo wyższa dla m >> n - O(m).


edytowany 1x, ostatnio: ŁF
MI
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 4 lata
  • Postów:29
0

Ciężko mi się w tym połapać... No nic, pozostała chyba opcja prymitywna, bo na inną nie mam pomysłu, a właściwie po prostu nie wiem jak ją wykonać.

lemmiwink
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 12 lat
1

Możesz też zrobić tak:

Kopiuj
int tab[] = {1, 2, 3, 4, 4, 4, 4, 7, 7, 7};
int actual = tab[0];
int amount = 1;
int maxAmount = 1;
int elem = tab[0];
int size = 10;

for (int i = 1; i < size; i++) {
	if (tab[i] == actual) {
		amount++;
	} else {
		if (amount > maxAmount) {
			elem = actual;
			maxAmount = amount;
		}
		actual = tab[i];
		amount = 1;
	}
}
if (amount > maxAmount) {
	elem = actual;
	maxAmount = amount;
}

printf("%d\t%d", elem, maxAmount);
ŁF
Skoro dane są posortowane, to skorzystaj z tego do wyszukiwania kolejnej, wyższej liczby. I język angielski się kłania - w tym kontekście aktualny (bieżący) to po angielsku current, a nie actual.
lemmiwink
faktycznie, tu powinno byc 'current', a nie 'actual' - mój błąd. Korzystam z tego, że dane są posortowane - w momencie wykrycia nowej wartości aktualizuję elem i maxAmout (jeśli potzeba)
ŁF
Moderator
  • Rejestracja:ponad 22 lata
  • Ostatnio:2 dni
0

@mistergol: co w tym takiego skomplikowanego? Nie wiesz co to histogram, to idziesz sobie na wikipedię i czytasz, aż zrozumiesz. Wiedząc, co to histogram patrzysz jeszcze raz na kod. Rozbijasz go na prostsze przypadki, np. tablica pięciu elementów o trzech wartościach, i patrzysz co się dzieje.

Zobacz:
data | histogram | index(max)
1, 2, 4, 4 | 1, 1, 0, 2 | 4
1, 1, 1, 4 | 3, 0, 0, 1 | 1
1, 2, 2, 5, 1, 4 | 2, 2, 0, 1, 1 | niezdefiniowany - 1 albo 2

itp. Data to dane wejściowe z przedziału 1..n. Histogram to liczba wystąpień poszczególnych liczb, na pozycji 1 liczba wystąpień jedynki, na pozycji trzeciej liczba trójek itp (a ponieważ tablice w C++ oraz C# indeksuje się od zera, to żonglowanie jedynką - raz odjąć, a raz dodać). Index(max) to indeks maksymalnej pozycji w histogramie.


edytowany 1x, ostatnio: ŁF
lemmiwink
ale po co Ci histogram do znalezienia dominanty? Gdyby w tablicy mogły być wartości od 0 do 1000000000 to też utworzyłbyś histogram?
ŁF
Przepraszam, ale nie rozumiem pierwszego pytania. Przecież widzisz - i to ubrane w kod - jak jest używany, a po co jest potrzebny sam sobie odpowiedziałeś... Za drugim pytaniem też nie nadążam - to przecież oczywiste, że tak bym nie zrobił. Rozwiązanie dobiera się do problemu, nie problem do rozwiązania, tutaj jest podany przedział i podany rozmiar tablicy i to rozwiązanie doskonale sobie z nim poradzi. Dla krótkiej tablicy (do kilkuset tysięcy elementów) o nieznanych wartościach użyłbym hashmapy, a dla ogólnego przypadku użyłbym połówkowego wyszukiwania sąsiada.
lemmiwink
Oczywiście, że to rozwiązanie doskonale sobie z tym zadaniem poradzi. Ja jednak jestem zwolennikiem pisania rozwiązań dla ogólnych, a nie dla jakichś konkretnych przypadków (o ile nie wymagają tego względy wydajnościowe albo pamięciowe).
ŁF
Myślałem, że tego nie napiszesz... Twoje rozwiązanie dla ogólnego przypadku będzie nieoptymalne - patrz mój komentarz pod Twoim postem - a więc nieodpowiednie. Rozumiesz, co mam na myśli?
_13th_Dragon
@lemmiwink, twój algorytm ma złożoność O(n). Jeżeli jesteś "zwolennikiem pisania rozwiązań dla ogólnych" to czemu nie napisałeś algorytm O(log(N)), który w ogólnym przypadku tu bardziej pasuje.
ŁF
Moderator
  • Rejestracja:ponad 22 lata
  • Ostatnio:2 dni
1

Rozwiązanie o złożoności O(m*log(n)), gdzie n - ilość danych, m - ilość różnych liczb, ponownie w C#

Kopiuj
		private static int FindIndexOfRightNeighbour(int me, int start, int[] everybody)
		{
			int l = start, len = everybody.Length - 1, r = len;

			if (everybody[len] <= me)
				return len + 1;
			if (everybody[0] > me)
				return 0;

			while (l <= r)
			{
				int m = (l + r) >> 1;
				int x = everybody[m];

				if (everybody[m + 1] > me && x == me)
					return m+1;

				if (x <= me)
					 l = m + 1;
				  else
					 r = m - 1;
			}
			
			throw new Exception();
		}


		var random = new Random((int)DateTime.Now.Ticks);
		var data = Enumerable.Repeat(0, 500).Select(rnd => random.Next(1, 14)).OrderBy(v => v).ToArray();

		int l = 0, r = 0, max = 0, value = 0, currentValue = data[0];
		while (true)
		{
			l = r;
			if (data[r + 1] != currentValue)
				++r; // tu drobna optymalizacja dla tablic z m >> n
			else
				r = FindIndexOfRightNeighbour(currentValue, r, data);
			if (r - l > max)
			{
				max = r - l;
				value = data[r-1];
			}

			if (r >= data.Length)
				break;
			currentValue = data[r];
		}

Wartość występująca najczęściej znajdzie się w zmiennej value. Jeśli kilka wartości występuje równie często, zwrócona zostanie najniższa. Można podciągnąć średnią złożoność obliczeniową do O(m*log(log(n)) stosując zmodyfikowany algorytm wyszukiwania binarnego, ale to już zostawię autorowi wątku.


Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.