Zadanie do sprawdzenia

0

Hej, przerabiam sobie książkę z Javy i zastanawiam się czy zrobiłem poprawnie zadanie(a dokładniej zadanie, na które składają się dwa zadania).
Jeśli komuś chciałby się rzucić okiem i powytykać błędy to będę wdzięczny, treści zadań:

  1. Zaimplementuj klasę Queue, nieograniczoną kolejkę ciągów znaków. Dodaj metodę add, która dodaje element na końcu oraz metodę remove usuwającą element z początku kolejki. Zapamiętuj elementy w postaci połączonej listy węzłów. Zaimplementuj Node jako klasę zagnieżdżoną. Czy powinna ona być klasą statyczną ?
  2. Dla kolejki z poprzedniego ćwiczenia utwórz iterator - obiekt, który zwraca po kolei elementy z kolejki. Zaimplementuj Iterator jako klasę zagnieżdżoną z metodami next i hasNext. Dodaj metodę iterator() w klasie Queue, która zwróci obiekt Queue.Iterator. Czy iterator powinien być statyczny?

Czy powinna ona(Node) być klasą statyczną ?
Czy iterator powinien być statyczny?
Moja odpowiedź: No raczej tak, skoro w treści ćwiczeń pisze, że ma być to klasa zagnieżdżona, to musi być static, bo bez static byłaby to klasa wewnętrzna, tak ?

A tutaj to co udało mi się napisać:

import java.util.ArrayList;
public class Queue {

    private ArrayList<Node> lista = new ArrayList<>();

    public void add(String s) {

        Node newNode = new Node();

        if(lista.size() == 0)
            newNode.previous = null;
        else {
            newNode.previous = lista.get(lista.size() - 1);
            newNode.previous.next = newNode;
        }

        newNode.next = null;
        newNode.text = s;
        lista.add(newNode);
    }

    public void remove() {

        if(lista.size() == 0)
            System.err.println("Operacja nie powiodła się.. Kolejka jest pusta.");
        else if(lista.size() == 1)
            lista.remove(0);
        else {
            lista.get(1).previous = null;
            lista.remove(0);
        }
    }

    public Iterator iterator() {

        Iterator newIterator = new Iterator();
        newIterator.iteratorList = lista;
        return newIterator;
    }

    public static class Iterator {

        private ArrayList<Node> iteratorList;
        private static int position = 0;

        public String next() {

            if(iteratorList.get(position).next != null) {
                position++;
                return iteratorList.get(position-1).text;
            }
            else
                return "Kolejka się skończyła";

        }

        public boolean hasNext() {

            if(iteratorList.get(position).next != null)
                return true;
            else
                return false;
        }
    }

    public static class Node {

        private Node previous;
        private Node next;
        private String text;

        public Node() {

        }

        public Node(Node previous, Node next, String text) {

            this.previous = previous;
            this.next = next;
            this.text = text;
        }
    }
}
0

Na pytania o statyczność spróbuj jednak odpowiedzieć bardziej naukowo, tak jak podszedłeś do reszty :)

Proponowałbym, żebyś do tego zadania dopisał testy JUnit. Nie ma programowania bez testów, więc tego nie unikniesz. Napiszesz sobie parę testów, które będą dowodziły poprawności w typowych scenariuszach. Wtedy ktoś na forum mógłby się pokusić o jakiś kontrtest, który wykłada Twoje rozwiązanie. Całość można by opublikować na githubie, wraz ze strukturą katalogów, gdyby ktoś chciał sobie to puścić.

Tak, z tym byłoby dość dużo pracy.

Tak na pierwszy rzut oka mam tylko jedną uwagę. Usuwanie pierwszego elementu z ArrayList jest nieekonomiczne. Sprowadza się do przepisania całej tablicy, a lepiej żeby działało to w tzw. złożoności stałej. Dlatego napisali "połączonej listy węzłów". Musisz te węzły przechowywać w pamięci w inny sposób. Idealne rozwiązanie w ogóle nie będzie miało tablicy wszystkich elementów. Więcej Ci nie powiem, bo spalę zadanie.

