Untitled

 avatar
unknown
plain_text
24 days ago
14 kB
1
Indexable
#include <iostream>
#include <string>
using namespace std;


struct simple_object {

    string word;
    double key;

    friend ostream& operator<<(ostream& os, simple_object so);

};



int simple_object_comparator(simple_object so1, simple_object so2) {
    if (so1.key == so2.key)
        return 0;
    else if (so1.key < so2.key)
        return -1;
    else if (so1.key > so2.key)
        return 1;
}

ostream& operator<<(ostream& os, simple_object so) { // CHUJ WIE
    string key = to_string(so.key);
    key.erase(key.find_last_not_of('0') + 1, string::npos);
    key.erase(key.find_last_not_of('.') + 1, string::npos);
    os << "Word: " + so.word + "; key: " + key + "\n";
    return os;
}

int int_cmp(int i1, int i2) { // jest potrzebny do heapsorta jako argument
    if (i1 == i2)
        return 0;
    else if (i1 < i2)
        return -1;
    else if (i1 > i2)
        return 1;
}

// heapSort
enum mode { BOTTOM_UP, TOP_DOWN };

template <typename T>
struct HeapSort {
    int size;
    T* heap_array;
    HeapSort(T* array, int n, int (*func)(T, T), bool mode = BOTTOM_UP) { // konstruktor (tablica, rozmiar, komparator, tryb)
        heap_array = array; // uznajemy ze ta tablica to kopiec i dopiero ja bedziemy naprawiac

        if (mode == BOTTOM_UP) { // w razie czego sprawdzic czy nie pomylil krystian nazw !!!
            size = 0; // uznajemy ze tablica jest pusta mimo ze tak naprawde jest pelna
            for (int i = 0; i < n; i++) { // przy kazdej iteracji zwiekszamy (uznajemy ze jest o jeden wiekszy jest jej rozmiar)
                size++;
                heapUp(size, func); // tak jakby odkrywamy sobie po elemencie i robimy heap up
            }
        }
        else if (mode == TOP_DOWN) {
            size = n; // uznajemy ze jest pelna tablica (widzimy ja cala)
            for (int i = size / 2; i > -1; i--) { // idziemy od size/2 (taka zasada w heapie, bo ona nam pozwala na pominiecie liscie (ostatniego rzedu elementow))
                heapDown(i, func);
            }
        }

        sort(size, func); // konstruktor u mnie odrazu sortuje jakby sie przyprul skurwol zamaist tworzyc kopca i uzyc funkcje to dziala odrazu razem z tworzeniem kopca bo tak mi bylo wygodniej

    }

    // po naprawieniu kopca, idziemy od ostatniego elementu w tyl (przedostatni itd) oraz zawsze zamieniamy ostatni n-1 z pierwszym, zmniejszamy size (czyli potem ostatnim bedzie ten co chwile przed tym był przedostatnim) i robimy heap down, w zwiazku z czym po posortowaniu na samym dole (w lisciach kopca) bedziemy mieli najwieksze elementy
    void sort(int& size, int (*func)(T, T)) {
        for (int i = size - 1; i > 0; i--) {
            swap(heap_array[i], heap_array[0]); // jak cos to pomoc z neta (zawsze raczej bedzie wygldadac tak samo)
            size--;
            heapDown(0, func);
        }
    }

    T get(int index) {

        if (index < size) {
            return heap_array[index];
        }
    }

    int parent(int i) {
        i++;
        return (i >> 1) - 1;
    }
    int left_child(int i) {
        i++;
        return (i << 1) - 1;
    }
    int right_child(int i) {
        i++;
        return (i << 1);
    }

    void heapUp(int el_index, int (*func)(T, T)) {
        if (func(heap_array[el_index], heap_array[parent(el_index)]) == 1 && el_index > 0) {
            T tmp = heap_array[parent(el_index)];
            heap_array[parent(el_index)] = heap_array[el_index];
            heap_array[el_index] = tmp;
            heapUp(parent(el_index), func);
        }
    }

    string str(string(*func)(T), int k = -1) {
        return heap_array->str(func, k);
    }

    void heapDown(int el_index, int (*func)(T, T)) {

        int l_child_index = left_child(el_index);
        int r_child_index = right_child(el_index);

        int largest;
        if (l_child_index < size && func(heap_array[l_child_index], heap_array[el_index]) == 1)
            largest = l_child_index;
        else
            largest = el_index;

        if (r_child_index < size && func(heap_array[r_child_index], heap_array[largest]) == 1)
            largest = r_child_index;

        if (el_index != largest) {
            swap(heap_array[el_index], heap_array[largest]);
            heapDown(largest, func);
        }
    }
};



// count sort -> wykład 1:1, tak ma po prostu byc kazdy probably bedzie mial to samo
void countSort(int* arr, int size, int max) {
    int* array = new int[max] { 0 };

    for (int i = 0; i < size; i++)
        array[arr[i]]++;

    int i = 0;
    for (int j = 0; j < max; j++) {
        while (array[j] > 0) {
            array[j]--;
            arr[i++] = j;
        }
    }

    delete[] array;  // nw czy zadziała
}




