Strona główna » Algorytmy » Artykuły » Unikalne Elementy Tablicy
 

Unikalne Elementy Tablicy

Cel

Dana liczba może zostać zapisany w tablicy wiele razy. Napisz algorytm, który wybierze z podanej, nieposortowanej tablicy liczb wszystkie unikalne elementy. Przykładowo jeśli dana jest lista [3, 2, 1, 3, 3, 2] to ma ona tylko trzy unikalne wartości, którymi są [1, 2, 3].

Opis problemu

W tym przypadku elementami tablicy są liczby, ale mogłyby też być bardziej rozbudowanymi strukturami. Tego typu algorytm może się przydać podczas pracy z bazami danych. Przykładowo wiele osób może mieć to samo imię. Jeśli wybierzemy tylko unikalne imiona z listy wszystkich dowiemy się ile imion jest aktualnie używanych.

Implementacja

Czy już był?

Pierwsza wersja algorytmu polega na wybieraniu każdego kolejnego elementu i dopisywani go do wyniku tylko pod warunkiem, że żaden z poprzednich elementów nie był taki sam. Oznacza to, że dla i-tego elementu należy wykonać i-1 porównań. Złożoność takiego algorytmu jest kwadratowa tj. O(n2). Oto przykładowy kod:

  1. static List<int> unikalneElementy(List<int> lista) {
  2.   List<int> wynik = new List<int>();
  3.   for (int i = 0; i < lista.Count; i++) {
  4.     bool dopisz = true;
  5.     for (int j = 0; j < i; j++) {
  6.       if (lista[i] == lista[j]) {
  7.         dopisz = false;
  8.         break;
  9.       }
  10.     }
  11.     if (dopisz) {
  12.       wynik.Add(lista[i]);
  13.     }
  14.   }
  15.   return wynik;
  16. }

Algorytm składa się z dwóch pętli: pierwsza przechodzi po kolejnych elementach tablicy wejściowej, a druga po wszystkich elementach przed aktualnie rozpatrywanym. W przypadku, gdy trafi się identyczny element pętla jest przerywana, a wartość zmiennej dopisz zmieniana na fałsz, aby element nie został dopisany. Algorytm można przyśpieszyć wyszukując identycznego elementu bezpośrednio na liście wynikowej. Niemniej pesymistyczna złożoność czasowa pozostaje taka sama.

Spójrz Wstecz

Istnieje szybka metoda znajdowania wszystkich unikalnych elementów. Najpierw dane należy posortować - jak wiadomo najlepsze algorytmy sortujące mają złożoność O(nlog(n)). Po posortowaniu identyczne elementy znajdą się koło siebie, więc przed dodaniem elementu do listy wynikowej wystarczy spojrzeć czy poprzedni element w posortowanej tablicy jest inny. Złożoność takiego przeszukania to zaledwie O(n). Oto przykładowa implementacja:

  1. static List<int> unikalneElementy(List<int> lista) {
  2.   List<int> wynik = new List<int>();
  3.   lista.Sort();
  4.   wynik.Add(lista[0]);
  5.   for (int i = 1; i < lista.Count; i++) {
  6.     if (lista[i] != lista[i - 1]) {
  7.       wynik.Add(lista[i]);
  8.     }
  9.   }
  10.   return wynik;
  11. }

Jak można zauważyć algorytm uprościł się do zaledwie jednej pętlej w której znajduje się jeden warunek. Niewątpliwie jest on lepszy niż poprzednio opisany, ale pod warunkiem, że zostanie dobrany odpowiedni algorytm sortujący, ponieważ jego złożoność znacząco wpływa na efektywność napisanej funkcji.

Testowanie funkcji

W celu przetestowania napisanych funkcji wystaczy poniższy fragment programu:

  1. static void Main(string[] args) {
  2.   Console.WriteLine("Podaj elementy tablicy:");
  3.   string[] data = Console.ReadLine().Split(' ');
  4.   List<int> lista = new List<int>();
  5.   foreach(string s in data) {
  6.     lista.Add(Convert.ToInt32(s));
  7.   }
  8.   Console.WriteLine("Unikalne elementy to:");
  9.   List<int> wynik = unikalneElementy(lista);
  10.   foreach(int a in wynik) {
  11.     Console.Write("{0} ", a);
  12.   }
  13.   Console.ReadKey();
  14. }