poniedziałek, 1 września 2014

Specjalne kontenery STL w C++

#include <iostream>
#include <stack>
#include <queue>
#include <string>
#include <exception>
#include <bitset>
#include <limits> // Dla numeric_limits (chociaż niekoniecznie w Microsoft Visual Studio 2013).

// Bezpieczniejsza klasa stosu.

template <class type> class safer_stack {
protected:
    std::deque<type> elements;

public:
    // Klasa wyjątku dla funkcji składowych pop oraz top wywoływanych w przypadku pustego stosu.

    class read_empty_stack : public std::exception {
    public:
        virtual const char *what() const throw() {
            return "proba odczytania pustego elementu";
        }
    };

    // Liczba elementów.

    typename std::deque<type>::size_type size() const {
        return elements.size();
    }

    // Czy stos pusty.

    bool empty() const {
        return elements.empty();
    }

    // Umieść element na stosie.

    void push(const type &element) {
        elements.push_back(element);
    }

    // Zdejmij element ze stosu i zwróć jego wartość.

    type pop() {
        if (elements.empty())
            throw read_empty_stack();

        type element(elements.back());

        elements.pop_back();

        return element;
    }

    // Zwróć wartość kolejnego elementu.

    type &top() {
        if (elements.empty())
            throw read_empty_stack();

        return elements.back();
    }
};

int main() {
    // Stos.

    std::stack<int> elements;

    elements.push(1); // Umieść na stosie element.

    elements.push(2);

    elements.push(3);

    std::cout << elements.top() << std::endl; // Pobierz ze stosu element ale go nie usuwaj.

    elements.pop(); // Usuń element ze stosu.

    elements.top() = 77; // Zmień kolejny element.

    while (!elements.empty()) {
        std::cout << elements.top() << std::endl;

        elements.pop();
    }

    try {
        safer_stack<int> safer_elements;

        safer_elements.push(1);

        safer_elements.push(2);

        safer_elements.push(3);

        safer_elements.pop();

        safer_elements.pop();

        safer_elements.top() = 77;

        safer_elements.push(4);

        safer_elements.push(5);

        safer_elements.pop();

        safer_elements.pop();

        safer_elements.pop();

        safer_elements.pop(); // O jeden za dużo.
    }
    catch (const std::exception &information) {
        std::cerr << "Wyjatek: " << information.what() << ".\n";
    }

    // Kolejka.

    std::queue<std::string> queue_elements;

    queue_elements.push("String nr 1");

    queue_elements.push("String nr 2");

    queue_elements.push("String nr 3");

    std::cout << queue_elements.front() << std::endl; // Pobierz z kolejki element.

    queue_elements.pop(); // Zdejmij z kolejki element.

    std::cout << "W kolejce jest " << queue_elements.size() << " elementow.\n";

    // Kolejka priorytetowa.

    std::priority_queue<float> priority_elements;

    priority_elements.push(22.1);

    // Pobierz i wypisz elementy.

    while (!priority_elements.empty()) {
        std::cout << priority_elements.top() << std::endl;

        priority_elements.pop();
    }

    // Kontener bitset.

    enum color { red, yellow, gree, blue, white, black, num_colors }; // Każdy bit reprezentuje kolor.
    std::bitset<num_colors> used_colors;

    used_colors.set(red); // Ustawianie bitu do koloru.

    used_colors.set(blue);

    std::cout << "Wartosci bitowe uzytych kolorow: " << used_colors << std::endl;

    std::cout << "Liczba uzytych kolorow: " << used_colors.count() << std::endl;

    std::cout << "Wartosci bitowe niewykorzystanych kolorow: " << ~used_colors << std::endl;

    if (used_colors.any()) { // Jeżeli został wykorzystany jakiś kolor.
        // Przejrzyj wszystkie kolory.

        for (int iterator = 0; iterator < num_colors; ++iterator) {
            if (used_colors[(color)iterator]) // Jeżeli został wykorzystany rzeczywisty kolor.
                std::cout << "Kolor wykorzystany.\n";

            used_colors[(color)iterator].flip(); // Zamiana wartości bitu.
        }
    }

    std::cout << "267 w postaci binarnej liczby typu short: " << std::bitset<std::numeric_limits<unsigned short>::digits>(267) << std::endl;

    std::cout << "10000000 w postaci binarnej liczby 24 bitowej: " << std::bitset<24>(1e7) << std::endl;

    std::cout << "1000101011 binarnie to " << std::bitset<100>(std::string("1000101011")).to_ulong() << " dziesiatkowo.\n";
}

Źródło:
- Prata S., Język C++. Szkoła programowania. Wydanie VI, Helion SA, 2012,
- Josuttis N. M., C++. Biblioteka standardowa, Helion SA, 2003.

