Untitled
unknown
plain_text
10 months ago
17 kB
3
Indexable
#include <iostream>
#include <string>
#include <chrono>
using namespace std;
// struktura simple_object
struct simple_object {
string word;
double key;
friend ostream& operator<<(ostream& os, simple_object so);
};
// komparator dla simple_object
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;
}
// Przeciążenia operatorów dla simple_object dla printowania
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;
}
// Komparator - zgodnie z tym co w instrukcji, stworzony na potrzeby HeapSorta jako argument
int int_cmp(int i1, int i2) {
if (i1 == i2)
return 0;
else if (i1 < i2)
return -1;
else if (i1 > i2)
return 1;
}
// heapSort
enum mode { BOTTOM_UP, TOP_DOWN }; // enumerator definiujacy czy kopiec ma byc tworzony od dolu czy od gory
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) - i to jest wlasnie podpunkt z roszerzenia kopca
heap_array = array; // uznajemy ze ta tablica to kopiec i dopiero ja bedziemy naprawiac, buduje kopiec z tej tablicy i dopiero potem sortuje
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 stworzeniu 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);
}
}
// zwraca element z indeksem index
T get(int index) {
if (index < size) {
return heap_array[index];
}
}
// do wyliczania indeksów rodzica, lewego i prawego dziecka
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);
}
// przekopcowanie w góre (z poprzedniego zadania) - uzywane podczas tworzenia kopca wyzej w funkcji
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);
}
}
// do wyprintowania kopca
string str(string(*func)(T), int k = -1) {
return heap_array->str(func, k);
}
// przekopcowanie w dół (z poprzedniego zadania) - uzywane podczas tworzenia kopca wyzej w funkcji
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;
}
// 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++;
}
// do wstawiania danych w odpowiednim miejscu w bucketsort
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;
// do dzielenia kubelkow na czesci (rzutowanie na floata zeby nie bylo dzielenia calkowitego)
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 = min((int)(key / (max / buckets)), buckets - 1); // 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_double(simple_object so) {
return so.key;
}
// EKSPERYMENTO DO INTÓW
//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];
//
// // Losowanie liczb
// 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));
//
// // Sortowanie przez zliczanie
// auto t1 = std::chrono::high_resolution_clock::now();
// countSort(array1, n, m);
// auto t2 = std::chrono::high_resolution_clock::now();
// auto counting_sort_duration = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count();
//
// cout << "\nCounting sort czas: " << counting_sort_duration << " mikrosekund" << endl;
// for (int i = 0; i < 10; i++) { // Pierwsze 10 elementów
// cout << array1[i] << ", ";
// }
//
// // Sortowanie przez kopcowanie
// t1 = std::chrono::high_resolution_clock::now();
// HeapSort<int>* bh = new HeapSort<int>(array2, n, int_cmp, BOTTOM_UP);
// t2 = std::chrono::high_resolution_clock::now();
// auto heap_sort_duration = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count();
//
// cout << "\nHeap sort czas: " << heap_sort_duration << " mikrosekund" << endl;
// for (int i = 0; i < 10; i++) { // Pierwsze 10 elementów
// cout << array2[i] << ", ";
// }
// delete bh;
//
// // Sortowanie kubełkowe
// t1 = std::chrono::high_resolution_clock::now();
// bucketSort(array3, n, m);
// t2 = std::chrono::high_resolution_clock::now();
// auto bucket_sort_duration = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count();
//
// cout << "\nBucket sort czas: " << bucket_sort_duration << " mikrosekund" << endl;
// for (int i = 0; i < 10; i++) { // Pierwsze 10 elementów
// cout << array3[i] << ", ";
// }
//
// // Sprawdzanie poprawności wyników sortowania
// for (int i = 0; i < n; i++) {
// if (array1[i] != array2[i] || array1[i] != array3[i]) {
// cout << "Blad sortowania";
// break;
// }
// if (i == n - 1)
// cout << "\n\nSortowanie poprawne";
// }
//
// delete[] array1;
// delete[] array2;
// delete[] array3;
// }
//}
// EKSPERYMENT DO RESZTY
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];
simple_object* array2 = new simple_object[n];
for (int i = 0; i < n; i++) {
array1[i].key = ((rand() << 15) + rand()) / m_double;
array1[i].word = 'a' + rand() % 26; // 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] << ", ";
t1 = clock();
bucketSort(array2, n, 1.0, simple_object_key_double, simple_object_comparator);
t2 = clock();
// Sprawdzanie poprawności wyników sortowania
//for (int i = 0; i < n; i++) {
// if (array1[i] != bh[i]) {
// cout << "Blad sortowania";
// break;
// }
// if (i == n - 1)
// cout << "\n\nSortowanie poprawne";
//}
delete[] array1;
//delete[] bh;
delete[] array2;
// DZIAŁA HEAP SORT NIE DZIAŁA BUCKET SORT NIE WIADOMO CZEMU
}
}
// 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];
// }
Editor is loading...
Leave a Comment