package hjelpeklasser;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.StringJoiner;
public class BinTre<T> implements Iterable<T>
{
private static final class Node<T>
{
private T verdi;
private Node<T> venstre;
private Node<T> høyre;
private Node(T verdi, Node<T> v, Node<T> h)
{
this.verdi = verdi;
venstre = v;
høyre = h;
}
private Node(T verdi)
{
this.verdi = verdi;
}
}
private Node<T> rot;
private int antall;
public BinTre()
{
rot = null;
antall = 0;
}
public BinTre(int[] posisjon, T[] verdi)
{
if (posisjon.length > verdi.length) throw new
IllegalArgumentException("Verditabellen har for få elementer!");
for (int i = 0; i < posisjon.length; i++)
{
leggInn(posisjon[i],verdi[i]);
}
}
public BinTre(final BinTre<T> tre)
{
rot = kopi(tre.rot);
antall = tre.antall;
}
private static <T> Node<T> kopi(Node<T> p)
{
if (p == null) return null;
return new Node<>(p.verdi,kopi(p.venstre),kopi(p.høyre));
}
public final void leggInn(int k, T verdi)
{
if (k < 1) throw new
IllegalArgumentException("Posisjon k(" + k + ") < 1!");
Node<T> p = rot, q = null;
int n = Integer.highestOneBit(k >> 1);
while (p != null && n > 0)
{
q = p;
p = (n & k) == 0 ? p.venstre : p.høyre;
n >>= 1;
}
if (n > 0) throw new
IllegalArgumentException("Posisjon k(" + k + ") mangler forelder!");
else if (p != null) throw new
IllegalArgumentException("Posisjon k(" + k + ") finnes fra før!");
p = new Node<>(verdi);
if (q == null) rot = p;
else if ((k & 1) == 0)
q.venstre = p;
else
q.høyre = p;
antall++;
}
public int antall()
{
return antall;
}
public boolean tom()
{
return antall == 0;
}
private Node<T> finnNode(int k)
{
if (k < 1) return null;
Node<T> p = rot;
int n = Integer.highestOneBit(k >> 1);
for (; p != null && n > 0; n >>= 1)
{
p = (k & n) == 0 ? p.venstre : p.høyre;
}
return p;
}
public boolean finnes(int k)
{
return finnNode(k) != null;
}
public T hent(int k)
{
Node<T> p = finnNode(k);
if (p == null) throw new
IllegalArgumentException("Posisjon k(" + k + ") er ukjent!");
return p.verdi;
}
public T oppdater(int k, T nyverdi)
{
Node<T> p = finnNode(k);
if (p == null) throw new
IllegalArgumentException("Posisjon k(" + k + ") er ukjent!");
T gammelverdi = p.verdi;
p.verdi = nyverdi;
return gammelverdi;
}
private static <T> boolean inneholder(Node<T> p, T verdi)
{
if (p == null) return false;
return verdi.equals(p.verdi) || inneholder(p.venstre,verdi)
|| inneholder(p.høyre,verdi);
}
public boolean inneholder(T verdi)
{
return inneholder(rot,verdi);
}
private static <T> int posisjon(Node<T> p, int k, T verdi)
{
if (p == null) return -1;
if (verdi.equals(p.verdi)) return k;
int i = posisjon(p.venstre,2*k,verdi);
if (i > 0) return i;
return posisjon(p.høyre,2*k+1,verdi);
}
public int posisjon(T verdi)
{
return posisjon(rot,1,verdi);
}
public T fjern(int k)
{
if (k < 1) throw new
IllegalArgumentException("Posisjon k(" + k + ") < 1!");
Node<T> p = rot, q = null;
int n = Integer.highestOneBit(k >> 1);
while (p != null && n > 0)
{
q = p;
p = (n & k) == 0 ? p.venstre : p.høyre;
n >>= 1;
}
if (p == null) throw new
IllegalArgumentException("Posisjon k(" + k + ") er utenfor treet!");
if (p.venstre != null || p.høyre != null) throw new
IllegalArgumentException("Posisjon k(" + k + ") er ingen bladnode!");
if (p == rot) rot = null;
else if (p == q.venstre) q.venstre = null;
else q.høyre = null;
antall--;
return p.verdi;
}
public void nullstill()
{
if (!tom()) nullstill(rot);
rot = null; antall = 0;
}
private void nullstill(Node<T> p)
{
if (p.venstre != null)
{
nullstill(p.venstre);
p.venstre = null;
}
if (p.høyre != null)
{
nullstill(p.høyre);
p.høyre = null;
}
p.verdi = null;
}
public void nivåorden(Oppgave<? super T> oppgave)
{
if (rot == null) return;
Kø<Node<T>> kø = new TabellKø<>();
kø.leggInn(rot);
while (!kø.tom())
{
Node<T> p = kø.taUt();
oppgave.utførOppgave(p.verdi);
if (p.venstre != null) kø.leggInn(p.venstre);
if (p.høyre != null) kø.leggInn(p.høyre);
}
}
public String toNivåString()
{
StringJoiner s = new StringJoiner(", ", "[", "]");
if (!tom()) nivåorden(x -> s.add(x.toString()));
return s.toString();
}
public T førstPreorden()
{
if (tom()) throw new NoSuchElementException("Treet er tomt!");
return rot.verdi;
}
private static <T> void preorden(Node<T> p, Oppgave<? super T> oppgave)
{
oppgave.utførOppgave(p.verdi);
if (p.venstre != null) preorden(p.venstre,oppgave);
if (p.høyre != null) preorden(p.høyre,oppgave);
}
public void preorden(Oppgave<? super T> oppgave)
{
if (rot != null) preorden(rot,oppgave);
}
public String toPreString()
{
StringJoiner s = new StringJoiner(", ", "[", "]");
if (!tom()) preorden(x -> s.add(x.toString()));
return s.toString();
}
public void preorden2(Oppgave<? super T> oppgave)
{
if (tom()) return;
Stakk<Node<T>> stakk = new TabellStakk<>();
Node<T> p = rot;
while (true)
{
oppgave.utførOppgave(p.verdi);
if (p.venstre != null)
{
if (p.høyre != null) stakk.leggInn(p.høyre);
p = p.venstre;
}
else if (p.høyre != null)
{
p = p.høyre;
}
else if (!stakk.tom())
{
p = stakk.taUt();
}
else
break;
}
}
public T førstInorden()
{
if (tom()) throw new NoSuchElementException("Treet er tomt!");
Node<T> p = rot;
while (p.venstre != null) p = p.venstre;
return p.verdi;
}
private static <T> void inorden(Node<T> p, Oppgave<? super T> oppgave)
{
if (p.venstre != null) inorden(p.venstre,oppgave);
oppgave.utførOppgave(p.verdi);
if (p.høyre != null) inorden(p.høyre,oppgave);
}
public void inorden(Oppgave <? super T> oppgave)
{
if (rot != null) inorden(rot,oppgave);
}
@Override
public String toString()
{
StringJoiner s = new StringJoiner(", ", "[", "]");
if (!tom()) inorden(x -> s.add(x.toString()));
return s.toString();
}
public void inorden2(Oppgave<? super T> oppgave)
{
if (tom()) return;
Stakk<Node<T>> stakk = new TabellStakk<>();
Node<T> p = rot;
for ( ; p.venstre != null; p = p.venstre)
{
stakk.leggInn(p);
}
while (true)
{
oppgave.utførOppgave(p.verdi);
if (p.høyre != null)
{
for (p = p.høyre; p.venstre != null; p = p.venstre)
{
stakk.leggInn(p);
}
}
else if (!stakk.tom())
{
p = stakk.taUt();
}
else break;
}
}
public T førstPostorden()
{
if (tom()) throw new NoSuchElementException("Treet er tomt!");
Node<T> p = rot;
while (true)
{
if (p.venstre != null) p = p.venstre;
else if (p.høyre != null) p = p.høyre;
else return p.verdi;
}
}
private static <T> void postorden(Node<T> p, Oppgave<? super T> oppgave)
{
if (p.venstre != null) postorden(p.venstre,oppgave);
if (p.høyre != null) postorden(p.høyre,oppgave);
oppgave.utførOppgave(p.verdi);
}
public void postorden(Oppgave<? super T> oppgave)
{
if (rot != null) postorden(rot,oppgave);
}
public String toPostString()
{
StringJoiner s = new StringJoiner(", ", "[", "]");
if (!tom()) postorden(x -> s.add(x.toString()));
return s.toString();
}
public void postorden2(Oppgave<? super T> oppgave)
{
if (tom()) return;
Stakk<Node<T>> stakk = new TabellStakk<>();
Node<T> p = rot;
while (true)
{
if (p.venstre != null)
{
stakk.leggInn(p);
p = p.venstre;
}
else if (p.høyre != null)
{
stakk.leggInn(p);
p = p.høyre;
}
else break;
}
oppgave.utførOppgave(p.verdi);
while (true)
{
if (stakk.tom()) return;
Node<T> f = stakk.taUt();
if (f.høyre == null || p == f.høyre)
{
p = f;
}
else
{
stakk.leggInn(f);
p = f.høyre;
while (true)
{
if (p.venstre != null)
{
stakk.leggInn(p);
p = p.venstre;
}
else if (p.høyre != null)
{
stakk.leggInn(p);
p = p.høyre;
}
else
break;
}
}
oppgave.utførOppgave(p.verdi);
}
}
@Override
public Iterator<T> iterator()
{
return new InordenIterator();
}
private class InordenIterator implements Iterator<T>
{
private final Stakk<Node<T>> stakk = new TabellStakk<>();
private Node<T> p = rot;
private Node<T> først(Node<T> q)
{
while (q.venstre != null)
{
stakk.leggInn(q);
q = q.venstre;
}
return q;
}
public InordenIterator()
{
if (tom()) return;
p = først(rot);
}
@Override
public T next()
{
if (!hasNext()) throw new NoSuchElementException("Ingen verdier!");
T verdi = p.verdi;
if (p.høyre != null) p = først(p.høyre);
else if (!stakk.tom()) p = stakk.taUt();
else p = null;
return verdi;
}
@Override
public boolean hasNext()
{
return p != null;
}
}
public Iterator<T> omvendtiterator()
{
return new OmvendtInordenIterator();
}
private class OmvendtInordenIterator implements Iterator<T>
{
private final Stakk<Node<T>> stakk = new TabellStakk<>();
private Node<T> p = rot;
private Node<T> sist(Node<T> q)
{
while (q.høyre != null)
{
stakk.leggInn(q);
q = q.høyre;
}
return q;
}
public OmvendtInordenIterator()
{
if (tom()) return;
p = sist(rot);
}
@Override
public T next()
{
if (!hasNext()) throw new NoSuchElementException("Ingen verdier!");
T verdi = p.verdi;
if (p.venstre != null) p = sist(p.venstre);
else if (!stakk.tom()) p = stakk.taUt();
else p = null;
return verdi;
}
@Override
public boolean hasNext()
{
return p != null;
}
}
public Iterator<T> preiterator()
{
return new PreordenIterator();
}
private class PreordenIterator implements Iterator<T>
{
private final Stakk<Node<T>> stakk = new TabellStakk<>();
private Node<T> p = rot;
@Override
public boolean hasNext()
{
return p != null;
}
@Override
public T next()
{
if (!hasNext()) throw new NoSuchElementException("Ingen verdier!");
T tempverdi = p.verdi;
if (p.venstre != null)
{
if (p.høyre != null) stakk.leggInn(p.høyre);
p = p.venstre;
}
else if (p.høyre != null) p = p.høyre;
else if (!stakk.tom()) p = stakk.taUt();
else p = null;
return tempverdi;
}
}
public Iterator<T> postiterator()
{
return new PostordenIterator();
}
private class PostordenIterator implements Iterator<T>
{
private final Stakk<Node<T>> stakk = new TabellStakk<>();
private Node<T> p;
private Node<T> postførst(Node<T> q)
{
while (true)
{
if (q.venstre != null)
{
stakk.leggInn(q);
q = q.venstre;
}
else if (q.høyre != null)
{
stakk.leggInn(q);
q = q.høyre;
}
else
return q;
}
}
private PostordenIterator()
{
if (tom()) return;
p = postførst(rot);
}
@Override
public boolean hasNext()
{
return p != null;
}
@Override
public T next()
{
if (!hasNext()) throw new NoSuchElementException("Ingen verdier!");
T tempverdi = p.verdi;
if (stakk.tom()) p = null;
else
{
Node<T> f = stakk.kikk();
if (f.høyre == null || p == f.høyre) p = stakk.taUt();
else p = postførst(f.høyre);
}
return tempverdi;
}
}
public Iterator<T> nivåiterator()
{
return new NivåordenIterator();
}
private class NivåordenIterator implements Iterator<T>
{
private Kø<Node<T>> kø = new TabellKø<>();
private Node<T> p = null;
private NivåordenIterator()
{
if (rot == null) return;
p = rot;
}
@Override
public boolean hasNext()
{
return p != null;
}
@Override
public T next()
{
if (!hasNext()) throw new NoSuchElementException("Ingen verdier!");
T temp = p.verdi;
if (p.venstre != null) kø.leggInn(p.venstre);
if (p.høyre != null) kø.leggInn(p.høyre);
p = kø.tom() ? null : kø.taUt();
return temp;
}
}
private static int høyde(Node<?> p)
{
if (p == null) return -1;
return 1 + Math.max(høyde(p.venstre), høyde(p.høyre));
}
public int høyde()
{
return høyde(rot);
}
private static boolean isomorf(Node<?> p, Node<?> q)
{
if (p == null && q == null) return true;
if (p == null ^ q == null) return false;
return isomorf(p.venstre,q.venstre) && isomorf(p.høyre,q.høyre);
}
public boolean isomorf(BinTre<?> tre)
{
if (this == tre) return true;
if (antall != tre.antall) return false;
return isomorf(rot,tre.rot);
}
private static boolean equals(Node<?> p, Node<?> q)
{
if (p == null && q == null) return true;
if (p == null ^ q == null) return false;
return p.verdi.equals(q.verdi) &&
equals(p.venstre, q.venstre) && equals(p.høyre, q.høyre);
}
@Override
public boolean equals(Object objekt)
{
if (this == objekt) return true;
if (!(objekt instanceof BinTre)) return false;
@SuppressWarnings("unchecked")
BinTre<T> tre = (BinTre<T>)objekt;
if (antall != tre.antall) return false;
return equals(rot,tre.rot);
}
}