niedziela, 31 sierpnia 2014

Kontenery STL w C++

#include <iostream>
#include <list>
#include <iterator>
#include <algorithm> // Dla for_each.
#include <set>
#include <string>
#include <map>
#include <deque>
#include <functional> // Dla obiektu funkcyjnego greater.

void out_int(int number);

template <class type> class runtime_cmp {
public:
    enum cmp_mode { normal, reverse };

    // Konstruktor dla kryterium sortowania.

    runtime_cmp(cmp_mode mode_constructor = normal) : mode(mode_constructor) { }

    // Porównanie elementów.
 
    bool operator()(const type &element_one, const type &element_two) const {
        return ((mode == normal) ? (element_one < element_two) : (element_two < element_one));
    }

    // Porównanie kryteriów sortowania.

    bool operator==(const runtime_cmp &element) {
        return (mode == element.mode);
    }

private:
    cmp_mode mode;
};

int main() {
    // Kontenery sekwencyjne.

    // Wektory.

    // Kolejki o dwóch końcach.

    std::deque<std::string> string_queue;

    string_queue.assign(3, "String"); // Wstaw 3 kopie podanego łańcucha.

    string_queue.push_back("Ostatni string"); // Dołącz na końcu podany element.

    string_queue.push_front("Pierwszy string"); // Wstaw na początek.

    std::copy(string_queue.begin(), string_queue.end(), std::ostream_iterator<std::string>(std::cout, "\n")); // Wypisz elementy w oddzielnych wierszach.

    string_queue.pop_front(); // Usuń pierwszy.

    string_queue.pop_back(); // Usuń ostatni element.

    // Wstaw łańcuch "Other" do każdego elementu oprócz pierwszego.

    for (unsigned iterator = 1; iterator < string_queue.size(); ++iterator)
        string_queue[iterator] = "Other " + string_queue[iterator];

    string_queue.resize(4, "String zmiany rozmiaru"); // Zmień rozmiar o ewentualnie brakujące elementy uzupełnij podanymi.

    // Listy.

    std::list<int> one(5, 2); // Lista pięciu wartości 2.
    std::list<int> two, four, five;
    int numbers[5] = { 1, 2, 3, 4, 5 };

    two.insert(two.begin(), numbers, (numbers + 5)); // Wstawia kopie elementów z zakresu od drugiego do trzeciego argument przed miejscem podanym jako trzeci argument.

    int more_numbers[6] = { 6, 7, 8, 9, 10, 11 };
    std::list<int> three(two);

    three.insert(three.end(), more_numbers, (more_numbers + 6));

    std::cout << "Lista one: ";

    std::for_each(one.begin(), one.end(), out_int);

    std::cout << std::endl;

    std::cout << "Lista two: ";

    std::for_each(two.begin(), two.end(), out_int);

    std::cout << std::endl;

    std::cout << "Lista three: ";

    std::for_each(three.begin(), three.end(), out_int);

    std::cout << std::endl;

    // Wypełnij listy elementami.

    for (int iterator = 0; iterator < 6; iterator++) {
        four.push_back(iterator);

        five.push_front(iterator);
    }

    three.remove(2); // Usuwa z listy wszystkie wystąpienia wartości 2.

    three.splice(three.begin(), one); // Wstawia zawartość listy podanej jako drugi argument (i usuwa jej zawartość) przed pozycję podaną jako pierwszy argument.

    five.splice(std::find(five.begin(), five.end(), 3), four); // Wstaw wszystkie elementy kontenera podanego jako drugi argument przed pierwszym elementem, do którego iterator zwróciła funkcja find wprowadzona jako pierwszy argument.

    five.splice(five.end(), five, five.begin()); // Pozycja docelowa, lista źródłowa, pozycja źródłowa (przenieś pierwszy element na koniec).
 
    three.unique(); // Łączy grupę takich samych elementów występujących obok siebie w jeden element.

    three.sort(); // Sortuje liste od wartości najmniejszej do największej.

    three.merge(two); // Scala listę podaną jako argument (i usuwa jej zawartość) z listą wywołującą.

    // Kontenery asocjacyjne.

    // Zbiory i wielozbiory.

    std::string words[] = { "Pierwszy", "Drugi", "Trzeci" };
    std::string second_words[] = { "Czwarty", "Piaty" };
    std::set<std::string> word_container(words, (words + 3)); // Zbiór obiektów typu string.
    std::set<std::string> second_word_container(second_words, (second_words + 2));
    std::set<std::string> third_word_container;
    std::ostream_iterator<std::string, char> out(std::cout, " "); // Interfejs do wyświetlania typu string na strumień cout używający typu char i separatora " ".

    std::copy(word_container.begin(), word_container.end(), out); // Kopiuj z do i posortuj.

    std::cout << std::endl;

    std::set_union(word_container.begin(), word_container.end(), second_word_container.begin(), second_word_container.end(), out); // Wysyła sumę zbiorów do strumienia podanego jako ostatni argument, sortuje i scala takie same wyrazy.

    std::set_union(word_container.begin(), word_container.end(), second_word_container.begin(), second_word_container.end(), std::insert_iterator<std::set<std::string> >(third_word_container, third_word_container.begin()));

    std::cout << std::endl;

    std::set_intersection(word_container.begin(), word_container.end(), second_word_container.begin(), second_word_container.end(), out); // Przecięcie dwóch zbiorów.

    std::cout << std::endl;

    std::set_difference(word_container.begin(), word_container.end(), second_word_container.begin(), second_word_container.end(), out); // Różnica dwóch zbiorów.

    std::cout << std::endl;

    third_word_container.insert("Kolejny"); // Wstawiamy kolejną wartość do zbioru.

    std::copy(third_word_container.lower_bound("Drugi"), third_word_container.upper_bound("Trzeci"), out); // Wyświetlanie zakresu: funkcja lower_bound przyjmuje jako argument wartość klucza i zwraca iterator, który wskazuje na pierwszy element zbioru nie mniejszy od podanego argumentu (funkcja upper_bound intuicyjnie odpowiednio).

    std::cout << std::endl;
 
    if (third_word_container.insert("Kolejny").second)
        std::cout << "Wstawiono element \"Kolejny\" do kontenera \"third_word_container\".\n";
    else
        std::cout << "Element \"Kolejny\" w kontenerze \"third_word_container\" juz istnieje.\n";

    int delete_numbers = third_word_container.erase("Kolejny"); // Usuń wszystkie elementy o podanej wartości.

    std::cout << "Usuniet " << delete_numbers << " elementow \"Kolejny\".\n";

    std::set <int, std::greater<int> > int_container; // Bez powtórzeń, elementy są wartościami całkowitymi, a porządek malejący.
    std::set<int, std::greater<int> >::iterator position; // Iterator dla kolekcji.

    int_container.insert(4);

    int_container.insert(2);

    int_container.insert(1);

    // Iteruj po wszystkich elementach.

    for (position = int_container.begin(); position != int_container.end(); ++position)
        std::cout << * position << std::endl;

    std::set<int> second_int_container(int_container.begin(), int_container.end()); // Przypisz elementy do innego zbioru w porządku rosnącym.

    std::set<int, runtime_cmp<int> > third_int_container;

    third_int_container.insert(5);

    third_int_container.insert(2);

    third_int_container.insert(1);

    runtime_cmp<int> reverse_order(runtime_cmp<int>::reverse); // Kryterium sortowania o odwrotnej kolejności elementów.

    std::set<int, runtime_cmp<int> > fourth_int_container(reverse_order);

    third_int_container = fourth_int_container; // Przypisz elementy oraz kryterium sortowania.

    if (third_int_container.value_comp() == fourth_int_container.value_comp())
        std::cout << "Zbiory third_int_container oraz fourth_int_container posiadaja to samo kryterium sortowania.\n";

    std::multiset<int, std::greater<int> > int_multicontainer; // Powtórzenia dozwolone, elementy są wartościami całkowitymi, porządek malejący.

    int_multicontainer.insert(4);

    int_multicontainer.insert(1);

    int_multicontainer.insert(5);

    std::multiset<int, std::greater<int> >::iterator multiset_pointer = int_multicontainer.insert(4); // Wstaw ponownie wartość 4.

    std::cout << "Wartosc 4 wstawiono do kontenera \"int_multicontainer\" jako element nr " << std::distance(int_multicontainer.begin(), multiset_pointer) + 1 << ".\n";

    // Mapy oraz multimapy.

    std::map<std::string, float> map_collection;

    map_collection.insert(std::map<std::string, float>::value_type("Jan", 22.3));

    map_collection.insert(std::pair<std::string, float>("Bartlomiej", 26)); // Wykorzystanie konwersji niejawnej.

    map_collection.insert(std::pair<const std::string, float>("Tomek", 26)); // Brak wykorzystania konwersji niejawnej.

    if (map_collection.insert(std::make_pair("Michal", 0)).second)
        std::cout << "Udalo sie wstawic pare Michal-0 do mapy.\n";
    else
        std::cout << "Nie udalo sie wstawic pary Michal-0 do mapy.\n";

    for (auto map_iterator = map_collection.begin(); map_iterator != map_collection.end(); ++map_iterator)
        std::cout << "Klucz: " << map_iterator->first << ", wartosc: " << map_iterator->second << std::endl;

    map_collection.erase("Tomek"); // Usuń wszystkie elementy o podanym kluczu.

    auto map_iterator = map_collection.find("Jan");

    // Poniższe dwie instrukcje sprawiają, że podany klucz zmieni swoją nazwę.

    map_collection["Jan"] = map_collection["Janek"];

    map_collection.erase("Janek");

    if (map_iterator != map_collection.end())
        map_collection.erase(map_iterator); // Usuń pierwszy element o podanym kluczu.

    map_collection["Bartek"] = map_collection["Bartlomiej"]; // Wstaw nowy element o wartości starego elementu.

    map_collection["Bonifacy"] = 0;

    for (auto map_iterator = map_collection.begin(); map_iterator != map_collection.end(); ++map_iterator)
        map_iterator->second *= 2; // Podwajamy wartość każdego klucza.

    typedef std::pair<const int, std::string> pair;
    typedef std::multimap<int, std::string> map_code;
    map_code codes;

    codes.insert(pair(41, "Bytom"));

    codes.insert(pair(81, "Bytom"));

    codes.insert(pair(81, "Sopot"));

    codes.insert(std::make_pair(33, "Krakow"));

    std::cout << "Liczba miast o kodzie 81: " << codes.count(81) << std::endl;

    std::cout << "Kod regioniu i miasto:\n";

    for (auto pointer = codes.begin(); pointer != codes.end(); ++pointer)
        std::cout << (* pointer).first << ", " << (* pointer).second << std::endl;

    std::pair<map_code::iterator, map_code::iterator> range = codes.equal_range(81);

    std::cout << "Miasta o kodzie 81:\n";

    for (auto pointer = range.first; pointer != range.second; ++pointer)
        std::cout << (* pointer).second << std::endl;

    std::cout << "Wszystkie wartosci dla klucza 81:\n";

    for (auto iterator = codes.begin(); iterator != codes.end(); ++iterator) {
        if (iterator->first == 81)
            std::cout << iterator->second << std::endl;
    }
}

