matematykaszkolna.pl
uproszczenie kodu Mariusz: template <class T> void LinkedList<T>::insert(T k,int (*Compare)(T,T)) { Link<T> *x,*y,*z; x = new Link<T>(k); y = getFirst(); z = nullptr; while(y != nullptr && Compare(x−>getData(),y−>getData()) > 0) { z = y; y = y−>getNext(); } x−>setNext(y); x−>setPrevious(z); if(z == nullptr) { if(getFirst() != nullptr) getFirst()−>setPrevious(x); setFirst(x); } else { if(y != nullptr) y−>setPrevious(x); z−>setNext(x); } if(x−>getNext() == nullptr) setLast(x); } Jak wyrugować jedną ze zmiennych lokalnych i w miarę możliwości uprościć kod
28 mar 20:22
Pytający: Po paru zmianach można tak uprościć (wymaga bezpośredniego dostępu do first, last i składowych węzła oraz potrzebny jest konstruktor węzła inicjalizujący wszystkie pola): template <class T> void LinkedList<T>::insert(T value, int(*compare)(const T&, const T&)) { Link<T> **addrNextPtr = &first; while (*addrNextPtr && compare(value, (*addrNextPtr)−>data) > 0) addrNextPtr = &(*addrNextPtr)−>next; Link<T> **addrPrevPtr = *addrNextPtr ? &(*addrNextPtr)−>previous : &last; *addrNextPtr = *addrPrevPtr = new Link<T>(value, *addrNextPtr, *addrPrevPtr); } Tu masz dopisaną tę funkcję z komentarzami: https://ideone.com/PbuWop (to zmodyfikowana wersja któregoś Twojego kodu, acz nie jestem pewny, czy ostatniego) Jak zwykle co nieco pozmieniałem, najistotniejsze linie: • 17 // deklaracja listy • 31, 150 // dodatkowy konstruktor • 40 // nowy przyjaciel (tego powyżej też nieco zmieniłem) • 131, 210 // insert • 508 // zmieniłem na wstawianie sortujące, w ramach testu Reszta to niezbyt istotne zmiany typu zmiana NULL na nullptr, czy konstruktory z listami inicjalizacyjnymi. Zmieniłem też przekazywanie argumentów do komparatora na przekazywanie przez stałą referencję zamiast przez wartość.
29 mar 17:49
Pytający: Poprawka (dość duża rozbieżność w linach jakoś rzuciła się w oczy): • 31, 49 // dodatkowy konstruktor
29 mar 17:51
Mariusz: [Warning] friend declaration 'std:: ostream& operator<<(std:: ostream&, Link<T>&)' declares a non−template function [−Wnon−template−friend] Wyskoczyło to ostrzeżenie Gdybym chciał zmieniać pozostałe funkcje to powywalać gettery i settery z tych funkcji i odwoływać się do adresów pól składowych klasy Wynika z tego że przydatność getterów i setterów jest dość ograniczona Gdyby chciał bawić się klasą zagnieżdzoną to przydałoby się wprowadzić iteratory, przeciążyć operator przypisania , napisać konstruktor kopiujący tylko czy nie będzie problemów z szablonami ? Za czasów Symfonii i Pasji Grębosza nie można było ich zagnieżdżać Z funkcji to może dopiszę insertBefore , przydałyby się takie jak SplitAfter , SplitBefore , Concat gdyby ktoś chciał się bawić np rekurencyjnym sortowaniem Usuwanie powtórzeń z posortowanej listy (tak właściwie wystarczyłoby wstawianie powtórzeń na koniec listy i zwracanie wskaźnika na ogon podlisty bez powtórzeń) mogłoby się przydać do algorytmu Grahama Jak przekształcić tę listę w listę cykliczną ? Niby następnik ogona to głowa a poprzednik głowy to ogon ale czy nie trzeba by było zmodyfikować funkcje tej listy
30 mar 00:44
Dziadek Mróz: Lista cykliczna na chłopski rozum: first −> el −> el −> ... −> el −> last −> first
30 mar 13:09
Dziadek Mróz: To dla jednokierunkowej, dla dwukierunkowej dla first idzie prev do last last <− first <− el <− ... <− el <− last first −> el −> ... −> el −> last −> first
30 mar 13:11
Pytający: Ano moja zmiana tamtego "przyjaciela" faktycznie nie do końca była sensowna. Była to zmiana typu "na szybko, działa, więc jest ok" (co mnie teraz właśnie najbardziej dziwi, to brak jakiegokolwiek ostrzeżenia u mnie, pewnie kwestia kompilatora). Tu masz ładnie opisane różne możliwe podejścia: https://stackoverflow.com/a/4661372 Znaczy miałeś w swoim kodzie to podejście "ekstrawertyczne". U mnie miało być to drugie podejście "introwertyczne" (to bez inliningu), jednak nie dopisałem potrzebnych deklaracji poprzedzających (u mnie przecież działało...), tu poprawione (linie 15, 16): https://ideone.com/dfYBgw Jeśli chcesz pozmieniać funkcje na wersje z podwójnym wskaźnikami, to wtedy należy odwoływać się do adresów pól składowych. Jeśli operujesz zwykłymi wskaźnikami to nie jest to niezbędne, wystarczą kopie, ale wtedy nie obejdzie się bez rozważania przypadków typu: if (warunek) head = ... else tmp_wezel−>next= ... Co do przydatności tych getterów i setterów: nie zawierają w sobie żadnej logiki (w sensie np. nie sprawdzają czy zapisywana wartość jest dozwolona, spełnia jakieś warunki (przykładowo jeśli miałbyś pole z jakimś tam indeksem, to taki setter mógłby się upewniać, że wartość należy do jakiegoś tam przedziału/zakresu)). Poza tym czy użytkownik powinien mieć dostęp do pól takich jak next, prev itp. i móc zmieniać ich wartości? Raczej nie, to są szczegóły implementacyjne, o których użytkownik nie musi nic wiedzieć i lepiej, żeby nic nie mógł tam namieszać. Znowuż odwołam się do listy z biblioteki standardowej: https://en.cppreference.com/w/cpp/container/list przykładowo metody front(), back() zwracają referencje do wartości (T& lub const T&), nie do żadnych węzłów. Poza tym masz masę innych metod (w tym operatorów) i one właśnie stanowią interfejs użytkownika. Do tego iteratory, a wtedy możesz używać np. różnych standardowych algorytmów (sortowania, porównywania leksykograficznego z własnym komparatorem, znajdowania wartości, zliczania wystąpień i wiele innych): https://en.cppreference.com/w/cpp/header/algorithm . Co do zagnieżdżania, węzły wcale nie muszą być szablonami, a i tak będą rozróżnialne. Przecież przykładowo LinkedList<int>::Link i LinkedList<double>::Link to różne typy. Zatem powinno chyba wystarczyć: template<class T> LinkedList { class Link {...} ... } A jakbyś jednak chciał, żeby na zewnątrz tej klasy można było węzły traktować jako typu Link<T>, to można użyć "alias template": https://ideone.com/LiCs2k https://en.cppreference.com/w/cpp/language/type_alias A przy zamianie na listę cykliczną niektóre funkcje na pewno musiałbyś nieco zmodyfikować, przykładowo bez zmian takie wyszukiwanie (find()) by Ci się zapętliło dla niepustej listy bez wyszukiwanej wartości (bo szuka dopóki węzeł jest różny od nullptr i wartość w nim jest różna od poszukiwanej).
31 mar 10:46
Mariusz: Używam gcc 6.3.0 , mam też ten pobrany z Code::Blocks IDE Bawiłem się jeszcze rekurencyjnym sortowaniem przez scalanie i oto co otrzymałem https://ideone.com/M2PEgW Ciekawe czy kod wymaga jakichś poprawek i czy można go jakoś uprościć
31 mar 18:12