Iterable Ciąg Colltaza

0

Witam, mam takie zadanie

Ciąg Collatza (znany też jako „hailstone sequence” lub ciąg Ulama) to ciąg liczb naturalnych rozpoczynający się od dowolnej liczby a0, którego kolejne wyrazy obliczane są według zasady

Istnieje hipoteza, że taki ciąg zawsze dojdzie do liczby 1 (i potem będzie już periodyczny: 1,4,2,1,4,2,1,4,...). Została ona sprawdzona aż do astronomicznie wielkich liczb, ale do tej pory nie udało się jej udowodnić.
Na przykład, jeśli rozpoczniemy od liczby 5, otrzymamy ciąg [5,16,8,4,2,1,...], a rozpoczynając od 7 otrzymamy już ciąg dłuższy: [7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1,...].
Zadanie polega na stworzeniu klasy Hailstone, której obiekty reprezentują pojedynczy ciąg Collatza. Konstruktor pobiera liczbę startową (a0), o której można założyć, że zawsze będzie większa od 1. Sam obiekt jest iterowalny, czyli implementuje interfejs Iterable i w każdej iteracji zwraca kolejne elementy ciągu, poczynając od wartości startowej. Iteracja powinna kończyć się po zwróceniu, jako ostatniego elementu, liczby 1.
Implementacja klasy Hailstone

może zawierać statyczną klasę wewnętrzną, jeśli będzie potrzebna;
nie może tworzyć żadnych tablic, ani używać żadnych kolekcji z bibliotek Jawy.
Utworzoną klasę przetestuj za pomocą następującego programu:

public class Main {
    public static void main(String... args) {
        int ini = 77031, count = -1, maxel = 0;
        Hailstone hailstone = new Hailstone(ini);
        for (int h : hailstone) {
            if (h > maxel) maxel = h;
            ++count;
        }
        System.out.println(ini + " " + count + " " + maxel);
    }
}

Powinien on wypisać, w jednej linii, oddzielone spacjami, trzy liczby: wartość startową (ini; w tym przykładzie 77031), ilość kroków wykonanych do osiągnięcia jedynki (count), oraz największy wyraz tego ciągu (maxel). Na przykład dla wartości startowej 10, ciąg, aż do uzyskania jedynki, zawierałby elementy [10 5 16 8 4 2 1], a zatem trzy liczby, które wtedy wypisałby program miałyby wartości 10 6 16.

import java.util.Iterator;

public class Hailstone<E> implements Iterable{
	public int a;
	public Hailstone(int ini) {
		this.a = ini;
	}
	public int doHail(Integer number){
	    this.a = number;
	        if(a % 2 == 0){
	            a /= 2;
	            return a;
	        }
	        else if(a %2 != 0){
	            a = 3*a+1;
	            return a;
	        }
			
	}
	
	public Iterator<E> iterator() {
	    return this.doHail(a).iterator(); //
	}
}

Wyskakuje błąd Cannot invoke iterator() on the primitive type int. Ktoś może mi pomóc?

0

zdaje mi się, że Integer, nie zostanie zrzutowany na int. Wygląda dobrze, ale jakbyś public int doHail zmienił na public Integer doHail ? Spróbuj, ja nie wiem

0

Krok pierwszy, to wycieczka do dokumentacji interfejsu Iterator

Mamy tam kilka metod, ale nas interesują dwie next i hasNext. Sztuka polega na napisaniu takiej implementacji tego interfejsu by:

  • Metoda hasNext zwracała false gdy ostatnio zwrócony element równy był 1.
  • Metoda next wyliczała wartość kolejnego elementu oraz dokonywała odpowiednich operacji, potrzebnych do określenia czy to element maksymalny, zapamiętania liczby kroków itd.

IMO punkt pierwszy można zrobić tak:

class HailstoneIterator implements Iterator<Long>{
     private int last;
     
     public boolean hasNext(){return last != 1;}
}

Reszta to twoje zadanie.

0

Utknąłem, nie wiem co napisał w zwracaniu w metodzie next()

package zad1;

import java.util.Iterator;

public class Hailstone implements Iterator<Hailstone>, Iterable<Hailstone> {
	
	
	public int a;

	public Hailstone(int ini) {
		this.a= ini;
	}

	@Override
	public boolean hasNext() {
		if(a !=1){
			return true;
		}
		return false;
	}

	@Override
	public Hailstone next() {
		 
         if(a % 2 == 0){
             a /= 2;
             return this;
         }
         else if(a %2 != 0){
             a = 3*a+1;
             return this;
         }
		return null;
	}

	@Override
	public Iterator<Hailstone> iterator() {
		
		return this;
	}

}

wiem że nie jestem geniuszem, ale to co widać już napisałem sam, :)

0

Ok zrobiłem, dzięki za naprowadzenie!

package zad1;

import java.util.Iterator;

public class Hailstone implements Iterator<Integer>, Iterable<Integer> {
	
	
	public int a;
	private int last = 0;

	public Hailstone(int ini) {
		this.a= ini;
	}

	@Override
	public boolean hasNext() {
		if(a !=1){
			
			return true;
		}else if(a==1){
			a++;
			last++;
			if(last ==1){
				return true;
			}
		}
		return false;
	}

	@Override
	public Integer next() {
		 
         if(a % 2 == 0){
             a /= 2;
             return a;
         }
         else if(a %2 != 0){
             a = 3*a+1;
             return  a;
         }
		return null;
	}

	@Override
	public Iterator<Integer> iterator() {
		
		return this;
	}

}

0
  1. poprawiłem moją wersję hasNext. Teraz jest OK.
  2. Jak napisać next? W drugiej wersji napisałeś prawie wszystko co trzeba. Jednak do hasNext niepotrzebnie przeniosłeś logikę związana z inkrementacją liczby kroków:
private Integer last; 
private Integer numberOfSteps;

@Override
public Integer next() {
	if (last % 2 == 0) return updateState(last / 2);
	else return updateState(last * 3 + 1);
}

private Integer updateState(Integer newState) {
	numberOfSteps++;
	return last = newState;
}

połącz to z poprzednim kodem i będzie OK.

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