void out_int(int number) {
    std::cout << number << " ";
}

Źródło:
- Prata S., Język C++. Szkoła programowania. Wydanie VI, Helion SA, 2012,
- Josuttis N. M., C++. Biblioteka standardowa, Helion SA, 2003.

Iteratory STL w C++

#include <iostream>
#include <vector>
#include <iterator>
#include <list>
#include <set>

// Definicja iteratora wstawiającego dla kontenerów asocjacyjnych.

template <class container> class associative_insert_iterator : public std::iterator<std::output_iterator_tag, void, void, void, void> {
protected:
    container & insert_container; // Kontener, do którego wstawiane są elementy.

public:
    explicit associative_insert_iterator(container & constructor_container) : insert_container(constructor_container) { }

    associative_insert_iterator<container> & operator=(const typename container::value_type & value) {
        insert_container.insert(value);

        return * this;
    }

    associative_insert_iterator<container> & operator*() {
        return * this;
    }

    associative_insert_iterator<container> & operator++() {
        return * this;
    }

    associative_insert_iterator<container> * operator++(int) {
        return * this;
    }
};

int main() {
    std::vector<double> numbers(5);
    double table[5] = { 1.204, 2.1, 3, 4, 5 };
    std::vector<double>::iterator pointer;
    // std::vector<double>::const_iterator const_pointer; // Do iterowania po elementach w trybie z odczytem i zapisem.

    // Przypisuje wszystkim elementom kontera konkretną wartość.

    for (pointer = numbers.begin(); pointer != numbers.end(); pointer++)
        * pointer = 1.2;

    std::advance(pointer, -1); // Przesuń iterator o 1 miejsce do tyłu.

    std::cout << "Roznica pomiedzy poczatkiem a aktualna pozycja iteratora liczb calkowytych wynosi " << std::distance(numbers.begin(), pointer) << ".\n";

    std::iter_swap(numbers.begin(), ++numbers.begin()); // Zamień miejscami.

    // for (auto pointer = numbers.begin(); pointer != numbers.end(); pointer++)
        // * pointer = 1.2;

    // for (auto pointer : numbers)
    // * pointer = 1.2;

    std::ostream_iterator<double, char> out_iterator(std::cout, " ");

    *out_iterator++ = 15; // Wyświetla liczbę 15 i oddziela ją spacją.

    std::cout << std::endl;

    std::istream_iterator<int> int_reader(std::cin); // Utwórz iterator strumieniowy wejściowy odczytujący dane ze strumienia cin.
    std::istream_iterator<int> int_reader_off; // Iterator końca strumienia.

    // Dopóki możliwy jest odczyt elementów z wykorzystaniem iteratora strumieniowego wejściowego to wypisuj je.

    while (int_reader != int_reader_off) {
        std::cout << "Podales: " << * int_reader << std::endl;

        ++int_reader;
    }

    std::copy(table, (table + 5), numbers.begin()); // Kopiuje tablicę do wektora.

    std::copy(numbers.begin(), numbers.end(), out_iterator); // Kopiuje wektor do strumienia wyjścia.

    std::cout << std::endl;

    // std::copy(numbers.begin(), numbers.end(), std::ostream_iterator<int, char>(std::cout, " "));

    std::copy(numbers.rbegin(), numbers.rend(), out_iterator); // Kopiuje wektor do strumienia wyjścia w odwrotnej kolejności.

    std::cout << std::endl;

    std::vector<double>::reverse_iterator reverse_pointer;

    // std::vector<double>::reverse_iterator reverse_pointer(pointer); // Konwertuj iterator na iterator odwrotny.

    // std::vector<double>::iterator reverse_reverse_pointer;

    // reverse_reverse_pointer = reverse_pointer.base(); // Konwertuj z powrotem na iterator normalny.

    // Wypisuje w odwrotnej kolejności.

    for (reverse_pointer = numbers.rbegin(); reverse_pointer != numbers.rend(); reverse_pointer++)
        std::cout << *reverse_pointer << std::endl;

    std::string words[] = { "Pierwszy", "Drugi", "Trzeci", "Czwarty" };
    std::vector<std::string> word_vector(4);

    std::copy(words, (words + 4), word_vector.begin());

    std::copy(words, (words + 2), std::back_insert_iterator<std::vector<std::string> >(word_vector)); // Wstawia dwa ciągi z tablicy stringów na koniec wektora zwiększając tym samym ilość jego elementów do 6.

    numbers.clear(); // Wyczyść zawartość

    std::list<int> lists;
    std::set<int> sets;
    std::back_insert_iterator<std::vector<double> > bi_iterator(numbers); // Utwórz wstawiacz końcowy dla wektora.
    std::front_insert_iterator<std::list<int> > fi_iterator(lists); // Utwórz wstawiacz początkowy dla listy.
    std::insert_iterator<std::set<int> > i_iterator(sets, sets.begin()); // Utwórz wstawiacz ogólny dla kontenera typu set.

    * bi_iterator = 1; // Wstaw element.

    ++bi_iterator; // Przesuń iterator na kolejny element.

    * bi_iterator = 2;

    std::back_inserter(numbers) = 3; // Wstaw element.

    std::back_inserter(numbers) = 4;

    std::front_inserter(lists) = 1;

    std::inserter(sets, sets.begin()) = 1;

    std::copy(numbers.begin(), numbers.end(), out_iterator);

    // Użycie iterator zdefiniowanego przez użytkownika.

    std::set<int> collection;
    associative_insert_iterator<std::set<int> > aii_iterator(collection);

    * aii_iterator = 1;

    aii_iterator++;
}