Połączona lista węzłow to LinkedList. Nie wiem, czy masz to sam zaimplementować, czy skorzystać z gotowca. Raczej zrób sam. Na takiej liście trudne operacje to usuwanie ze środka i wstawianie do środka listy. A tego nie musisz obsługiwać.

0

@jarekczek:

Proponowałbym, żebyś do tego zadania dopisał testy JUnit. Nie ma programowania bez testów, więc tego nie unikniesz. Napiszesz sobie parę testów, które będą dowodziły poprawności w typowych scenariuszach. Wtedy ktoś na forum mógłby się pokusić o jakiś kontrtest, który wykłada Twoje rozwiązanie. Całość można by opublikować na githubie, wraz ze strukturą katalogów, gdyby ktoś chciał sobie to puścić.

Serio? Wiesz jak trudne jest dla początkującego poza samym programowanie ogarnięcie idei testów, frameworka oraz fakt, że coś trzeba przetestować, ale nie wiem jak, ale tak radzą? Najpierw język, potem inne aspekty samego programowania. No i nie odpowiadasz na jego pytania :P

0

@jarekczek

Dzięki wielkie, testów jeszcze nigdy nie pisałem i myślę, że to dobra okazja, żeby zacząć je pisać. Postaram się wszystko na githuba wrzucić jutro, żeby było ładnie i schludnie.

Co do LinkedList to mam trochę wątpliwości czy powinienem tego używać, bo jestem dopiero na 100 stronie w książce(2 rozdział) i z kolekcji miałem omówione jedynie ArrayList, a to i tak tylko z grubsza przy okazji tematu z tablicami. Więc teoretycznie nie powinienem wiedzieć nic więcej niż tablice i ArrayList - w pewnym sensie też tak jest, ponieważ o innych kolekcjach mam wiedzę teoretyczną, a nie miałem okazji zastosować ich praktycznie w kodzie. Myślę, że właśnie cel tego zadania jest zapoznanie się z tym jak działa Queue, by później nie mieć problemu z ogarnięciem tych wszystkich kolekcji (dopiero w rozdziale 7 są kolekcje w tej książce).

Mam świadomość, że jest to nieekonomiczne z tym usuwaniem, aczkolwiek było to ostatnie zadanie z tego rozdziału, była 3 w nocy - tylko na to udało mi się wpaść, a co najważniejsze działało.

Mam również jedno pytanie, ponieważ moja metoda next() z Iteratora, zwraca obecną wartość, a następnie przechodzi na następną pozycję w liście(o ile taka istnieje) - czy tak właśnie powinno być ? Przykładowo mam 3 liczby w kolejce {1,2,3} i metoda zwróci 1, 2 - ale trójki już nie zwróci, ponieważ na tej wartości się zatrzymuje, bo nie może wyjść poza kolejkę. Czy wa takiej sytuacji, gdzie nie ma następnego elementu iterator powinien wskakiwać na pierwszą wartość i zwrócić ostatnią ?

0

@Burdzi0 Chyba masz rację. JUnit to za dużo na początek. Ale coś być musi. Więc niech będzie funkcja main, która pokazuje, że obiekt działa prawidłowo. JUnit to taki automat, który odhacza na zielono, gdy program działa dobrze. Zamiast tego można mieć jakiś output na konsoli. Zamiast automatu musimy obejrzeć ten output i stwierdzić sami - dobrze, o to chodziło. A mi chodziło o to, że Herbatek musiał sobie sam to sprawdzić i dobrze byłoby widzieć ten kod sprawdzający. To ułatwia ocenę.

Iterator musi zwrócić kolejno wszystkie elementy. Potem już nieważne, co się stanie. Grunt, żeby hasNext dawało false. Wtedy użytkownikowi biblioteki nie wolno uruchomić next.

Skoro LinkedList, jest dopiero w 7. rozdziale to nie możesz go użyć. No i dobrze :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1