// BucketSort
template <typename T>
struct Node {
    struct Node<T>* prev = nullptr;
    T data;
    struct Node<T>* next = nullptr;
};

template <typename T>
struct LinkedList {
    struct Node<T>* head = nullptr;
    struct Node<T>* tail = nullptr;
    int size = 0;

    T get(int i) {


        Node<T>* n = head;

        for (int j = 0; j < i; j++) {
            n = n->next;
        }

        return n->data;
    }

    void pushFront(T data) {

        // tworzenie węzła
        Node<T>* n = new Node<T>();
        n->data = data;

        n->next = head;

        // jeśli nie został wcześniej dodany żaden element
        if (head != nullptr) {
            head->prev = n;
        }
        else {
            tail = n;
            head = n;
        }

        head = n;

        // zwiększenie informacji o ilości elementów znajdujących się w liście
        size++;
    }

    void sortInsert(T data, int (*func)(T, T)) {
        if (head == nullptr || func(head->data, data) == 1 || func(head->data, data) == 0) {
            pushFront(data);
            return;
        }
        else if (func(tail->data, data) == -1 || func(tail->data, data) == 0) {
            pushBack(data);
            return;
        }


        Node<T>* current = head;

        while (current->next != nullptr && func(current->next->data, data) == -1) {
            current = current->next;
        }

        Node<T>* newNode = new Node<T>();
        newNode->data = data;
        newNode->next = current->next;
        current->next = newNode;

        size++;
    }


    void pushBack(T data) {

        // tworzenie węzła
        Node<T>* n = new Node<T>();
        n->data = data;

        n->prev = tail;

        // jeśli nie został wcześniej dodany żaden element
        if (tail != nullptr) {
            tail->next = n;
        }
        else {
            head = n;
            tail = n;
        }

        tail = n;

        // zwiększenie informacji o ilości elementów znajdujących się w liście
        size++;
    }

    void clear() {
        Node<T>* n = head;
        Node<T>* lastFound = nullptr;

        if (head == nullptr) {
            cout << "Lista nie zawiera żadnych elementów";
            return;
        }

        while (true) {
            lastFound = n;

            n = n->next;

            if (n == nullptr)
                break;

            delete n->prev;

            size--;
        }

        delete lastFound;

        // ustawienie tail i head na nullptr
        head = tail = nullptr;
    }

    int getSize() {
        return size;
    }
};

// BucketSort dla int
void bucketSort(int* arr, int size, int max) {

    int buckets = size;
    int sep = ceil(max / (float)buckets); // może z internetu, na stronie geeksforgeeks byl wytlumaczone chyba, tylko trzeba zjechac na dol strony i pod kodem bedzie podział dla intow zamiast dla float chyba

    LinkedList<int>* array = new LinkedList<int>[buckets];
    int index;
    for (int i = 0; i < size; i++) {
        index = arr[i] / sep;
        array[index].sortInsert(arr[i], int_cmp);
    }

    for (int i = 0; i < size; i++)
        arr[i] = 0;

    int j = 0;
    for (int i = 0; i < buckets; i++) {
        int list_size = array[i].getSize();
        for (int k = 0; k < list_size; k++) {
            arr[j++] = array[i].get(k);
        }

        if (array[i].getSize())
            array[i].clear();
    }
    delete[] array;
}

// BucketSort dla reszty (to nie jest sortowanie w miejscu, z tych 3  tylkko heapsort jest)
template <typename T>
void bucketSort(T* arr, int size, double max, double (*func_k)(T), int (*func_cmp)(T, T)) {

    int buckets = size;

    // jest kubełkow tyle ile jest elementow w tablicy, zeby przy rozkladzie jakims jednostajnym wyszlo tak ze do kubelka trafi jedna liczba czyli nie bedzie trzeba sortowac kubelka (sortowanie w srodku ma byc jak najkrotsze, a w kubelku chcemy zeby bylo jak najmniej elementow)
    // najlepsze n+k, a najgorszy przypadek n^2
    LinkedList<T>* array = new LinkedList<T>[buckets];
    int index;
    double key;
    for (int i = 0; i < size; i++) {
        key = func_k(arr[i]); // funkcja ktora bierze klucz z obiektu
        index = key / (max / buckets); // przydzielenie wartosci indeksu kubelka do ktorego ma trafic element z tablicy (kazdy kubelek to lista, a jak lista jednoelementowa to nie ma co sortowac prosciutto crudo)
        array[index].sortInsert(arr[i], func_cmp); // 1 sposob -> powkladac wszystko i posortowac, 2 sposob -> odrazu sie wklada do kubelka w miejscu w ktorym powinno byc (tutaj uzywamy 2 sposobu)
    } // po tym mam wszystkie juz elementy w kubelkach i kubelki sa posortowane

    // caly ten for odpowiada za wyciaganie z kubelkow do tablicy jako posortowane elementy
    int j = 0;
    for (int i = 0; i < buckets; i++) { // mamy pierwszy kubelek, w nim lista i iterujemy po kubelkach i z kazdego kubelka wyciagamy te elementy
        int list_size = array[i].getSize();
        for (int k = 0; k < list_size; k++) {
            arr[j++] = array[i].get(k); // dodawanie posortowanych elementow z kubelka do tablicy
        }

        if (list_size != 0)
            array[i].clear(); // czyszczenie listy
    }
    delete[] array; // zwalniamy pamiec

}