Źródło:
- Prata S., Język C++. Szkoła programowania. Wydanie VI, Helion SA, 2012,
- Josuttis N. M., C++. Biblioteka standardowa, Helion SA, 2003.

Wektory STL w C++

#include <iostream>
#include <vector>
#include <algorithm>

bool is_lower_than_3(double number);

int main() {
    std::vector<int> numbers(5); // Wektor 5 liczb całkowitych.
    // std::vector<int> numbers(5, 1); // Wektor pięciu liczb 1.
    int elements;

    std::cout << "Ile wektor lancuchow ma miec elementow: ";

    std::cin >> elements;

    std::vector<std::string> titles(elements);

    // Przypisanie konkretnym elementom wektora danych wartości.

    for (int iterator = 0; iterator < numbers.size(); iterator++)
        numbers[iterator] = iterator; // Brak kontroli zakresu.

    try {
        numbers.at(5) = 6; // Kontrola zakresu.
    } catch (std::out_of_range & extension) {
        std::cout << "Blad kontroli zakresu: " << extension.what() << std::endl;
    }

    std::vector<int>::iterator pointer; // Deklaracja iteratora.
    // auto pointer = numbers.begin();

    pointer = numbers.begin(); // Iterator wskazuje na pierwszy element wektora.

    *pointer = 1;

    ++pointer; // Przesuwamy iterator na kolejny element.

    *pointer = 2;

    numbers.back() = 0; // Przypisz ostatniemu elementowi wartość 0.

    // Wypisanie wszystkich elementów wektora za pomocą iteratora.

    for (pointer = numbers.begin(); pointer != numbers.end(); pointer++)
        std::cout << * pointer << std::endl;

    std::vector<double> scores;

    std::cout << "Najwieksza mozliwa liczba elementor dla wektora zmiennych typu double to w tym wypadku " << scores.max_size() << " natomiast w aktualnym obszarze pamieci moze pomiescic " << scores.capacity() << " elementy.\n"; // Funkcja capacity zwróci wartość większa od zera dopiero jak w wektorze znajdą się jakieś wartości.

    std::cout << "Ile chcesz wprowadzic wartosci punktow: ";

    std::cin >> elements;

    // scores.reserve(elements); // Zarezerwuj obszar pamięci na elements elementów.

    double temporary;

    for (int iterator = 0; iterator < elements; iterator++) {
        std::cout << "Podaj wartosc: ";

        std::cin >> temporary;

        scores.push_back(temporary); // Dodaje element na koniec wektora. Z kolei funkcja pop_back usuwa ostatni element.
    }

    scores.erase(scores.begin(), (scores.begin() + 2)); // Usuwamy pierwszy i drugi element.

    std::cout << "Podaj ktora wartosc chcesz usunac z kontenera liczb calkowitych: ";

    std::cin >> elements;

    pointer = std::find(numbers.begin(), numbers.end(), elements);

    if (pointer != numbers.end())
        numbers.erase(pointer);

    std::vector<double> new_scores(scores); // Konstruktor kopiujący.

    new_scores.insert(new_scores.begin(), scores.begin(), scores.end()); // Wstawia przed pierwszy element wektora (określany jako pierwszy argument) wartości wektora określane zakresem drugiego i trzeciego argumentu.

    for_each(new_scores.begin(), new_scores.end(), is_lower_than_3); // Dla każdego elementu z zakresu podanego przez iteratory wywołujemy daną funkcję.

    // for (auto iterator : new_scores)
        // is_lower_than_3(iterator);

    std::random_shuffle(new_scores.begin(), new_scores.end()); // Zamienia kolejność elementów w sposób losowy.

    std::sort(new_scores.begin(), new_scores.end()); // Sortuje wartości w porzadku rosnącym (jeśli elementy kontenera nie są zdefiniowane przez użytkownika). Jeżeli chcemy sortować w porządku malejącym to musimy napisać funkcję, która porównuje dwa pierwsze argumenty funkcji sort, a jej nazwę podać jako trzeci argument.

    std::vector<int> next_numbers(numbers.begin(), numbers.end());

    new_scores.resize(0); // Ustawia liczbę elementów kontenera na 0.

    new_scores.clear(); // Opróżnia kontener.

    new_scores.~vector<double>(); // Niszczy wszystkie elementy i zwalnia pamięć.
}

