package hjelpeklasser;
import java.util.*;
import java.io.*;
import java.net.URL;
import java.util.function.Consumer;
public final class MGraf implements Iterable<String>
{
private boolean[][] graf;
private int antall;
private String[] navn;
private String[] snavn;
private int[] indeks;
private int[] forrige;
public MGraf(int dimensjon)
{
graf = new boolean[dimensjon][dimensjon];
antall = 0;
navn = new String[dimensjon];
snavn = new String[dimensjon];
indeks = new int[dimensjon];
}
public MGraf()
{
this(10);
}
public int antallNoder()
{
return antall;
}
public int dimensjon()
{
return graf.length;
}
public String[] nodenavn()
{
return Arrays.copyOf(snavn, antall);
}
private int finn(String nodenavn)
{
return Arrays.binarySearch(snavn, 0, antall, nodenavn);
}
public boolean nodeFinnes(String nodenavn)
{
return finn(nodenavn) >= 0;
}
private void utvid()
{
int nydimensjon = graf.length == 0 ? 1 : 2*graf.length;
navn = Arrays.copyOf(navn, nydimensjon);
snavn = Arrays.copyOf(snavn, nydimensjon);
indeks = Arrays.copyOf(indeks, nydimensjon);
boolean[][] gammelgraf = graf;
graf = new boolean[nydimensjon][nydimensjon];
for (int i = 0; i < antall; i++)
{
System.arraycopy(gammelgraf[i], 0, graf[i], 0, antall);
}
}
public boolean leggInnNode(String nodenavn)
{
if (navn == null || nodenavn.length() == 0)
throw new IllegalArgumentException("Noden må ha et navn!");
int rad = finn(nodenavn);
if (rad >= 0) return false;
if (antall >= graf.length) utvid();
rad = -(rad + 1);
for (int i = antall; i > rad; i--)
{
snavn[i] = snavn[i - 1];
indeks[i] = indeks[i - 1];
}
snavn[rad] = nodenavn;
navn[antall] = nodenavn;
indeks[rad] = antall;
antall++;
return true;
}
public void leggInnKant(String franode, String tilnode)
{
if (franode.equals(tilnode)) throw
new IllegalArgumentException(franode + " er lik " + tilnode + "!");
int i = finn(franode);
if (i < 0) throw new NoSuchElementException(franode + " er ukjent!");
int j = finn(tilnode);
if (j < 0) throw new NoSuchElementException(tilnode + " er ukjent!");
int rad = indeks[i];
int kolonne = indeks[j];
if (graf[rad][kolonne]) throw
new IllegalArgumentException("Kanten finnes fra før!");
graf[rad][kolonne] = true;
}
public void leggInnKanter(String franode, String... tilnoder)
{
for (String tilnode : tilnoder) leggInnKant(franode, tilnode);
}
public MGraf(String url) throws IOException
{
this();
BufferedReader inn = new BufferedReader
(new InputStreamReader((new URL(url)).openStream()));
String linje;
while ((linje = inn.readLine()) != null)
{
String[] nodenavn = linje.split(" ");
leggInnNode(nodenavn[0]);
for (int i = 1; i < nodenavn.length; i++)
{
leggInnNode(nodenavn[i]);
leggInnKant(nodenavn[0], nodenavn[i]);
}
}
inn.close();
}
public String kanterFra(String nodenavn)
{
int i = finn(nodenavn);
if (i < 0) return null;
int rad = indeks[i];
StringJoiner sj = new StringJoiner(", ", "[", "]");
for (int kolonne = 0; kolonne < antall; kolonne++)
if (graf[rad][kolonne] == true) sj.add(navn[kolonne]);
return sj.toString();
}
private class MGrafIterator implements Iterator<String>
{
private int denne = 0;
public boolean hasNext()
{
return denne < antall;
}
public String next()
{
if (!hasNext())
throw new NoSuchElementException("Tomt eller ingen verdier igjen!");
return snavn[denne++];
}
}
public Iterator<String> iterator()
{
return new MGrafIterator();
}
public void skrivGraf(String filnavn) throws IOException
{
PrintWriter ut = new PrintWriter(filnavn);
for (int i = 0; i < antall; i++)
{
ut.print(snavn[i]);
int rad = indeks[i];
for (int kolonne = 0; kolonne < antall; kolonne++)
{
if (graf[rad][kolonne]) ut.print(" " + navn[kolonne]);
}
ut.println();
}
ut.close();
}
public boolean erIsolert(String nodenavn)
{
int is = finn(nodenavn);
if (is < 0) throw new NoSuchElementException(nodenavn + " er ukjent!");
int k = indeks[is];
for (int i = 0; i < antall; i++) if (graf[k][i]) return false;
for (int j = 0; j < antall; j++) if (graf[j][k]) return false;
return true;
}
public boolean erKant(String franode, String tilnode)
{
int i = finn(franode);
if (i < 0) throw new IllegalArgumentException(franode + " er ukjent!");
int j = finn(tilnode);
if (j < 0) throw new IllegalArgumentException(franode + " er ukjent!");
return graf[indeks[i]][indeks[j]];
}
public int grad(String nodenavn)
{
int i = finn(nodenavn);
if (i < 0) throw new IllegalArgumentException(nodenavn + " er ukjent!");
int rad = indeks[i];
int grad = 0;
for (boolean harKryss : graf[rad]) if (harKryss) grad++;
return grad;
}
public String[] kantTabellFra(String node)
{
int i = finn(node);
if (i < 0) throw new IllegalArgumentException(node + " er ukjent!");
int rad = indeks[i];
String[] tabell = new String[antall];
int ant = 0;
for (int kolonne = 0; kolonne < antall; kolonne++)
{
if (graf[rad][kolonne]) tabell[ant++] = navn[kolonne];
}
return Arrays.copyOf(tabell, ant);
}
public String kanterTil(String node)
{
int i = finn(node);
if (i < 0) throw new IllegalArgumentException(node + " er ukjent!");
int kolonne = indeks[i];
StringJoiner sj = new StringJoiner(", ", "[", "]");
for (int rad = 0; rad < antall; rad++)
{
if (graf[rad][kolonne]) sj.add(navn[rad]);
}
return sj.toString();
}
public String[] kantTabellTil(String node)
{
int i = finn(node);
if (i < 0) throw new IllegalArgumentException(node + " er ukjent!");
int kolonne = indeks[i];
String[] tabell = new String[antall];
int ant = 0;
for (int rad = 0; rad < antall; rad++)
{
if (graf[rad][kolonne]) tabell[ant++] = navn[rad];
}
return Arrays.copyOf(tabell, ant);
}
public void dybdeFørstPretraversering(String startnode, Consumer<String> oppgave)
{
int is = finn(startnode);
if (is < 0) throw new IllegalArgumentException(startnode + " er ukjent!");
int i = indeks[is];
boolean besøkt[] = new boolean[antall];
dybdeFørstPre(i, besøkt, oppgave);
}
private void
dybdeFørstPre(int i, boolean[] besøkt, Consumer<String> oppgave)
{
besøkt[i] = true;
oppgave.accept(navn[i]);
for (int j = 0; j < antall; j++)
{
if (graf[i][j] && !besøkt[j])
dybdeFørstPre(j, besøkt, oppgave);
}
}
public void breddeFørstTraversering(String startnode, Consumer<String> oppgave)
{
int is = finn(startnode);
if (is < 0) throw new IllegalArgumentException(startnode + " er ukjent!");
int i = indeks[is];
boolean[] besøkt = new boolean[antall];
Queue<Integer> kø = new ArrayDeque<>();
besøkt[i] = true;
kø.offer(i);
while (!kø.isEmpty())
{
i = kø.poll();
oppgave.accept(navn[i]);
for (int j = 0; j < antall; j++)
{
if (graf[i][j] && !besøkt[j])
{
besøkt[j] = true;
kø.offer(j);
}
}
}
}
}