double simple_object_key(simple_object so) {
    return so.key;
}

// int main()
// {
//     srand(time(NULL));

//     //int tablica[30];
//     //for (int i = 0; i < 30; i++)
//     //    tablica[i] = rand() % 100;

//     //cout << "Talibca: \n";
//     //for (int i = 0; i < 30; i++) {
//     //    cout << tablica[i] << ", ";
//     //}
//     //cout << "\n";


//     //countSort(tablica, 30, 100);
//     //bucketSort(tablica, 30, 100);


//     // HeapSort<int>* bh = new HeapSort<int>(tablica, 30, int_cmp, BOTTOM_UP);
//     //for (int i = 0; i < 30; i++)
//     //    cout << tablica[i] << ", ";

//     simple_object so_tab[]{ {"marcin9", 10.}, {"marcin1", 0.87}, {"marcin3", 1.87}, {"marcin0", 0.00568}, {"marcin4", 2.33},{"marcin10", 10.008}, {"marcin6", 5.18}, {"marcin2", 1.07}, {"marcin5", 3.33}, {"marcin8", 9.33}, {"marcin7", 8.1} };
//     bucketSort(so_tab, 11, 11, simple_object_key, simple_object_comparator);
//     for (int i = 0; i < 11; i++)
//         cout << so_tab[i];
// }

int main()
{
    const int MAX_ORDER = 7;
    const int m = (int)pow(10, 7);

    for (int o = 1; o <= MAX_ORDER; o++) {
        const int n = (int)pow(10, o);
        int* array1 = new int[n];

        for (int i = 0; i < n; i++) {
            array1[i] = rand() % m;
        }

        int* array2 = new int[n];
        int* array3 = new int[n];
        memcpy(array2, array1, n * sizeof(int));
        memcpy(array3, array1, n * sizeof(int));

        clock_t t1 = clock();
        countSort(array1, n, m);
        clock_t t2 = clock();

        cout << "\nCounting sort czas: " << (t2 - (double)t1) / CLOCKS_PER_SEC << endl;
        for (int i = 0; i < 10; i++) { // pierwsze 10 elementow
            cout << array1[i] << ", ";
        }


        t1 = clock();
        HeapSort<int>* bh = new HeapSort<int>(array2, n, int_cmp, BOTTOM_UP);
        t2 = clock();

        cout << "\nHeap sort czas: " << (t2 - (double)t1) / CLOCKS_PER_SEC << endl;
        for (int i = 0; i < 10; i++) { // pierwsze 10 elementow
            cout << array2[i] << ", ";
        }

        t1 = clock();
        bucketSort(array3, n, m);
        t2 = clock();
        cout << "\nBucket sort czas: " << (t2 - (double)t1) / CLOCKS_PER_SEC << endl;
        for (int i = 0; i < 10; i++) { // pierwsze 10 elementow
            cout << array3[i] << ", ";
        }

        delete[] array1;
        delete[] array2;
        delete[] array3;
    }
}


//int main() {
//    const int MAX_ORDER = 7; // m a k s y m a l n y rzad w i e l k o s c i s o r t o w a n y c h danych
//    const double m_double = (double)pow(2, 30); // m i a n o w n i k przy u s t a l a n i u losowej liczby
//
//    for (int o = 1; o <= MAX_ORDER; o++) {
//        const int n = (int)pow(10, o);
//
//        simple_object* array1 = new simple_object[n];
//
//        for (int i = 0; i < n; i++) {
//            array1[i].key = rand();
//            array1[i].word = "hjkhkjhkj"; // obojetnie jakie bo i tak nie bierze udzial w niczym 
//        }
//
//        clock_t t1 = clock();
//        HeapSort<simple_object>* bh = new HeapSort<simple_object>(array1, n, simple_object_comparator, TOP_DOWN);
//        clock_t t2 = clock();
//
//        cout << "\nHeap sort czas: " << (t2 - (double)t1) / CLOCKS_PER_SEC << endl;
//        for (int i = 0; i < 10; i++)
//            cout << array1[i] << ", ";
//
//        delete[] array1;
//        delete[] bh;
//
//        // DZIAŁA HEAP SORT NIE DZIAŁA BUCKET SORT NIE WIADOMO CZEMU
//
//    }
//}



Leave a Comment