bool is_lower_than_3(double number) {
    if (number < 3)
        return true;
    else
        return false;
}

Źródło:
- Prata S., Język C++. Szkoła programowania. Wydanie VI, Helion SA, 2012,
- Josuttis N. M., C++. Biblioteka standardowa, Helion SA, 2003.

piątek, 27 czerwca 2014

Kod C++ - rekurencja

#include <iostream>
#include <ctime>
#include <cstdlib>

int exponentiation_recursion(int base, int index);
int exponentiation_iteration(int base, int index);
int fibonacci_recursion(int number);
int fibonacci_iteration(int number);
int factorial_recursion(int number);
int factorial_iteration(int number);
double execution_time(int (* pointer)(int), int argument, int & result); // Funkcja obliczająca czas wykonania danej funkcji.
double execution_time(int (* pointer)(int, int), int first_argument, int second_argument, int & result); // Funkcja obliczająca czas wykonania danej funkcji (przeładowanie).

int main() {
    int result;
    double recursion_time, iteration_time;

    recursion_time = execution_time(fibonacci_recursion, 30, result);

    iteration_time = execution_time(fibonacci_iteration, 30, result);

    std::cout << "Funkcja obliczajaca rekurencyjnie ciag Fibonacciego dla liczby 30 wykonala sie w czasie " << recursion_time << " sekund.\n";

    std::cout << "Funkcja obliczajaca iteracyjnie ciag Fibonacciego dla liczby 30 wykonala sie w czasie " << iteration_time << " sekund.\n";

    recursion_time = execution_time(exponentiation_recursion, 2, 30, result);

    iteration_time = execution_time(exponentiation_iteration, 2, 30, result);

    std::cout << "Funkcja obliczajaca rekurencyjnie 2 do potegi 30 wykonala sie w czasie " << recursion_time << " sekund.\n";

    std::cout << "Funkcja obliczajaca iteracyjnie 2 do potegi 30 wykonala sie w czasie " << iteration_time << " sekund.\n";
}

