Strona główna » Algorytmy » Artykuły » Zakresy
 

Zakresy

Cel

Zapisywanie wielu liczb pod rząd jest monotonnym zadaniem, więc bardzo często zapisujemy w skrócie np. 1-10 co można przetłumaczyć jako zbiór liczb od 1 do 10. Napisz program, który zamieni tablicę liczb na zakresy. Przykładowo dla liczb 1, 2, 3 poprawny zakres to 1-3, ale dla liczby 5 powinno zostać wypisane tylko 5. Zakładamy, że elementy na liście są unikalne.

Analiza

Opis

Przed przystąpieniem do pisania kodu przeanalizujmy treść zadania. Otóż wiadomo, że liczby na liście będą unikalne, ale czy będą posortowane? Poniższa propozycja rozwiązania zadania wymaga, aby tak było, więc posortowanie powinno zostać wykonane na samym początku algorytmu. Następnie pobieramy pierwszą liczbę z nieprzejrzanej części tablicy i zwiększamy indeks tak długo, aż kolejna liczba jest o jeden większa od poprzedniej. W przypadku, gdy okaże się, że następna liczba jest większa o więcej niż jeden to należy aktualny zakres zapisać na tablicę. Kroki te powtarzamy tak długo, aż w tablicy wszystko elementy zostaną sprawdzone.

Przykład

Dana jest tablica [2, 1, 5, 3]. Na początku sortujemy elementy otrzymując w ten sposób [1, 2, 3, 5]. Następnie rozpoczynamy przeglądanie od elementu 1, wykrywamy, że kolejne 2 i 3 są kolejnymi liczbami, ale 5 już nie, więc zapisujemy na listę 1-3. W tablicy zostaje tylko [5]. Kończymy algorytm stwierdzając, że nie ma więcej elementów, więc zapisujemy aktualnie znaleziony zakres. Ostatecznie skróciliśmy tablicę do zapisu "1-3 5".

Złożoność

Sortowanie tablicy zależy od implementacji algorytmu, ale możemy przyjąć O(nlogn), a druga część kodu jest liniowa, więc ostatecznie algorytm działa w czasie liniowo-logarytmicznym O(nlogn).

Implementacja

Do przechowywania zakresu warto skorzystać z struktury pary liczb, aby zapisać początek i koniec pewnego zakresu. W przypadku, gdy zakres składa się z jednej wartości to obie liczby będą sobie równe.

  1. class zakres {
  2.   int poczatek;
  3.   int koniec;
  4.   public zakres(int poczatek, int koniec) {
  5.     this.poczatek = poczatek;
  6.     this.koniec = koniec;
  7.   }
  8.   public override string ToString() {
  9.     string s = poczatek.ToString();
  10.     if (poczatek != koniec)
  11.       s += "-" + koniec.ToString();
  12.     return s + " ";
  13.   }
  14. }

Poniżej znajduje się przykładowa implementacja funkcji konwertujNaZakresy(). Jako argument należy podać tablicę liczb do zamiany na zakresy.

  1. static List<zakres> konwertujNaZakresy(int[] dane) {
  2.   Array.Sort(dane);
  3.   List<zakres> lista = new List<zakres>();
  4.   for (int i = 0; i < dane.Length; i++) {
  5.     int teraz = dane[i];
  6.     while (i < dane.Length && dane[i + 1] == dane[i] + 1) {
  7.       i++;
  8.     }
  9.     lista.Add(new zakres(teraz, dane[i]));
  10.   }
  11.   return lista;
  12. }

Testowanie funkcji

Poniższy fragment kodu wczyta dane od użytkownika i wypisze wynik na ekran:

  1. static void Main(string[] args) {
  2.   Console.WriteLine("Podaj elementy");
  3.   string[] dane = Console.ReadLine().Split(' ');
  4.   int[] tab = new int[dane.Length];
  5.   for (int i = 0; i < dane.Length; i++)
  6.     tab[i] = Convert.ToInt32(dane[i]);
  7.   List<zakres> lista = konwertujNaZakresy(tab);
  8.   for (int i = 0; i < lista.Count; i++)
  9.     Console.Write(lista[i]);
  10.   Console.ReadKey();
  11. }
Zadania
Zadanie 1
Kod źródłowy Zadanie 1Kod źródłowy Zadanie 1Kod źródłowy Zadanie 1