package hjelpeklasser;
import java.util.*;
import java.io.*;
import java.net.URL;
import java.util.function.Consumer;
public final class Graf implements Iterable<String>
{
private static final class Node
{
private final String navn;
private final List<Node> kanter;
private byte innkanter = 0;
private boolean besøkt = false;
private Node forrige = null;
private Node(String navn)
{
this.navn = navn;
kanter = new LinkedList<>();
}
@Override
public String toString()
{
return navn;
}
public boolean equals(Object o)
{
if (o == this) return true;
if (o == null || getClass() != o.getClass()) return false;
return navn.equals(((Node)o).navn);
}
}
private final Map<String, Node> noder;
public Graf()
{
noder = new HashMap<>();
}
public boolean leggInnNode(String navn)
{
if (navn == null || navn.length() == 0)
throw new IllegalArgumentException("Noden må ha et navn!");
if (noder.get(navn) != null) return false;
return noder.put(navn, new Node(navn)) == null;
}
public boolean nodeFinnes(String navn)
{
return noder.get(navn) != null;
}
public Iterator<String> iterator()
{
return noder.keySet().iterator();
}
public String[] nodenavn()
{
return noder.keySet().toArray(new String[0]);
}
public void leggInnKant(String franode, String tilnode)
{
if (franode.equals(tilnode)) throw
new IllegalArgumentException(franode + " er lik " + tilnode + "!");
Node fra = noder.get(franode);
if (fra == null) throw new NoSuchElementException(franode + " er ukjent!");
Node til = noder.get(tilnode);
if (til == null) throw new NoSuchElementException(tilnode + " er ukjent!");
if(fra.kanter.contains(til)) throw
new IllegalArgumentException("Kanten finnes fra før!");
til.innkanter++;
fra.kanter.add(til);
}
public void leggInnKanter(String franode, String... tilnoder)
{
for (String tilnode : tilnoder) leggInnKant(franode, tilnode);
}
public String kanterFra(String node)
{
Node fra = noder.get(node);
if (fra == null) return null;
return fra.kanter.toString();
}
public Graf(String url) throws IOException
{
this();
try (BufferedReader inn = new BufferedReader
(new InputStreamReader((new URL(url)).openStream())))
{
String linje;
while ((linje = inn.readLine()) != null)
{
String[] navn = linje.split(" ");
leggInnNode(navn[0]);
for (int i = 1; i < navn.length; i++)
{
leggInnNode(navn[i]);
leggInnKant(navn[0], navn[i]);
}
}
}
}
public int antallNoder()
{
return noder.size();
}
public boolean erIsolert(String nodenavn)
{
Node p = noder.get(nodenavn);
if (p == null) throw new NoSuchElementException(nodenavn + " er ukjent!");
return p.kanter.size() == 0 && p.innkanter == 0;
}
public boolean erKant(String franode, String tilnode)
{
Node fra = noder.get(franode);
if (fra == null) throw new IllegalArgumentException(franode + " er ukjent!");
Node til = noder.get(tilnode);
if (til == null) throw new IllegalArgumentException(tilnode + " er ukjent!");
for (Node n : fra.kanter) if (n.navn.equals(tilnode)) return true;
return false;
}
public int grad(String nodenavn)
{
Node p = noder.get(nodenavn);
if (p == null) throw new NoSuchElementException(nodenavn + " er ukjent!");
return p.kanter.size();
}
public void skrivGraf(String filnavn) throws IOException
{
PrintWriter ut = new PrintWriter(filnavn);
for (String nodenavn : this)
{
ut.print(nodenavn);
Node node = noder.get(nodenavn);
for (Node til : node.kanter) ut.print(" " + til.navn);
ut.println();
}
ut.close();
}
public String[] kantTabellFra(String node)
{
Node fra = noder.get(node);
if (fra == null) return null;
String[] kanttabell = new String[fra.kanter.size()];
int i = 0;
for (Node p : fra.kanter) kanttabell[i++] = p.navn;
return kanttabell;
}
public String kanterTil(String nodenavn)
{
if (!nodeFinnes(nodenavn)) return "[]";
StringJoiner sj = new StringJoiner(", ", "[", "]");
for (String navn : this)
{
Node p = noder.get(navn);
for (Node q : p.kanter) if (q.navn.equals(nodenavn)) sj.add(navn);
}
return sj.toString();
}
public String[] kantTabellTil(String nodenavn)
{
if (!nodeFinnes(nodenavn)) return new String[0];
ArrayList<String> liste = new ArrayList<>();
for (String navn : this)
{
Node p = noder.get(navn);
for (Node q : p.kanter) if (q.navn.equals(nodenavn)) liste.add(navn);
}
return liste.toArray(new String[0]);
}
public void nullstill()
{
for (Node p : noder.values())
{
p.besøkt = false; p.forrige = null;
}
}
private void dybdeFørstPre(Node p, Consumer<String> oppgave)
{
p.besøkt = true;
oppgave.accept(p.navn);
for (Node q : p.kanter)
{
if (!q.besøkt) dybdeFørstPre(q, oppgave);
}
}
public void dybdeFørstPretraversering(String startnode, Consumer<String> oppgave)
{
Node p = noder.get(startnode);
if (p == null) throw new IllegalArgumentException(startnode + " er ukjent!");
dybdeFørstPre(p, oppgave);
}
public void breddeFørstTraversering(String startnode, Consumer<String> oppgave)
{
Node p = noder.get(startnode);
if (p == null) throw new IllegalArgumentException(startnode + " er ukjent!");
Queue<Node> kø = new ArrayDeque<>();
p.besøkt = true;
kø.offer(p);
while (!kø.isEmpty())
{
p = kø.poll();
oppgave.accept(p.navn);
for (Node q : p.kanter)
{
if (!q.besøkt)
{
q.besøkt = true;
kø.offer(q);
}
}
}
}
public void kortestVeiFra(String node)
{
Node p = noder.get(node);
if (p == null) throw new IllegalArgumentException(node + " er ukjent!");
Queue<Node> kø = new ArrayDeque<>();
p.besøkt = true;
kø.offer(p);
while (!kø.isEmpty())
{
p = kø.poll();
for (Node q : p.kanter)
{
if (!q.besøkt)
{
q.besøkt = true;
q.forrige = p;
kø.offer(q);
}
}
}
}
public String veiTil(String node)
{
Node p = noder.get(node);
if (p == null) throw new IllegalArgumentException(node + " er ukjent!");
if (p.forrige == null) return "[]";
Deque<String> stakk = new ArrayDeque<>();
while (p != null)
{
stakk.push(p.navn);
p = p.forrige;
}
return stakk.toString();
}
}