int exponentiation_recursion(int base, int index) {
    if (index == 0) // Przypadek elementarny.
        return 1;
    else
        return (base * exponentiation_recursion(base, (index - 1)));
}

int exponentiation_iteration(int base, int index) {
    if (index == 0)
        return 1;
    else if (index == 1)
        return base;
    else {
        int result = base;

        for (int iterator = 2; iterator <= index; iterator++)
            result *= base;

        return result;
    }
}

int fibonacci_recursion(int number) {
    if ((number == 1) || (number == 2)) // Przypadek elementarny.
        return 1;
    else
        return (fibonacci_recursion(number - 1) + fibonacci_recursion(number - 2));
}

int fibonacci_iteration(int number) {
    if ((number == 1) || (number == 2))
        return 1;
    else {
        int result;
        int before = 1, after = 1;

        for (int iterator = 3; iterator <= number; iterator++) {
            result = (before + after);

            before = after;

            after = result;
        }

        return result;
    }
}

int factorial_recursion(int number) {
    if (number == 0) // Przypadek elementarny.
        return 1;
    else
        return (number * factorial_recursion(number - 1));
}

int factorial_iteration(int number) {
    if (number == 0)
        return 1;
    else {
        int result = 1;

        for (int iterator = 1; iterator <= number; iterator++)
            result *= iterator;

        return result;
    }
}

double execution_time(int (* pointer)(int), int argument, int & result) {
    clock_t start, stop;
    double time;

    start = clock();

    result = pointer(argument);

    stop = clock();

    time = static_cast<double>(stop - start); // Wynikiem jest liczba cykli procesora.

    time /= CLOCKS_PER_SEC; // Wynik w sekundach.

    return time;
}

double execution_time(int (* pointer)(int, int), int first_argument, int second_argument, int & result) {
    clock_t start, stop;
    double time;

    start = clock();

    result = pointer(first_argument, second_argument);

    stop = clock();

    time = static_cast<double>(stop - start); // Wynikiem jest liczba cykli procesora.

    time /= CLOCKS_PER_SEC; // Wynik w sekundach.

    return time;
}

poniedziałek, 5 maja 2014

Różnice między C++ a C ciąg dalszy

1) W C++ istnieje dokładniejsza kontrola typów wyliczeniowych. Jeżeli definiujemy np. "enum typ" to w języku C jest możliwy zapis "typ++" natomiast w C++ nie.
2) W języku C definicja zmiennych musi nastąpić na początku wywołania funkcji main.
3) W języku C++ nie można wywołać niezadeklarowanej uprzednio funkcji.
4) C dopuszcza przypisanie wskaźnikowi do void każdego innego typu. W C i C++ możliwa jest następująca instrukcja (przy założeniu, że "integer" jest zmienną typu int równą 10): "void * wskaznik_do_void = & integer". Natomiast "int * wskaznik_do_integer = wskaznik_do_void" dopuszczalne jest tylko w C.
5) C nie pozwala aby struktura nie zawierała danych składowych.
6) W C dozwolony jest zapis np. "const int zmienna" natomiast w C++ nie. Kompilator języka C przyjmuje taki zapis jako deklarację obszaru pamięci przydzielonego w jakimś innym miejscu programu. Jest to dopuszczalne z uwagi na to, iż w języku C stałe są domyślnie łączone zewnętrznie. W C++ domyślnie w stosunku do stałych jest stosowane łączenie wewnętrzne. W C++ stałe nie zawsze zajmują pamięć (w przeciwieństwie do C).
7) Język C wymagał podczas deklaracji zmiennych strukturalnych poprzedzanie nazwy struktury łańcuchem "struct". W C++ jest to zbędne.
8) Struktury języka C nie mogą posiadać funkcji składowych.

Przeczytaj część pierwszą.

Źródło: Eckel B., Thinking in C++. Edycja polska, Helion SA, 2002

C++11

W stosunku do poprzedniej wersji języka C++ wprowadzono m.in. następujące nowości:
  • typ long long,
  • typy char16_t i char32_t dla zmiennych bez znaku odpowiednio o szerokości 16 i 32 bitów (literały znakowe i napisowe dla typu char16_t są poprzedzone literą u natomiast dla char32_t są poprzedzone literą U),
  • obsługa dla wariantu kodowania znaków UTF-8 (literał poprzedzamy przedrostkiem "u8"),
  • łańcuch literalny, który sprawia, że znaki nie są interpretowane przez kompilator czyli można je wpisywać wprost w łańcuchu jak np. znaki specjalne łącznie ze znakami cudzysłowu (przed literałem dodajemy tutaj "R"),
  • inicjalizacja zmiennych: "int zmienna{1};" oraz instrukcja "int zmienna{}", która wstawia do zmiennej wartość 0, 
  • podobnie inicjalizacja tablic: "double tablica[2] {1.26e4, 1.11e-8};"  i wypełnianie wartościami zerowymi w postaci "double tablica[10] {};",
  • nadawanie wartości początkowych łańcuchom znaków: "char znaki[] = {"Znaki"};" lub "char znaki[] {"Znaki"};", a także "string signs = {"Znaki"};" lub "string signs {"Znaki"};",
  • podobnie sytuacja ma miejsce w przypadku struktur: "struct struktura {"Pole 1", 2, 3.0}" i dla inicjalizacji wartościami zerowymi "struct struktura {}",
  • przyrostki "LL" i "ULL" dla literałów odpowiednio typu long long i unsigned long,
  • dedukowanie typu zmiennej na podstawie typu wartości inicjalizującej gdzie np. instrukcja "auto zmienna = 0.0" określa zmienną jako double, a instrukcja "auto zmienna = 0" jako int,
  • klasa szablonowa array będąca skuteczną i bezpieczną alternatywą dla tablic wbudowanych o stałym rozmiarze,
  • pętla zakresowa for postaci "for (typ zmienna : tablica)" gdzie "typ" jest typem danych przechowywanych w "tablica", a "zmienna" przyjmuje wartość pierwszego elementu z danego zestawu danych (pętla przechodzi po wszystkich elementach tablicy),
  • referencja do r-wartości deklarowana jest np. jako "int && r_value = (2 * zmienna  + 20);" co niedozwolone jest dla zwykłej referencji,
  • wyrażenie "decltype" umożliwia określenie tego samego typu zmiennej, np. wyrażenie "decltype(zmienna_1) zmienna_2;" przypisuje "zmienna_2" typ "zmienna_1", a z kolei wyrażenie "decltype(zmienna_1 + zmienna_2) zmienna_3;" przypisuje "zmienna_3" typ wyrażenia ujętego w nawiasy,
  • opóźniona deklaracja typu zwracanego: "auto funkcja(typ zmienna_1, typ zmienna_2) -> double;" czy też "auto funkcja(typ zmienna_1, typ zmienna_2) -> decltype(zmienna_1 + zmienna_2);",
  • specyfikator thread_local wskazujący, że czas życia zmiennej jest równy czasowi życia wątku zawierającego zmienną (zmienna z tym przydomkiem jest dla wątku tym samym co zmienna statyczna dla całego programu),
  • inicjalizacja operatorem new: możliwe są np. takie instrukcje jak "int * tablica = new int[2] {1, 2};" czy też "double * wskaznik = new int {1};",
  • inicjalizacja obiektu klasy za pomocą listy: "klasa obiekt = {"Argument", 1, 2.0};",
  • wyliczenia z własnym zasięgiem: deklarując typ wyliczeniowy jako "enum nazwa_klasy nazwa_typu_wyliczeniowego {Element_1, Element_2}" możemy odwoływać się do elementów wyliczenia np. jako "nazwa_typu_wyliczeniowego nazwa_odniesienia = nazwa_typu_wyliczeniowego::Element_1" co pozwala na eliminację problemu kolizji nazw elementów wyliczeń poprzez nadanie im zasięgu klasy,
  • w C++11 domyślnym typem wewnętrznym wyliczenia jest int jednak można ręcznie określić pożądanym typ wewnętrzny za pomocą wyrażenia o postaci np. "enum nazwa_klasy : short nazwa_typu_wyliczeniowego {Element1, Element2}" (typ wewnętrzny musi być typem całkowitoliczbowym,
  • w C++98 słowo "explicit" nie działa z funkcjami konwersji w przeciwieństwie do C++11,
  • notacja "nullptr" określająca wskaźnik pusty,
  • inicjalizacja składowych klas: zapis "class klasa { int zmienna = 1; };" równoważny jest zapisowi "klasa::klasa() : zmienna(1) { }" jako liście inicjalizacyjnej,
  • szablon będący argumentem typu dla innego szablonu: w poprzedniej wersji C++ w obawie przed mylną interpretacją operatora przesunięcia bitowego należało pisać deklarację w postaci np. "szablon < klasa<int> > obiekt;" natomiast w C++ ten problem został już zażegnany,
  • szablonowe aliasy typów: zamiast stosowania deklaracji np. "typedef std::klasa<int, 1> aliast" możemy wykorzystać instrukcję "template<typename type> using alias = std::klasa<type, 1>" co sprawia, że pisząc np. "alias<double> obiekt" określamy, iż "obiekt" jest typu "std::klasa<double, 1>",
  • klasa kontenerowa forward_list, która implementuje zwyczajną listę jednokierunkową,
  • szablon klasy array,
  • nieuporządkowane kontenery asocjacyjne typu unordered_set, unordered_multiset, unordered_map i unordered_multimap,
  • szablon initializer_list, który pozwala na stosowanie składni listy inicjalizującej do inicjalizowania kontenerów STL listami wartości,
Źródło: Prata S., Język C++. Szkoła programowania, Wydanie VI, Helion SA, 2012