Abi-NRW Klassen zum Testen eingefügt
Die Klassen werden von der Qualitäts- und UnterstützungsAgentur - Landesinstitut für Schule herausgegeben.
This commit is contained in:
parent
bd718ba27d
commit
13cad69e1d
|
@ -0,0 +1,262 @@
|
|||
package schule.ngb.zm.util.abi;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Generische Klasse BinarySearchTree<ContentType>
|
||||
* </p>
|
||||
* <p>
|
||||
* Mithilfe der generischen Klasse BinarySearchTree koennen beliebig viele
|
||||
* Objekte in einem Binaerbaum (binaerer Suchbaum) entsprechend einer
|
||||
* Ordnungsrelation verwaltet werden. <br />
|
||||
* Ein Objekt der Klasse stellt entweder einen leeren binaeren Suchbaum dar oder
|
||||
* verwaltet ein Inhaltsobjekt sowie einen linken und einen rechten Teilbaum,
|
||||
* die ebenfalls Objekte der Klasse BinarySearchTree sind.<br />
|
||||
* Die Klasse der Objekte, die in dem Suchbaum verwaltet werden sollen, muss
|
||||
* das generische Interface ComparableContent implementieren. Dabei muss durch
|
||||
* Ueberschreiben der drei Vergleichsmethoden isLess, isEqual, isGreater (s.
|
||||
* Dokumentation des Interfaces) eine eindeutige Ordnungsrelation festgelegt
|
||||
* sein. <br />
|
||||
* Alle Objekte im linken Teilbaum sind kleiner als das Inhaltsobjekt des
|
||||
* binaeren Suchbaums. Alle Objekte im rechten Teilbaum sind groesser als das
|
||||
* Inhaltsobjekt des binaeren Suchbaums. Diese Bedingung gilt (rekursiv) auch in
|
||||
* beiden Teilbaeumen. <br />
|
||||
* Hinweis: In dieser Version wird die Klasse BinaryTree nicht benutzt.
|
||||
* </p>
|
||||
*
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version Generisch_03 2017-11-28
|
||||
*/
|
||||
public class BinarySearchTree<ContentType extends ComparableContent<ContentType>> {
|
||||
|
||||
/* --------- Anfang der privaten inneren Klasse -------------- */
|
||||
|
||||
/**
|
||||
* Durch diese innere Klasse kann man dafuer sorgen, dass ein leerer Baum
|
||||
* null ist, ein nicht-leerer Baum jedoch immer eine nicht-null-Wurzel sowie
|
||||
* nicht-null-Teilbaeume hat.
|
||||
*/
|
||||
private class BSTNode<CT extends ComparableContent<CT>> {
|
||||
|
||||
private CT content;
|
||||
private BinarySearchTree<CT> left, right;
|
||||
|
||||
public BSTNode(CT pContent) {
|
||||
// Der Knoten hat einen linken und rechten Teilbaum, die
|
||||
// beide von null verschieden sind. Also hat ein Blatt immer zwei
|
||||
// leere Teilbaeume unter sich.
|
||||
this.content = pContent;
|
||||
left = new BinarySearchTree<CT>();
|
||||
right = new BinarySearchTree<CT>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ----------- Ende der privaten inneren Klasse -------------- */
|
||||
|
||||
private BSTNode<ContentType> node;
|
||||
|
||||
/**
|
||||
* Der Konstruktor erzeugt einen leeren Suchbaum.
|
||||
*/
|
||||
public BinarySearchTree() {
|
||||
this.node = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Anfrage liefert den Wahrheitswert true, wenn der Suchbaum leer ist,
|
||||
* sonst liefert sie den Wert false.
|
||||
*
|
||||
* @return true, wenn der binaere Suchbaum leer ist, sonst false
|
||||
*
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return this.node == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls der Parameter null ist, geschieht nichts.<br />
|
||||
* Falls ein bezueglich der verwendeten Vergleichsmethode isEqual mit
|
||||
* pContent uebereinstimmendes Objekt im geordneten binaeren Suchbau
|
||||
* enthalten ist, passiert nichts. <br />
|
||||
* Achtung: hier wird davon ausgegangen, dass isEqual genau dann true
|
||||
* liefert, wenn isLess und isGreater false liefern. <br />
|
||||
* Andernfalls (isLess oder isGreater) wird das Objekt pContent entsprechend
|
||||
* der vorgegebenen Ordnungsrelation in den BinarySearchTree eingeordnet.
|
||||
*
|
||||
* @param pContent
|
||||
* einzufuegendes Objekt vom Typ ContentType
|
||||
*
|
||||
*/
|
||||
public void insert(ContentType pContent) {
|
||||
if (pContent != null) {
|
||||
if (isEmpty()) {
|
||||
this.node = new BSTNode<ContentType>(pContent);
|
||||
} else if (pContent.isLess(this.node.content)) {
|
||||
this.node.left.insert(pContent);
|
||||
} else if(pContent.isGreater(this.node.content)) {
|
||||
this.node.right.insert(pContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Anfrage liefert den linken Teilbaum des binaeren Suchbaumes. <br />
|
||||
* Wenn er leer ist, wird null zurueckgegeben.
|
||||
*
|
||||
* @return den linken Teilbaum (Objekt vom Typ BinarySearchTree<ContentType>)
|
||||
* bzw. null, wenn der Suchbaum leer ist
|
||||
*
|
||||
*/
|
||||
public BinarySearchTree<ContentType> getLeftTree() {
|
||||
if (this.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return this.node.left;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Anfrage liefert das Inhaltsobjekt des Suchbaumes. Wenn der Suchbaum
|
||||
* leer ist, wird null zurueckgegeben.
|
||||
*
|
||||
* @return das Inhaltsobjekt vom Typ ContentType bzw. null, wenn der aktuelle
|
||||
* Suchbaum leer ist
|
||||
*
|
||||
*/
|
||||
public ContentType getContent() {
|
||||
if (this.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return this.node.content;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Anfrage liefert den rechten Teilbaum des binaeren Suchbaumes. <br />
|
||||
* Wenn er leer ist, wird null zurueckgegeben.
|
||||
*
|
||||
* @return den rechten Teilbaum (Objekt vom Typ BinarySearchTree<ContentType>)
|
||||
* bzw. null, wenn der aktuelle Suchbaum leer ist
|
||||
*
|
||||
*/
|
||||
public BinarySearchTree<ContentType> getRightTree() {
|
||||
if (this.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return this.node.right;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls ein bezueglich der verwendeten Vergleichsmethode mit
|
||||
* pContent uebereinstimmendes Objekt im binaeren Suchbaum enthalten
|
||||
* ist, wird dieses entfernt. Falls der Parameter null ist, aendert sich
|
||||
* nichts.
|
||||
*
|
||||
* @param pContent
|
||||
* zu entfernendes Objekt vom Typ ContentType
|
||||
*
|
||||
*/
|
||||
public void remove(ContentType pContent) {
|
||||
if (isEmpty() || pContent == null ) {
|
||||
// Abbrechen, da kein Element zum entfernen vorhanden ist.
|
||||
return;
|
||||
}
|
||||
|
||||
if (pContent.isLess(node.content)) {
|
||||
// Element ist im linken Teilbaum zu loeschen.
|
||||
node.left.remove(pContent);
|
||||
} else if (pContent.isGreater(node.content)) {
|
||||
// Element ist im rechten Teilbaum zu loeschen.
|
||||
node.right.remove(pContent);
|
||||
} else {
|
||||
// Element ist gefunden.
|
||||
if (node.left.isEmpty()) {
|
||||
if (node.right.isEmpty()) {
|
||||
// Es gibt keinen Nachfolger.
|
||||
node = null;
|
||||
} else {
|
||||
// Es gibt nur rechts einen Nachfolger.
|
||||
node = getNodeOfRightSuccessor();
|
||||
}
|
||||
} else if (node.right.isEmpty()) {
|
||||
// Es gibt nur links einen Nachfolger.
|
||||
node = getNodeOfLeftSuccessor();
|
||||
} else {
|
||||
// Es gibt links und rechts einen Nachfolger.
|
||||
if (getNodeOfRightSuccessor().left.isEmpty()) {
|
||||
// Der rechte Nachfolger hat keinen linken Nachfolger.
|
||||
node.content = getNodeOfRightSuccessor().content;
|
||||
node.right = getNodeOfRightSuccessor().right;
|
||||
} else {
|
||||
BinarySearchTree<ContentType> previous = node.right
|
||||
.ancestorOfSmallRight();
|
||||
BinarySearchTree<ContentType> smallest = previous.node.left;
|
||||
this.node.content = smallest.node.content;
|
||||
previous.remove(smallest.node.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls ein bezueglich der verwendeten Vergleichsmethode isEqual mit
|
||||
* pContent uebereinstimmendes Objekt im binaeren Suchbaum enthalten ist,
|
||||
* liefert die Anfrage dieses, ansonsten wird null zurueckgegeben. <br />
|
||||
* Falls der Parameter null ist, wird null zurueckgegeben.
|
||||
*
|
||||
* @param pContent
|
||||
* zu suchendes Objekt vom Typ ContentType
|
||||
* @return das gefundene Objekt vom Typ ContentType, bei erfolgloser Suche null
|
||||
*
|
||||
*/
|
||||
public ContentType search(ContentType pContent) {
|
||||
if (this.isEmpty() || pContent == null) {
|
||||
// Abbrechen, da es kein Element zu suchen gibt.
|
||||
return null;
|
||||
} else {
|
||||
ContentType content = this.getContent();
|
||||
if (pContent.isLess(content)) {
|
||||
// Element wird im linken Teilbaum gesucht.
|
||||
return this.getLeftTree().search(pContent);
|
||||
} else if (pContent.isGreater(content)) {
|
||||
// Element wird im rechten Teilbaum gesucht.
|
||||
return this.getRightTree().search(pContent);
|
||||
} else if (pContent.isEqual(content)) {
|
||||
// Element wurde gefunden.
|
||||
return content;
|
||||
} else {
|
||||
// Dieser Fall sollte nicht auftreten.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------- Weitere private Methoden -------------- */
|
||||
|
||||
/**
|
||||
* Die Methode liefert denjenigen Baum, dessen linker Nachfolger keinen linken
|
||||
* Nachfolger mehr hat. Es ist also spaeter moeglich, in einem Baum im
|
||||
* rechten Nachfolger den Vorgaenger des linkesten Nachfolgers zu finden.
|
||||
*
|
||||
*/
|
||||
private BinarySearchTree<ContentType> ancestorOfSmallRight() {
|
||||
if (getNodeOfLeftSuccessor().left.isEmpty()) {
|
||||
return this;
|
||||
} else {
|
||||
return node.left.ancestorOfSmallRight();
|
||||
}
|
||||
}
|
||||
|
||||
private BSTNode<ContentType> getNodeOfLeftSuccessor() {
|
||||
return node.left.node;
|
||||
}
|
||||
|
||||
private BSTNode<ContentType> getNodeOfRightSuccessor() {
|
||||
return node.right.node;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
package schule.ngb.zm.util.abi;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Generische Klasse BinaryTree<ContentType>
|
||||
* </p>
|
||||
* <p>
|
||||
* Mithilfe der generischen Klasse BinaryTree koennen beliebig viele
|
||||
* Inhaltsobjekte vom Typ ContentType in einem Binaerbaum verwaltet werden. Ein
|
||||
* Objekt der Klasse stellt entweder einen leeren Baum dar oder verwaltet ein
|
||||
* Inhaltsobjekt sowie einen linken und einen rechten Teilbaum, die ebenfalls
|
||||
* Objekte der generischen Klasse BinaryTree sind.
|
||||
* </p>
|
||||
*
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version Generisch_03 2014-03-01
|
||||
*/
|
||||
public class BinaryTree<ContentType> {
|
||||
|
||||
/* --------- Anfang der privaten inneren Klasse -------------- */
|
||||
|
||||
/**
|
||||
* Durch diese innere Klasse kann man dafuer sorgen, dass ein leerer Baum
|
||||
* null ist, ein nicht-leerer Baum jedoch immer eine nicht-null-Wurzel sowie
|
||||
* nicht-null-Teilbaeume, ggf. leere Teilbaeume hat.
|
||||
*/
|
||||
private class BTNode<CT> {
|
||||
|
||||
private CT content;
|
||||
private BinaryTree<CT> left, right;
|
||||
|
||||
public BTNode(CT pContent) {
|
||||
// Der Knoten hat einen linken und einen rechten Teilbaum, die
|
||||
// beide von null verschieden sind. Also hat ein Blatt immer zwei
|
||||
// leere Teilbaeume unter sich.
|
||||
this.content = pContent;
|
||||
left = new BinaryTree<CT>();
|
||||
right = new BinaryTree<CT>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ----------- Ende der privaten inneren Klasse -------------- */
|
||||
|
||||
private BTNode<ContentType> node;
|
||||
|
||||
/**
|
||||
* Nach dem Aufruf des Konstruktors existiert ein leerer Binaerbaum.
|
||||
*/
|
||||
public BinaryTree() {
|
||||
this.node = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wenn der Parameter pContent ungleich null ist, existiert nach dem Aufruf
|
||||
* des Konstruktors der Binaerbaum und hat pContent als Inhaltsobjekt und
|
||||
* zwei leere Teilbaeume. Falls der Parameter null ist, wird ein leerer
|
||||
* Binaerbaum erzeugt.
|
||||
*
|
||||
* @param pContent
|
||||
* das Inhaltsobjekt des Wurzelknotens vom Typ ContentType
|
||||
*/
|
||||
public BinaryTree(ContentType pContent) {
|
||||
if (pContent != null) {
|
||||
this.node = new BTNode<ContentType>(pContent);
|
||||
} else {
|
||||
this.node = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wenn der Parameter pContent ungleich null ist, wird ein Binaerbaum mit
|
||||
* pContent als Inhalt und den beiden Teilbaeume pLeftTree und pRightTree
|
||||
* erzeugt. Sind pLeftTree oder pRightTree gleich null, wird der
|
||||
* entsprechende Teilbaum als leerer Binaerbaum eingefuegt. So kann es also
|
||||
* nie passieren, dass linke oder rechte Teilbaeume null sind. Wenn der
|
||||
* Parameter pContent gleich null ist, wird ein leerer Binaerbaum erzeugt.
|
||||
*
|
||||
* @param pContent
|
||||
* das Inhaltsobjekt des Wurzelknotens vom Typ ContentType
|
||||
* @param pLeftTree
|
||||
* der linke Teilbaum vom Typ BinaryTree<ContentType>
|
||||
* @param pRightTree
|
||||
* der rechte Teilbaum vom Typ BinaryTree<ContentType>
|
||||
*/
|
||||
public BinaryTree(ContentType pContent, BinaryTree<ContentType> pLeftTree, BinaryTree<ContentType> pRightTree) {
|
||||
if (pContent != null) {
|
||||
this.node = new BTNode<ContentType>(pContent);
|
||||
if (pLeftTree != null) {
|
||||
this.node.left = pLeftTree;
|
||||
} else {
|
||||
this.node.left = new BinaryTree<ContentType>();
|
||||
}
|
||||
if (pRightTree != null) {
|
||||
this.node.right = pRightTree;
|
||||
} else {
|
||||
this.node.right = new BinaryTree<ContentType>();
|
||||
}
|
||||
} else {
|
||||
// Da der Inhalt null ist, wird ein leerer BinarySearchTree erzeugt.
|
||||
this.node = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Anfrage liefert den Wahrheitswert true, wenn der Binaerbaum leer
|
||||
* ist, sonst liefert sie den Wert false.
|
||||
*
|
||||
* @return true, wenn der Binaerbaum leer ist, sonst false
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return this.node == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wenn pContent null ist, geschieht nichts. <br />
|
||||
* Ansonsten: Wenn der Binaerbaum leer ist, wird der Parameter pContent als
|
||||
* Inhaltsobjekt sowie ein leerer linker und rechter Teilbaum eingefuegt.
|
||||
* Ist der Binaerbaum nicht leer, wird das Inhaltsobjekt durch pContent
|
||||
* ersetzt. Die Teilbaeume werden nicht geaendert.
|
||||
*
|
||||
* @param pContent
|
||||
* neues Inhaltsobjekt vom Typ ContentType
|
||||
*/
|
||||
public void setContent(ContentType pContent) {
|
||||
if (pContent != null) {
|
||||
if (this.isEmpty()) {
|
||||
node = new BTNode<ContentType>(pContent);
|
||||
this.node.left = new BinaryTree<ContentType>();
|
||||
this.node.right = new BinaryTree<ContentType>();
|
||||
}
|
||||
this.node.content = pContent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Anfrage liefert das Inhaltsobjekt des Binaerbaums. Wenn der
|
||||
* Binaerbaum leer ist, wird null zurueckgegeben.
|
||||
*
|
||||
* @return das Inhaltsobjekt der Wurzel vom Typ ContentType bzw. null, wenn
|
||||
* der Binaerbaum leer ist
|
||||
*/
|
||||
public ContentType getContent() {
|
||||
if (this.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return this.node.content;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls der Parameter null ist, geschieht nichts. Wenn der Binaerbaum leer
|
||||
* ist, wird pTree nicht angehaengt. Andernfalls erhaelt der Binaerbaum den
|
||||
* uebergebenen BinaryTree als linken Teilbaum.
|
||||
*
|
||||
* @param pTree
|
||||
* neuer linker Teilbaum vom Typ BinaryTree<ContentType>
|
||||
*/
|
||||
public void setLeftTree(BinaryTree<ContentType> pTree) {
|
||||
if (!this.isEmpty() && pTree != null) {
|
||||
this.node.left = pTree;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls der Parameter null ist, geschieht nichts. Wenn der Binaerbaum leer
|
||||
* ist, wird pTree nicht angehaengt. Andernfalls erhaelt der Binaerbaum den
|
||||
* uebergebenen BinaryTree als rechten Teilbaum.
|
||||
*
|
||||
* @param pTree
|
||||
* neuer linker Teilbaum vom Typ BinaryTree<ContentType>
|
||||
*/
|
||||
public void setRightTree(BinaryTree<ContentType> pTree) {
|
||||
if (!this.isEmpty() && pTree != null) {
|
||||
this.node.right = pTree;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Anfrage liefert den linken Teilbaum des Binaerbaumes. Wenn der
|
||||
* Binaerbaum leer ist, wird null zurueckgegeben.
|
||||
*
|
||||
* @return linker Teilbaum vom Typ BinaryTree<ContentType> oder null, wenn
|
||||
* der aktuelle Binaerbaum leer ist
|
||||
*/
|
||||
public BinaryTree<ContentType> getLeftTree() {
|
||||
if (!this.isEmpty()) {
|
||||
return this.node.left;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Anfrage liefert den rechten Teilbaum des Binaerbaumes. Wenn der
|
||||
* Binaerbaum (this) leer ist, wird null zurueckgegeben.
|
||||
*
|
||||
* @return rechter Teilbaum vom Typ BinaryTree<ContentType> oder null, wenn
|
||||
* der aktuelle Binaerbaum (this) leer ist
|
||||
*/
|
||||
public BinaryTree<ContentType> getRightTree() {
|
||||
if (!this.isEmpty()) {
|
||||
return this.node.right;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
package schule.ngb.zm.util.abi;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Klasse Client
|
||||
* </p>
|
||||
* <p>
|
||||
* Objekte von Unterklassen der abstrakten Klasse Client ermoeglichen
|
||||
* Netzwerkverbindungen zu einem Server mittels TCP/IP-Protokoll. Nach
|
||||
* Verbindungsaufbau koennen Zeichenketten (Strings) zum Server gesendet und von
|
||||
* diesem empfangen werden, wobei der Nachrichtenempfang nebenlaeufig geschieht.
|
||||
* Zur Vereinfachung finden Nachrichtenversand und -empfang zeilenweise statt,
|
||||
* d. h., beim Senden einer Zeichenkette wird ein Zeilentrenner ergaenzt und beim
|
||||
* Empfang wird dieser entfernt. Jede empfangene Nachricht wird einer
|
||||
* Ereignisbehandlungsmethode uebergeben, die in Unterklassen implementiert werden
|
||||
* muss. Es findet nur eine rudimentaere Fehlerbehandlung statt, so dass z.B.
|
||||
* Verbindungsabbrueche nicht zu einem Programmabbruch fuehren. Eine einmal
|
||||
* unterbrochene oder getrennte Verbindung kann nicht reaktiviert werden.
|
||||
* </p>
|
||||
*
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version 30.08.2016
|
||||
*/
|
||||
|
||||
public abstract class Client
|
||||
{
|
||||
private MessageHandler messageHandler;
|
||||
|
||||
private class MessageHandler extends Thread
|
||||
{
|
||||
private SocketWrapper socketWrapper;
|
||||
private boolean active;
|
||||
|
||||
private class SocketWrapper
|
||||
{
|
||||
private Socket socket;
|
||||
private BufferedReader fromServer;
|
||||
private PrintWriter toServer;
|
||||
|
||||
public SocketWrapper(String pServerIP, int pServerPort)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket = new Socket(pServerIP, pServerPort);
|
||||
toServer = new PrintWriter(socket.getOutputStream(), true);
|
||||
fromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
socket = null;
|
||||
toServer = null;
|
||||
fromServer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public String receive()
|
||||
{
|
||||
if(fromServer != null)
|
||||
try
|
||||
{
|
||||
return fromServer.readLine();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
}
|
||||
return(null);
|
||||
}
|
||||
|
||||
public void send(String pMessage)
|
||||
{
|
||||
if(toServer != null)
|
||||
{
|
||||
toServer.println(pMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
if(socket != null)
|
||||
try
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
/*
|
||||
* Falls eine Verbindung getrennt werden soll, deren Endpunkt
|
||||
* nicht mehr existiert bzw. ihrerseits bereits beendet worden ist,
|
||||
* geschieht nichts.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MessageHandler(String pServerIP, int pServerPort)
|
||||
{
|
||||
socketWrapper = new SocketWrapper(pServerIP, pServerPort);
|
||||
start();
|
||||
if(socketWrapper.socket != null)
|
||||
active = true;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
String message = null;
|
||||
while (active)
|
||||
{
|
||||
message = socketWrapper.receive();
|
||||
if (message != null)
|
||||
processMessage(message);
|
||||
else
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
private void send(String pMessage)
|
||||
{
|
||||
if(active)
|
||||
socketWrapper.send(pMessage);
|
||||
}
|
||||
|
||||
private void close()
|
||||
{
|
||||
if(active)
|
||||
{
|
||||
active = false;
|
||||
socketWrapper.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Client(String pServerIP, int pServerPort)
|
||||
{
|
||||
messageHandler = new MessageHandler(pServerIP, pServerPort);
|
||||
}
|
||||
|
||||
public boolean isConnected()
|
||||
{
|
||||
return(messageHandler.active);
|
||||
}
|
||||
|
||||
public void send(String pMessage)
|
||||
{
|
||||
messageHandler.send(pMessage);
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
messageHandler.close();
|
||||
}
|
||||
|
||||
public abstract void processMessage(String pMessage);
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package schule.ngb.zm.util.abi;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Generisches Interface (Schnittstelle) ComparableContent<ContentType>
|
||||
* </p>
|
||||
* <p>
|
||||
* <p>Das generische Interface ComparableContent<ContentType> legt die Methoden
|
||||
* fest, ueber die Objekte verfuegen muessen, die in einen binaeren Suchbaum
|
||||
* (BinarySearchTree) eingefuegt werden sollen. Die Ordnungsrelation wird in
|
||||
* Klassen, die ComparableContent implementieren durch Ueberschreiben der drei
|
||||
* implizit abstrakten Methoden isGreater, isEqual und isLess festgelegt.
|
||||
* </p>
|
||||
* </p>
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version Generisch_02 2014-03-01
|
||||
*/
|
||||
public interface ComparableContent<ContentType> {
|
||||
|
||||
/**
|
||||
* Wenn festgestellt wird, dass das Objekt, von dem die Methode aufgerufen
|
||||
* wird, bzgl. der gewuenschten Ordnungsrelation groesser als das Objekt
|
||||
* pContent ist, wird true geliefert. Sonst wird false geliefert.
|
||||
*
|
||||
* @param pContent
|
||||
* das mit dem aufrufenden Objekt zu vergleichende Objekt vom
|
||||
* Typ ContentType
|
||||
* @return true, wenn das aufrufende Objekt groesser ist als das Objekt
|
||||
* pContent, sonst false
|
||||
*/
|
||||
public boolean isGreater(ContentType pContent);
|
||||
|
||||
/**
|
||||
* Wenn festgestellt wird, dass das Objekt, von dem die Methode aufgerufen
|
||||
* wird, bzgl. der gewuenschten Ordnungsrelation gleich gross wie das Objekt
|
||||
* pContent ist, wird true geliefert. Sonst wird false geliefert.
|
||||
*
|
||||
* @param pContent
|
||||
* das mit dem aufrufenden Objekt zu vergleichende Objekt vom
|
||||
* Typ ContentType
|
||||
* @return true, wenn das aufrufende Objekt gleich gross ist wie das Objekt
|
||||
* pContent, sonst false
|
||||
*/
|
||||
public boolean isEqual(ContentType pContent);
|
||||
|
||||
/**
|
||||
* Wenn festgestellt wird, dass das Objekt, von dem die Methode aufgerufen
|
||||
* wird, bzgl. der gewuenschten Ordnungsrelation kleiner als das Objekt
|
||||
* pContent ist, wird true geliefert. Sonst wird false geliefert.
|
||||
*
|
||||
* @param pContent
|
||||
* das mit dem aufrufenden Objekt zu vergleichende Objekt vom
|
||||
* Typ ContentType
|
||||
* @return true, wenn das aufrufende Objekt kleiner ist als das Objekt
|
||||
* pContent, sonst false
|
||||
*/
|
||||
public boolean isLess(ContentType pContent);
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package schule.ngb.zm.util.abi; /**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Klasse Connection
|
||||
* </p>
|
||||
* <p>
|
||||
* Objekte der Klasse Connection ermoeglichen eine Netzwerkverbindung zu einem
|
||||
* Server mittels TCP/IP-Protokoll. Nach Verbindungsaufbau koennen Zeichenketten
|
||||
* (Strings) zum Server gesendet und von diesem empfangen werden. Zur
|
||||
* Vereinfachung geschieht dies zeilenweise, d. h., beim Senden einer
|
||||
* Zeichenkette wird ein Zeilentrenner ergaenzt und beim Empfang wird dieser
|
||||
* entfernt. Es findet nur eine rudimentaere Fehlerbehandlung statt, so dass z.B.
|
||||
* der Zugriff auf unterbrochene oder bereits getrennte Verbindungen nicht zu
|
||||
* einem Programmabbruch fuehrt. Eine einmal getrennte Verbindung kann nicht
|
||||
* reaktiviert werden.
|
||||
* </p>
|
||||
*
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version 30.08.2016
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
|
||||
public class Connection
|
||||
{
|
||||
private Socket socket;
|
||||
private BufferedReader fromServer;
|
||||
private PrintWriter toServer;
|
||||
|
||||
public Connection(String pServerIP, int pServerPort)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket = new Socket(pServerIP, pServerPort);
|
||||
toServer = new PrintWriter(socket.getOutputStream(), true);
|
||||
fromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//Erstelle eine nicht-verbundene Instanz von Socket, wenn die avisierte
|
||||
//Verbindung nicht hergestellt werden kann
|
||||
socket = null;
|
||||
toServer = null;
|
||||
fromServer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public String receive()
|
||||
{
|
||||
if(fromServer != null)
|
||||
try
|
||||
{
|
||||
return fromServer.readLine();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
}
|
||||
return(null);
|
||||
}
|
||||
|
||||
public void send(String pMessage)
|
||||
{
|
||||
if(toServer != null)
|
||||
{
|
||||
toServer.println(pMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
|
||||
if(socket != null && !socket.isClosed())
|
||||
try
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
/*
|
||||
* Falls eine Verbindung geschlossen werden soll, deren Endpunkt nicht
|
||||
* mehr existiert bzw. seinerseits bereits geschlossen worden ist oder
|
||||
* die nicht korrekt instanziiert werden konnte (socket == null), geschieht
|
||||
* nichts.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
package schule.ngb.zm.util.abi;
|
||||
|
||||
import java.sql.*;
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Klasse DatabaseConnector
|
||||
* </p>
|
||||
* <p>
|
||||
* Ein Objekt der Klasse DatabaseConnector ermoeglicht die Abfrage und Manipulation
|
||||
* einer SQLite-Datenbank.
|
||||
* Beim Erzeugen des Objekts wird eine Datenbankverbindung aufgebaut, so dass
|
||||
* anschließend SQL-Anweisungen an diese Datenbank gerichtet werden koennen.
|
||||
* </p>
|
||||
*
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version 2016-01-24
|
||||
*/
|
||||
public class DatabaseConnector{
|
||||
private Connection connection;
|
||||
private QueryResult currentQueryResult = null;
|
||||
private String message = null;
|
||||
|
||||
/**
|
||||
* Ein Objekt vom Typ DatabaseConnector wird erstellt, und eine Verbindung zur Datenbank
|
||||
* wird aufgebaut. Mit den Parametern pIP und pPort werden die IP-Adresse und die
|
||||
* Port-Nummer uebergeben, unter denen die Datenbank mit Namen pDatabase zu erreichen ist.
|
||||
* Mit den Parametern pUsername und pPassword werden Benutzername und Passwort fuer die
|
||||
* Datenbank uebergeben.
|
||||
*/
|
||||
public DatabaseConnector(String pIP, int pPort, String pDatabase, String pUsername, String pPassword){
|
||||
//Eine Impementierung dieser Schnittstelle fuer SQLite ignoriert pID und pPort, da die Datenbank immer lokal ist.
|
||||
//Auch pUsername und pPassword werden nicht verwendet, da SQLite sie nicht unterstuetzt.
|
||||
try {
|
||||
//Laden der Treiberklasse
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
|
||||
//Verbindung herstellen
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:"+pDatabase);
|
||||
|
||||
} catch (Exception e) {
|
||||
message = e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Auftrag schickt den im Parameter pSQLStatement enthaltenen SQL-Befehl an die
|
||||
* Datenbank ab.
|
||||
* Handelt es sich bei pSQLStatement um einen SQL-Befehl, der eine Ergebnismenge
|
||||
* liefert, so kann dieses Ergebnis anschließend mit der Methode getCurrentQueryResult
|
||||
* abgerufen werden.
|
||||
*/
|
||||
public void executeStatement(String pSQLStatement){
|
||||
//Altes Ergebnis loeschen
|
||||
currentQueryResult = null;
|
||||
message = null;
|
||||
|
||||
try {
|
||||
//Neues Statement erstellen
|
||||
Statement statement = connection.createStatement();
|
||||
|
||||
//SQL Anweisung an die DB schicken.
|
||||
if (statement.execute(pSQLStatement)) { //Fall 1: Es gibt ein Ergebnis
|
||||
|
||||
//Resultset auslesen
|
||||
ResultSet resultset = statement.getResultSet();
|
||||
|
||||
//Spaltenanzahl ermitteln
|
||||
int columnCount = resultset.getMetaData().getColumnCount();
|
||||
|
||||
//Spaltennamen und Spaltentypen in Felder uebertragen
|
||||
String[] resultColumnNames = new String[columnCount];
|
||||
String[] resultColumnTypes = new String[columnCount];
|
||||
for (int i = 0; i < columnCount; i++){
|
||||
resultColumnNames[i] = resultset.getMetaData().getColumnLabel(i+1);
|
||||
resultColumnTypes[i] = resultset.getMetaData().getColumnTypeName(i+1);
|
||||
}
|
||||
|
||||
//Queue fuer die Zeilen der Ergebnistabelle erstellen
|
||||
Queue<String[]> rows = new Queue<String[]>();
|
||||
|
||||
//Daten in Queue uebertragen und Zeilen zaehlen
|
||||
int rowCount = 0;
|
||||
while (resultset.next()){
|
||||
String[] resultrow = new String[columnCount];
|
||||
for (int s = 0; s < columnCount; s++){
|
||||
resultrow[s] = resultset.getString(s+1);
|
||||
}
|
||||
rows.enqueue(resultrow);
|
||||
rowCount = rowCount + 1;
|
||||
}
|
||||
|
||||
//Ergebnisfeld erstellen und Zeilen aus Queue uebertragen
|
||||
String[][] resultData = new String[rowCount][columnCount];
|
||||
int j = 0;
|
||||
while (!rows.isEmpty()){
|
||||
resultData[j] = rows.front();
|
||||
rows.dequeue();
|
||||
j = j + 1;
|
||||
}
|
||||
|
||||
//Statement schließen und Ergebnisobjekt erstellen
|
||||
statement.close();
|
||||
currentQueryResult = new QueryResult(resultData, resultColumnNames, resultColumnTypes);
|
||||
|
||||
} else { //Fall 2: Es gibt kein Ergebnis.
|
||||
//Statement ohne Ergebnisobjekt schliessen
|
||||
statement.close();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
//Fehlermeldung speichern
|
||||
message = e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert das Ergebnis des letzten mit der Methode executeStatement an
|
||||
* die Datenbank geschickten SQL-Befehls als Ob-jekt vom Typ QueryResult zurueck.
|
||||
* Wurde bisher kein SQL-Befehl abgeschickt oder ergab der letzte Aufruf von
|
||||
* executeStatement keine Ergebnismenge (z.B. bei einem INSERT-Befehl oder einem
|
||||
* Syntaxfehler), so wird null geliefert.
|
||||
*/
|
||||
public QueryResult getCurrentQueryResult(){
|
||||
return currentQueryResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert null oder eine Fehlermeldung, die sich jeweils auf die letzte zuvor ausgefuehrte
|
||||
* Datenbankoperation bezieht.
|
||||
*/
|
||||
public String getErrorMessage(){
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Datenbankverbindung wird geschlossen.
|
||||
*/
|
||||
public void close(){
|
||||
try{
|
||||
connection.close();
|
||||
} catch (Exception e) {
|
||||
message = e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package schule.ngb.zm.util.abi;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Klasse Edge
|
||||
* </p>
|
||||
* <p>
|
||||
* Die Klasse Edge stellt eine einzelne, ungerichtete Kante eines Graphen dar.
|
||||
* Beim Erstellen werden die beiden durch sie zu verbindenden Knotenobjekte und eine
|
||||
* Gewichtung als double uebergeben. Beide Knotenobjekte koennen abgefragt werden.
|
||||
* Des Weiteren koennen die Gewichtung und eine Markierung gesetzt und abgefragt werden.
|
||||
* </p>
|
||||
*
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version Oktober 2015
|
||||
*/
|
||||
public class Edge{
|
||||
private Vertex[] vertices;
|
||||
private double weight;
|
||||
private boolean mark;
|
||||
|
||||
/**
|
||||
* Ein neues Objekt vom Typ Edge wird erstellt. Die von diesem Objekt
|
||||
* repraesentierte Kante verbindet die Knoten pVertex und pAnotherVertex mit der
|
||||
* Gewichtung pWeight. Ihre Markierung hat den Wert false.
|
||||
*/
|
||||
public Edge( Vertex pVertex, Vertex pAnotherVertex, double pWeight){
|
||||
vertices = new Vertex[2];
|
||||
vertices[0] = pVertex;
|
||||
vertices[1] = pAnotherVertex;
|
||||
weight = pWeight;
|
||||
mark = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage gibt die beiden Knoten, die durch die Kante verbunden werden, als neues Feld vom Typ Vertex zurueck. Das Feld hat
|
||||
* genau zwei Eintraege mit den Indexwerten 0 und 1.
|
||||
*/
|
||||
public Vertex[] getVertices(){
|
||||
Vertex[] result = new Vertex[2];
|
||||
result[0] = vertices[0];
|
||||
result[1] = vertices[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Auftrag setzt das Gewicht der Kante auf pWeight.
|
||||
*/
|
||||
public void setWeight(double pWeight){
|
||||
weight = pWeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert das Gewicht der Kante als double.
|
||||
*/
|
||||
public double getWeight(){
|
||||
return weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Auftrag setzt die Markierung der Kante auf den Wert pMark.
|
||||
*/
|
||||
public void setMark(boolean pMark){
|
||||
mark = pMark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert true, wenn die Markierung der Kante den Wert true hat, ansonsten false.
|
||||
*/
|
||||
public boolean isMarked(){
|
||||
return mark;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,314 @@
|
|||
package schule.ngb.zm.util.abi;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Klasse Graph
|
||||
* </p>
|
||||
* <p>
|
||||
* Die Klasse Graph stellt einen ungerichteten, kantengewichteten Graphen dar. Es koennen
|
||||
* Knoten- und Kantenobjekte hinzugefuegt und entfernt, flache Kopien der Knoten- und Kantenlisten
|
||||
* des Graphen angefragt und Markierungen von Knoten und Kanten gesetzt und ueberprueft werden.
|
||||
* Des Weiteren kann eine Liste der Nachbarn eines bestimmten Knoten, eine Liste der inzidenten
|
||||
* Kanten eines bestimmten Knoten und die Kante von einem bestimmten Knoten zu einem
|
||||
* anderen bestimmten Knoten angefragt werden. Abgesehen davon kann abgefragt werden, welches
|
||||
* Knotenobjekt zu einer bestimmten ID gehoert und ob der Graph leer ist.
|
||||
* </p>
|
||||
*
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version Oktober 2015
|
||||
*/
|
||||
public class Graph{
|
||||
private List<Vertex> vertices;
|
||||
private List<Edge> edges;
|
||||
|
||||
/**
|
||||
* Ein Objekt vom Typ Graph wird erstellt. Der von diesem Objekt
|
||||
* repraesentierte Graph ist leer.
|
||||
*/
|
||||
public Graph(){
|
||||
//Leere Listen fuer Knoten und Kanten erstellen.
|
||||
vertices = new List<Vertex>();
|
||||
edges = new List<Edge>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert eine neue Liste aller Knotenobjekte vom Typ List<Vertex>.
|
||||
*/
|
||||
public List<Vertex> getVertices(){
|
||||
//Eine neue Liste mit allen Vertex-Objekten erstellen.
|
||||
List<Vertex> result = new List<Vertex>();
|
||||
vertices.toFirst();
|
||||
while (vertices.hasAccess()){
|
||||
result.append(vertices.getContent());
|
||||
vertices.next();
|
||||
}
|
||||
//Aktuelles Element zum Anfang bewegen.
|
||||
result.toFirst();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert eine neue Liste aller Kantenobjekte vom Typ List<Edge>.
|
||||
*/
|
||||
public List<Edge> getEdges(){
|
||||
//Eine neue Liste mit allen Edge-Objekten erstellen.
|
||||
List<Edge> result = new List<Edge>();
|
||||
edges.toFirst();
|
||||
while (edges.hasAccess()){
|
||||
result.append(edges.getContent());
|
||||
edges.next();
|
||||
}
|
||||
//Aktuelles Element zum Anfang bewegen.
|
||||
result.toFirst();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert das Knotenobjekt mit pID als ID. Ist ein solchen Knotenobjekt nicht im Graphen enthalten,
|
||||
* wird null zurueckgeliefert.
|
||||
*/
|
||||
public Vertex getVertex( String pID){
|
||||
//Vertex-Objekt mit pID als ID suchen.
|
||||
Vertex result = null;
|
||||
vertices.toFirst();
|
||||
while (vertices.hasAccess() && result == null){
|
||||
if (vertices.getContent().getID().equals(pID)){
|
||||
result = vertices.getContent();
|
||||
}
|
||||
vertices.next();
|
||||
}
|
||||
|
||||
//Objekt zurueckliefern.
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Auftrag fuegt den Knoten pVertex in den Graphen ein, sofern es noch keinen
|
||||
* Knoten mit demselben ID-Eintrag wie pVertex im Graphen gibt und pVertex eine ID ungleich null hat.
|
||||
* Ansonsten passiert nichts.
|
||||
*/
|
||||
public void addVertex( Vertex pVertex){
|
||||
//Pruefen, ob der Vertex existiert und eine ID hat.
|
||||
if (pVertex != null && pVertex.getID() != null) {
|
||||
//Pruefen, ob nicht schon ein Vertex mit gleicher ID enthalten ist.
|
||||
boolean freeID = true;
|
||||
vertices.toFirst();
|
||||
while (vertices.hasAccess() && freeID){
|
||||
if (vertices.getContent().getID().equals(pVertex.getID())){
|
||||
freeID = false;
|
||||
}
|
||||
vertices.next();
|
||||
}
|
||||
|
||||
//Wenn die ID noch frei ist, den Vertex einfuegen, sonst nichts tun.
|
||||
if (freeID) {
|
||||
vertices.append(pVertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Auftrag fuegt die Kante pEdge in den Graphen ein, sofern beide durch die Kante verbundenen Knoten
|
||||
* im Graphen enthalten sind, nicht identisch sind und noch keine Kante zwischen den Knoten existiert. Ansonsten passiert nichts.
|
||||
*/
|
||||
public void addEdge(Edge pEdge){
|
||||
//Pruefen, ob pEdge exisitert.
|
||||
if (pEdge != null){
|
||||
Vertex[] vertexPair = pEdge.getVertices();
|
||||
|
||||
//Einfuegekriterien pruefen.
|
||||
if (vertexPair[0] != null && vertexPair[1] != null &&
|
||||
this.getVertex(vertexPair[0].getID()) == vertexPair[0] &&
|
||||
this.getVertex(vertexPair[1].getID()) == vertexPair[1] &&
|
||||
this.getEdge(vertexPair[0], vertexPair[1]) == null &&
|
||||
vertexPair[0] != vertexPair[1]){
|
||||
//Kante einfuegen.
|
||||
edges.append(pEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Auftrag entfernt den Knoten pVertex aus dem Graphen und loescht alle Kanten, die mit ihm inzident sind.
|
||||
* Ist der Knoten pVertex nicht im Graphen enthalten, passiert nichts.
|
||||
*/
|
||||
public void removeVertex( Vertex pVertex){
|
||||
//Inzidente Kanten entfernen.
|
||||
edges.toFirst();
|
||||
while (edges.hasAccess()){
|
||||
Vertex[] akt = edges.getContent().getVertices();
|
||||
if (akt[0] == pVertex || akt[1] == pVertex){
|
||||
edges.remove();
|
||||
} else {
|
||||
edges.next();
|
||||
}
|
||||
}
|
||||
|
||||
//Knoten entfernen
|
||||
vertices.toFirst();
|
||||
while (vertices.hasAccess() && vertices.getContent()!= pVertex){
|
||||
vertices.next();
|
||||
}
|
||||
if (vertices.hasAccess()){
|
||||
vertices.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Auftrag entfernt die Kante pEdge aus dem Graphen. Ist die Kante pEdge nicht
|
||||
* im Graphen enthalten, passiert nichts.
|
||||
*/
|
||||
public void removeEdge(Edge pEdge){
|
||||
//Kante aus Kantenliste des Graphen entfernen.
|
||||
edges.toFirst();
|
||||
while (edges.hasAccess()){
|
||||
if (edges.getContent() == pEdge){
|
||||
edges.remove();
|
||||
} else {
|
||||
edges.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Auftrag setzt die Markierungen aller Knoten des Graphen auf pMark.
|
||||
*/
|
||||
public void setAllVertexMarks(boolean pMark){
|
||||
vertices.toFirst();
|
||||
while (vertices.hasAccess()){
|
||||
vertices.getContent().setMark(pMark);
|
||||
vertices.next();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Auftrag setzt die Markierungen aller Kanten des Graphen auf pMark.
|
||||
*/
|
||||
public void setAllEdgeMarks(boolean pMark){
|
||||
edges.toFirst();
|
||||
while (edges.hasAccess()){
|
||||
edges.getContent().setMark(pMark);
|
||||
edges.next();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert true, wenn alle Knoten des Graphen mit true markiert sind, ansonsten false.
|
||||
*/
|
||||
public boolean allVerticesMarked(){
|
||||
boolean result = true;
|
||||
vertices.toFirst();
|
||||
while (vertices.hasAccess()){
|
||||
if (!vertices.getContent().isMarked()){
|
||||
result = false;
|
||||
}
|
||||
vertices.next();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert true, wenn alle Kanten des Graphen mit true markiert sind, ansonsten false.
|
||||
*/
|
||||
public boolean allEdgesMarked(){
|
||||
boolean result = true;
|
||||
edges.toFirst();
|
||||
while (edges.hasAccess()){
|
||||
if (!edges.getContent().isMarked()){
|
||||
result = false;
|
||||
}
|
||||
edges.next();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert alle Nachbarn des Knotens pVertex als neue Liste vom Typ List<Vertex>. Hat der Knoten
|
||||
* pVertex keine Nachbarn in diesem Graphen oder ist gar nicht in diesem Graphen enthalten, so
|
||||
* wird eine leere Liste zurueckgeliefert.
|
||||
*/
|
||||
public List<Vertex> getNeighbours( Vertex pVertex){
|
||||
List<Vertex> result = new List<Vertex>();
|
||||
|
||||
//Alle Kanten durchlaufen.
|
||||
edges.toFirst();
|
||||
while (edges.hasAccess()){
|
||||
|
||||
//Wenn ein Knoten der Kante pVertex ist, den anderen als Nachbarn in die Ergebnisliste einfuegen.
|
||||
Vertex[] vertexPair = edges.getContent().getVertices();
|
||||
if (vertexPair[0] == pVertex) {
|
||||
result.append(vertexPair[1]);
|
||||
} else {
|
||||
if (vertexPair[1] == pVertex){
|
||||
result.append(vertexPair[0]);
|
||||
}
|
||||
}
|
||||
edges.next();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert eine neue Liste alle inzidenten Kanten zum Knoten pVertex. Hat der Knoten
|
||||
* pVertex keine inzidenten Kanten in diesem Graphen oder ist gar nicht in diesem Graphen enthalten, so
|
||||
* wird eine leere Liste zurueckgeliefert.
|
||||
*/
|
||||
public List<Edge> getEdges( Vertex pVertex){
|
||||
List<Edge> result = new List<Edge>();
|
||||
|
||||
//Alle Kanten durchlaufen.
|
||||
edges.toFirst();
|
||||
while (edges.hasAccess()){
|
||||
|
||||
//Wenn ein Knoten der Kante pVertex ist, dann Kante als inzidente Kante in die Ergebnisliste einfuegen.
|
||||
Vertex[] vertexPair = edges.getContent().getVertices();
|
||||
if (vertexPair[0] == pVertex) {
|
||||
result.append(edges.getContent());
|
||||
} else{
|
||||
if (vertexPair[1] == pVertex){
|
||||
result.append(edges.getContent());
|
||||
}
|
||||
}
|
||||
edges.next();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert die Kante, welche die Knoten pVertex und pAnotherVertex verbindet,
|
||||
* als Objekt vom Typ Edge. Ist der Knoten pVertex oder der Knoten pAnotherVertex nicht
|
||||
* im Graphen enthalten oder gibt es keine Kante, die beide Knoten verbindet, so wird null
|
||||
* zurueckgeliefert.
|
||||
*/
|
||||
public Edge getEdge( Vertex pVertex, Vertex pAnotherVertex){
|
||||
Edge result = null;
|
||||
|
||||
//Kanten durchsuchen, solange keine passende gefunden wurde.
|
||||
edges.toFirst();
|
||||
while (edges.hasAccess() && result == null){
|
||||
|
||||
//Pruefen, ob die Kante pVertex und pAnotherVertex verbindet.
|
||||
Vertex[] vertexPair = edges.getContent().getVertices();
|
||||
if ((vertexPair[0] == pVertex && vertexPair[1] == pAnotherVertex) ||
|
||||
(vertexPair[0] == pAnotherVertex && vertexPair[1] == pVertex)) {
|
||||
//Kante als Ergebnis merken.
|
||||
result = edges.getContent();
|
||||
}
|
||||
edges.next();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert true, wenn der Graph keine Knoten enthaelt, ansonsten false.
|
||||
*/
|
||||
public boolean isEmpty(){
|
||||
return vertices.isEmpty();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,347 @@
|
|||
package schule.ngb.zm.util.abi;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Generische Klasse List<ContentType>
|
||||
* </p>
|
||||
* <p>
|
||||
* Objekt der generischen Klasse List verwalten beliebig viele linear
|
||||
* angeordnete Objekte vom Typ ContentType. Auf hoechstens ein Listenobjekt,
|
||||
* aktuellesObjekt genannt, kann jeweils zugegriffen werden.<br />
|
||||
* Wenn eine Liste leer ist, vollstaendig durchlaufen wurde oder das aktuelle
|
||||
* Objekt am Ende der Liste geloescht wurde, gibt es kein aktuelles Objekt.<br />
|
||||
* Das erste oder das letzte Objekt einer Liste koennen durch einen Auftrag zum
|
||||
* aktuellen Objekt gemacht werden. Ausserdem kann das dem aktuellen Objekt
|
||||
* folgende Listenobjekt zum neuen aktuellen Objekt werden. <br />
|
||||
* Das aktuelle Objekt kann gelesen, veraendert oder geloescht werden. Ausserdem
|
||||
* kann vor dem aktuellen Objekt ein Listenobjekt eingefuegt werden.
|
||||
* </p>
|
||||
*
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version Generisch_06 2015-10-25
|
||||
*/
|
||||
public class List<ContentType> {
|
||||
|
||||
/* --------- Anfang der privaten inneren Klasse -------------- */
|
||||
|
||||
private class ListNode {
|
||||
|
||||
private ContentType contentObject;
|
||||
private ListNode next;
|
||||
|
||||
/**
|
||||
* Ein neues Objekt wird erschaffen. Der Verweis ist leer.
|
||||
*
|
||||
* @param pContent das Inhaltsobjekt vom Typ ContentType
|
||||
*/
|
||||
private ListNode(ContentType pContent) {
|
||||
contentObject = pContent;
|
||||
next = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Inhalt des Knotens wird zurueckgeliefert.
|
||||
*
|
||||
* @return das Inhaltsobjekt des Knotens
|
||||
*/
|
||||
public ContentType getContentObject() {
|
||||
return contentObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Inhalt dieses Kontens wird gesetzt.
|
||||
*
|
||||
* @param pContent das Inhaltsobjekt vom Typ ContentType
|
||||
*/
|
||||
public void setContentObject(ContentType pContent) {
|
||||
contentObject = pContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Nachfolgeknoten wird zurueckgeliefert.
|
||||
*
|
||||
* @return das Objekt, auf das der aktuelle Verweis zeigt
|
||||
*/
|
||||
public ListNode getNextNode() {
|
||||
return this.next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Verweis wird auf das Objekt, das als Parameter uebergeben
|
||||
* wird, gesetzt.
|
||||
*
|
||||
* @param pNext der Nachfolger des Knotens
|
||||
*/
|
||||
public void setNextNode(ListNode pNext) {
|
||||
this.next = pNext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ----------- Ende der privaten inneren Klasse -------------- */
|
||||
|
||||
// erstes Element der Liste
|
||||
ListNode first;
|
||||
|
||||
// letztes Element der Liste
|
||||
ListNode last;
|
||||
|
||||
// aktuelles Element der Liste
|
||||
ListNode current;
|
||||
|
||||
/**
|
||||
* Eine leere Liste wird erzeugt.
|
||||
*/
|
||||
public List() {
|
||||
first = null;
|
||||
last = null;
|
||||
current = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthaelt,
|
||||
* sonst liefert sie den Wert false.
|
||||
*
|
||||
* @return true, wenn die Liste leer ist, sonst false
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
// Die Liste ist leer, wenn es kein erstes Element gibt.
|
||||
return first == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt,
|
||||
* sonst liefert sie den Wert false.
|
||||
*
|
||||
* @return true, falls Zugriff moeglich, sonst false
|
||||
*/
|
||||
public boolean hasAccess() {
|
||||
// Es gibt keinen Zugriff, wenn current auf kein Element verweist.
|
||||
return current != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses
|
||||
* nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in
|
||||
* der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach
|
||||
* Ausfuehrung des Auftrags kein aktuelles Objekt, d.h. hasAccess() liefert
|
||||
* den Wert false.
|
||||
*/
|
||||
public void next() {
|
||||
if (this.hasAccess()) {
|
||||
current = current.getNextNode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles
|
||||
* Objekt. Ist die Liste leer, geschieht nichts.
|
||||
*/
|
||||
public void toFirst() {
|
||||
if (!isEmpty()) {
|
||||
current = first;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls die Liste nicht leer ist, wird das letzte Objekt der Liste
|
||||
* aktuelles Objekt. Ist die Liste leer, geschieht nichts.
|
||||
*/
|
||||
public void toLast() {
|
||||
if (!isEmpty()) {
|
||||
current = last;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das
|
||||
* aktuelle Objekt zurueckgegeben, andernfalls (hasAccess() == false) gibt
|
||||
* die Anfrage den Wert null zurueck.
|
||||
*
|
||||
* @return das aktuelle Objekt (vom Typ ContentType) oder null, wenn es
|
||||
* kein aktuelles Objekt gibt
|
||||
*/
|
||||
public ContentType getContent() {
|
||||
if (this.hasAccess()) {
|
||||
return current.getContentObject();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls es ein aktuelles Objekt gibt (hasAccess() == true) und pContent
|
||||
* ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst
|
||||
* geschieht nichts.
|
||||
*
|
||||
* @param pContent
|
||||
* das zu schreibende Objekt vom Typ ContentType
|
||||
*/
|
||||
public void setContent(ContentType pContent) {
|
||||
// Nichts tun, wenn es keinen Inhalt oder kein aktuelles Element gibt.
|
||||
if (pContent != null && this.hasAccess()) {
|
||||
current.setContentObject(pContent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird ein neues
|
||||
* Objekt vor dem aktuellen Objekt in die Liste eingefuegt. Das aktuelle
|
||||
* Objekt bleibt unveraendert. <br />
|
||||
* Wenn die Liste leer ist, wird pContent in die Liste eingefuegt und es
|
||||
* gibt weiterhin kein aktuelles Objekt (hasAccess() == false). <br />
|
||||
* Falls es kein aktuelles Objekt gibt (hasAccess() == false) und die Liste
|
||||
* nicht leer ist oder pContent gleich null ist, geschieht nichts.
|
||||
*
|
||||
* @param pContent
|
||||
* das einzufuegende Objekt vom Typ ContentType
|
||||
*/
|
||||
public void insert(ContentType pContent) {
|
||||
if (pContent != null) { // Nichts tun, wenn es keinen Inhalt gibt.
|
||||
if (this.hasAccess()) { // Fall: Es gibt ein aktuelles Element.
|
||||
|
||||
// Neuen Knoten erstellen.
|
||||
ListNode newNode = new ListNode(pContent);
|
||||
|
||||
if (current != first) { // Fall: Nicht an erster Stelle einfuegen.
|
||||
ListNode previous = this.getPrevious(current);
|
||||
newNode.setNextNode(previous.getNextNode());
|
||||
previous.setNextNode(newNode);
|
||||
} else { // Fall: An erster Stelle einfuegen.
|
||||
newNode.setNextNode(first);
|
||||
first = newNode;
|
||||
}
|
||||
|
||||
} else { //Fall: Es gibt kein aktuelles Element.
|
||||
|
||||
if (this.isEmpty()) { // Fall: In leere Liste einfuegen.
|
||||
|
||||
// Neuen Knoten erstellen.
|
||||
ListNode newNode = new ListNode(pContent);
|
||||
|
||||
first = newNode;
|
||||
last = newNode;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls pContent gleich null ist, geschieht nichts.<br />
|
||||
* Ansonsten wird ein neues Objekt pContent am Ende der Liste eingefuegt.
|
||||
* Das aktuelle Objekt bleibt unveraendert. <br />
|
||||
* Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefuegt
|
||||
* und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false).
|
||||
*
|
||||
* @param pContent
|
||||
* das anzuhaengende Objekt vom Typ ContentType
|
||||
*/
|
||||
public void append(ContentType pContent) {
|
||||
if (pContent != null) { // Nichts tun, wenn es keine Inhalt gibt.
|
||||
|
||||
if (this.isEmpty()) { // Fall: An leere Liste anfuegen.
|
||||
this.insert(pContent);
|
||||
} else { // Fall: An nicht-leere Liste anfuegen.
|
||||
|
||||
// Neuen Knoten erstellen.
|
||||
ListNode newNode = new ListNode(pContent);
|
||||
|
||||
last.setNextNode(newNode);
|
||||
last = newNode; // Letzten Knoten aktualisieren.
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Falls es sich bei der Liste und pList um dasselbe Objekt handelt,
|
||||
* pList null oder eine leere Liste ist, geschieht nichts.<br />
|
||||
* Ansonsten wird die Liste pList an die aktuelle Liste angehaengt.
|
||||
* Anschliessend wird pList eine leere Liste. Das aktuelle Objekt bleibt
|
||||
* unveraendert. Insbesondere bleibt hasAccess identisch.
|
||||
*
|
||||
* @param pList
|
||||
* die am Ende anzuhaengende Liste vom Typ List<ContentType>
|
||||
*/
|
||||
public void concat(List<ContentType> pList) {
|
||||
if (pList != this && pList != null && !pList.isEmpty()) { // Nichts tun,
|
||||
// wenn pList und this identisch, pList leer oder nicht existent.
|
||||
|
||||
if (this.isEmpty()) { // Fall: An leere Liste anfuegen.
|
||||
this.first = pList.first;
|
||||
this.last = pList.last;
|
||||
} else { // Fall: An nicht-leere Liste anfuegen.
|
||||
this.last.setNextNode(pList.first);
|
||||
this.last = pList.last;
|
||||
}
|
||||
|
||||
// Liste pList loeschen.
|
||||
pList.first = null;
|
||||
pList.last = null;
|
||||
pList.current = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wenn die Liste leer ist oder es kein aktuelles Objekt gibt (hasAccess()
|
||||
* == false), geschieht nichts.<br />
|
||||
* Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das
|
||||
* aktuelle Objekt geloescht und das Objekt hinter dem geloeschten Objekt
|
||||
* wird zum aktuellen Objekt. <br />
|
||||
* Wird das Objekt, das am Ende der Liste steht, geloescht, gibt es kein
|
||||
* aktuelles Objekt mehr.
|
||||
*/
|
||||
public void remove() {
|
||||
// Nichts tun, wenn es kein aktuelle Element gibt oder die Liste leer ist.
|
||||
if (this.hasAccess() && !this.isEmpty()) {
|
||||
|
||||
if (current == first) {
|
||||
first = first.getNextNode();
|
||||
} else {
|
||||
ListNode previous = this.getPrevious(current);
|
||||
if (current == last) {
|
||||
last = previous;
|
||||
}
|
||||
previous.setNextNode(current.getNextNode());
|
||||
}
|
||||
|
||||
ListNode temp = current.getNextNode();
|
||||
current.setContentObject(null);
|
||||
current.setNextNode(null);
|
||||
current = temp;
|
||||
|
||||
//Beim loeschen des letzten Elements last auf null setzen.
|
||||
if (this.isEmpty()) {
|
||||
last = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert den Vorgaengerknoten des Knotens pNode. Ist die Liste leer, pNode
|
||||
* == null, pNode nicht in der Liste oder pNode der erste Knoten der Liste,
|
||||
* wird null zurueckgegeben.
|
||||
*
|
||||
* @param pNode
|
||||
* der Knoten, dessen Vorgaenger zurueckgegeben werden soll
|
||||
* @return der Vorgaenger des Knotens pNode oder null, falls die Liste leer ist,
|
||||
* pNode == null ist, pNode nicht in der Liste ist oder pNode der erste Knoten
|
||||
* der Liste ist
|
||||
*/
|
||||
private ListNode getPrevious(ListNode pNode) {
|
||||
if (pNode != null && pNode != first && !this.isEmpty()) {
|
||||
ListNode temp = first;
|
||||
while (temp != null && temp.getNextNode() != pNode) {
|
||||
temp = temp.getNextNode();
|
||||
}
|
||||
return temp;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package schule.ngb.zm.util.abi;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Klasse QueryResult
|
||||
* </p>
|
||||
* <p>
|
||||
* Ein Objekt der Klasse QueryResult stellt die Ergebnistabelle einer Datenbankanfrage mit Hilfe
|
||||
* der Klasse DatabaseConnector dar. Objekte dieser Klasse werden nur von der Klasse DatabaseConnector erstellt.
|
||||
* Die Klasse verfuegt ueber keinen oeffentlichen Konstruktor.
|
||||
* </p>
|
||||
*
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version 2015-01-31
|
||||
*/
|
||||
public class QueryResult{
|
||||
private String[][] data;
|
||||
private String[] columnNames;
|
||||
private String[] columnTypes;
|
||||
|
||||
/**
|
||||
* Paketinterner Konstruktor.
|
||||
*/
|
||||
QueryResult(String[][] pData, String[] pColumnNames, String[] pColumnTypes){
|
||||
data = pData;
|
||||
columnNames = pColumnNames;
|
||||
columnTypes = pColumnTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert die Eintraege der Ergebnistabelle als zweidimensionales Feld
|
||||
* vom Typ String. Der erste Index des Feldes stellt die Zeile und der zweite die
|
||||
* Spalte dar (d.h. Object[zeile][spalte]).
|
||||
*/
|
||||
public String[][] getData(){
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert die Bezeichner der Spalten der Ergebnistabelle als Feld vom
|
||||
* Typ String zurueck.
|
||||
*/
|
||||
public String[] getColumnNames(){
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert die Typenbezeichnung der Spalten der Ergebnistabelle als Feld
|
||||
* vom Typ String zurueck. Die Bezeichnungen entsprechen den Angaben in der MySQL-Datenbank.
|
||||
*/
|
||||
public String[] getColumnTypes(){
|
||||
return columnTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert die Anzahl der Zeilen der Ergebnistabelle als Integer.
|
||||
*/
|
||||
public int getRowCount(){
|
||||
if (data != null )
|
||||
return data.length;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert die Anzahl der Spalten der Ergebnistabelle als Integer.
|
||||
*/
|
||||
public int getColumnCount(){
|
||||
if (data != null && data.length > 0 && data[0] != null)
|
||||
return data[0].length;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
package schule.ngb.zm.util.abi;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Generische Klasse Queue<ContentType>
|
||||
* </p>
|
||||
* <p>
|
||||
* Objekte der generischen Klasse Queue (Warteschlange) verwalten beliebige
|
||||
* Objekte vom Typ ContentType nach dem First-In-First-Out-Prinzip, d.h., das
|
||||
* zuerst abgelegte Objekt wird als erstes wieder entnommen. Alle Methoden haben
|
||||
* eine konstante Laufzeit, unabhaengig von der Anzahl der verwalteten Objekte.
|
||||
* </p>
|
||||
*
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version Generisch_02 2014-02-21
|
||||
*/
|
||||
public class Queue<ContentType> {
|
||||
|
||||
/* --------- Anfang der privaten inneren Klasse -------------- */
|
||||
|
||||
private class QueueNode {
|
||||
|
||||
private ContentType content = null;
|
||||
private QueueNode nextNode = null;
|
||||
|
||||
/**
|
||||
* Ein neues Objekt vom Typ QueueNode<ContentType> wird erschaffen.
|
||||
* Der Inhalt wird per Parameter gesetzt. Der Verweis ist leer.
|
||||
*
|
||||
* @param pContent das Inhaltselement des Knotens vom Typ ContentType
|
||||
*/
|
||||
public QueueNode(ContentType pContent) {
|
||||
content = pContent;
|
||||
nextNode = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Verweis wird auf das Objekt, das als Parameter uebergeben wird,
|
||||
* gesetzt.
|
||||
*
|
||||
* @param pNext der Nachfolger des Knotens
|
||||
*/
|
||||
public void setNext(QueueNode pNext) {
|
||||
nextNode = pNext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert das naechste Element des aktuellen Knotens.
|
||||
*
|
||||
* @return das Objekt vom Typ QueueNode, auf das der aktuelle Verweis zeigt
|
||||
*/
|
||||
public QueueNode getNext() {
|
||||
return nextNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert das Inhaltsobjekt des Knotens vom Typ ContentType.
|
||||
*
|
||||
* @return das Inhaltsobjekt des Knotens
|
||||
*/
|
||||
public ContentType getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ----------- Ende der privaten inneren Klasse -------------- */
|
||||
|
||||
private QueueNode head;
|
||||
private QueueNode tail;
|
||||
|
||||
/**
|
||||
* Eine leere Schlange wird erzeugt.
|
||||
* Objekte, die in dieser Schlange verwaltet werden, muessen vom Typ
|
||||
* ContentType sein.
|
||||
*/
|
||||
public Queue() {
|
||||
head = null;
|
||||
tail = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert den Wert true, wenn die Schlange keine Objekte enthaelt,
|
||||
* sonst liefert sie den Wert false.
|
||||
*
|
||||
* @return true, falls die Schlange leer ist, sonst false
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return head == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Das Objekt pContentType wird an die Schlange angehaengt.
|
||||
* Falls pContentType gleich null ist, bleibt die Schlange unveraendert.
|
||||
*
|
||||
* @param pContent
|
||||
* das anzuhaengende Objekt vom Typ ContentType
|
||||
*/
|
||||
public void enqueue(ContentType pContent) {
|
||||
if (pContent != null) {
|
||||
QueueNode newNode = new QueueNode(pContent);
|
||||
if (this.isEmpty()) {
|
||||
head = newNode;
|
||||
tail = newNode;
|
||||
} else {
|
||||
tail.setNext(newNode);
|
||||
tail = newNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Das erste Objekt wird aus der Schlange entfernt.
|
||||
* Falls die Schlange leer ist, wird sie nicht veraendert.
|
||||
*/
|
||||
public void dequeue() {
|
||||
if (!this.isEmpty()) {
|
||||
head = head.getNext();
|
||||
if (this.isEmpty()) {
|
||||
head = null;
|
||||
tail = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert das erste Objekt der Schlange.
|
||||
* Die Schlange bleibt unveraendert.
|
||||
* Falls die Schlange leer ist, wird null zurueckgegeben.
|
||||
*
|
||||
* @return das erste Objekt der Schlange vom Typ ContentType oder null,
|
||||
* falls die Schlange leer ist
|
||||
*/
|
||||
public ContentType front() {
|
||||
if (this.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return head.getContent();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,359 @@
|
|||
package schule.ngb.zm.util.abi; /**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Klasse Server
|
||||
* </p>
|
||||
* <p>
|
||||
* Objekte von Unterklassen der abstrakten Klasse Server ermoeglichen das
|
||||
* Anbieten von Serverdiensten, so dass Clients Verbindungen zum Server mittels
|
||||
* TCP/IP-Protokoll aufbauen koennen. Zur Vereinfachung finden Nachrichtenversand
|
||||
* und -empfang zeilenweise statt, d. h., beim Senden einer Zeichenkette wird ein
|
||||
* Zeilentrenner ergaenzt und beim Empfang wird dieser entfernt.
|
||||
* Verbindungsannahme, Nachrichtenempfang und Verbindungsende geschehen
|
||||
* nebenlaeufig. Auf diese Ereignisse muss durch Ueberschreiben der entsprechenden
|
||||
* Ereignisbehandlungsmethoden reagiert werden. Es findet nur eine rudimentaere
|
||||
* Fehlerbehandlung statt, so dass z.B. Verbindungsabbrueche nicht zu einem
|
||||
* Programmabbruch fuehren. Einmal unterbrochene oder getrennte Verbindungen
|
||||
* koennen nicht reaktiviert werden.
|
||||
* </p>
|
||||
*
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version 30.08.2016
|
||||
*/
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
|
||||
public abstract class Server
|
||||
{
|
||||
private NewConnectionHandler connectionHandler;
|
||||
private List<ClientMessageHandler> messageHandlers;
|
||||
|
||||
private class NewConnectionHandler extends Thread
|
||||
{
|
||||
private ServerSocket serverSocket;
|
||||
private boolean active;
|
||||
|
||||
public NewConnectionHandler(int pPort)
|
||||
{
|
||||
try
|
||||
{
|
||||
serverSocket = new ServerSocket(pPort);
|
||||
start();
|
||||
active = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
serverSocket = null;
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
while (active)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Warten auf Verbdinungsversuch durch Client:
|
||||
Socket clientSocket = serverSocket.accept();
|
||||
// Eingehende Nachrichten vom neu verbundenen Client werden
|
||||
// in einem eigenen Thread empfangen:
|
||||
addNewClientMessageHandler(clientSocket);
|
||||
processNewConnection(clientSocket.getInetAddress().getHostAddress(),clientSocket.getPort());
|
||||
}
|
||||
|
||||
catch (IOException e)
|
||||
{
|
||||
/*
|
||||
* Kann keine Verbindung zum anfragenden Client aufgebaut werden,
|
||||
* geschieht nichts.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
active = false;
|
||||
if(serverSocket != null)
|
||||
try
|
||||
{
|
||||
serverSocket.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
/*
|
||||
* Befindet sich der ServerSocket im accept()-Wartezustand oder wurde
|
||||
* er bereits geschlossen, geschieht nichts.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ClientMessageHandler extends Thread
|
||||
{
|
||||
private ClientSocketWrapper socketWrapper;
|
||||
private boolean active;
|
||||
|
||||
private class ClientSocketWrapper
|
||||
{
|
||||
private Socket clientSocket;
|
||||
private BufferedReader fromClient;
|
||||
private PrintWriter toClient;
|
||||
|
||||
public ClientSocketWrapper(Socket pSocket)
|
||||
{
|
||||
try
|
||||
{
|
||||
clientSocket = pSocket;
|
||||
toClient = new PrintWriter(clientSocket.getOutputStream(), true);
|
||||
fromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
clientSocket = null;
|
||||
toClient = null;
|
||||
fromClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
public String receive()
|
||||
{
|
||||
if(fromClient != null)
|
||||
try
|
||||
{
|
||||
return fromClient.readLine();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
}
|
||||
return(null);
|
||||
}
|
||||
|
||||
public void send(String pMessage)
|
||||
{
|
||||
if(toClient != null)
|
||||
{
|
||||
toClient.println(pMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public String getClientIP()
|
||||
{
|
||||
if(clientSocket != null)
|
||||
return(clientSocket.getInetAddress().getHostAddress());
|
||||
else
|
||||
return(null); //Gemaess Java-API Rueckgabe bei nicht-verbundenen Sockets
|
||||
}
|
||||
|
||||
public int getClientPort()
|
||||
{
|
||||
if(clientSocket != null)
|
||||
return(clientSocket.getPort());
|
||||
else
|
||||
return(0); //Gemaess Java-API Rueckgabe bei nicht-verbundenen Sockets
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
if(clientSocket != null)
|
||||
try
|
||||
{
|
||||
clientSocket.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
/*
|
||||
* Falls eine Verbindung getrennt werden soll, deren Endpunkt
|
||||
* nicht mehr existiert bzw. ihrerseits bereits beendet worden ist,
|
||||
* geschieht nichts.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ClientMessageHandler(Socket pClientSocket)
|
||||
{
|
||||
socketWrapper = new ClientSocketWrapper(pClientSocket);
|
||||
if(pClientSocket!=null)
|
||||
{
|
||||
start();
|
||||
active = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
String message = null;
|
||||
while (active)
|
||||
{
|
||||
message = socketWrapper.receive();
|
||||
if (message != null)
|
||||
processMessage(socketWrapper.getClientIP(), socketWrapper.getClientPort(), message);
|
||||
else
|
||||
{
|
||||
ClientMessageHandler aMessageHandler = findClientMessageHandler(socketWrapper.getClientIP(), socketWrapper.getClientPort());
|
||||
if (aMessageHandler != null)
|
||||
{
|
||||
aMessageHandler.close();
|
||||
removeClientMessageHandler(aMessageHandler);
|
||||
processClosingConnection(socketWrapper.getClientIP(), socketWrapper.getClientPort());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void send(String pMessage)
|
||||
{
|
||||
if(active)
|
||||
socketWrapper.send(pMessage);
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
if(active)
|
||||
{
|
||||
active=false;
|
||||
socketWrapper.close();
|
||||
}
|
||||
}
|
||||
|
||||
public String getClientIP()
|
||||
{
|
||||
return(socketWrapper.getClientIP());
|
||||
}
|
||||
|
||||
public int getClientPort()
|
||||
{
|
||||
return(socketWrapper.getClientPort());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Server(int pPort)
|
||||
{
|
||||
connectionHandler = new NewConnectionHandler(pPort);
|
||||
messageHandlers = new List<ClientMessageHandler>();
|
||||
}
|
||||
|
||||
public boolean isOpen()
|
||||
{
|
||||
return(connectionHandler.active);
|
||||
}
|
||||
|
||||
public boolean isConnectedTo(String pClientIP, int pClientPort)
|
||||
{
|
||||
ClientMessageHandler aMessageHandler = findClientMessageHandler(pClientIP, pClientPort);
|
||||
if (aMessageHandler != null)
|
||||
return(aMessageHandler.active);
|
||||
else
|
||||
return(false);
|
||||
}
|
||||
|
||||
public void send(String pClientIP, int pClientPort, String pMessage)
|
||||
{
|
||||
ClientMessageHandler aMessageHandler = this.findClientMessageHandler(pClientIP, pClientPort);
|
||||
if (aMessageHandler != null)
|
||||
aMessageHandler.send(pMessage);
|
||||
}
|
||||
|
||||
public void sendToAll(String pMessage)
|
||||
{
|
||||
synchronized(messageHandlers)
|
||||
{
|
||||
messageHandlers.toFirst();
|
||||
while (messageHandlers.hasAccess())
|
||||
{
|
||||
messageHandlers.getContent().send(pMessage);
|
||||
messageHandlers.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void closeConnection(String pClientIP, int pClientPort)
|
||||
{
|
||||
ClientMessageHandler aMessageHandler = findClientMessageHandler(pClientIP, pClientPort);
|
||||
if (aMessageHandler != null)
|
||||
{
|
||||
processClosingConnection(pClientIP, pClientPort);
|
||||
aMessageHandler.close();
|
||||
removeClientMessageHandler(aMessageHandler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
connectionHandler.close();
|
||||
|
||||
synchronized(messageHandlers)
|
||||
{
|
||||
ClientMessageHandler aMessageHandler;
|
||||
messageHandlers.toFirst();
|
||||
while (messageHandlers.hasAccess())
|
||||
{
|
||||
aMessageHandler = messageHandlers.getContent();
|
||||
processClosingConnection(aMessageHandler.getClientIP(), aMessageHandler.getClientPort());
|
||||
aMessageHandler.close();
|
||||
messageHandlers.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public abstract void processNewConnection(String pClientIP, int pClientPort);
|
||||
|
||||
public abstract void processMessage(String pClientIP, int pClientPort, String pMessage);
|
||||
|
||||
public abstract void processClosingConnection(String pClientIP, int pClientPort);
|
||||
|
||||
private void addNewClientMessageHandler(Socket pClientSocket)
|
||||
{
|
||||
synchronized(messageHandlers)
|
||||
{
|
||||
messageHandlers.append(new ClientMessageHandler(pClientSocket));
|
||||
}
|
||||
}
|
||||
|
||||
private void removeClientMessageHandler(ClientMessageHandler pClientMessageHandler)
|
||||
{
|
||||
synchronized(messageHandlers)
|
||||
{
|
||||
messageHandlers.toFirst();
|
||||
while (messageHandlers.hasAccess())
|
||||
{
|
||||
if (pClientMessageHandler == messageHandlers.getContent())
|
||||
{
|
||||
messageHandlers.remove();
|
||||
return;
|
||||
}
|
||||
else
|
||||
messageHandlers.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ClientMessageHandler findClientMessageHandler(String pClientIP, int pClientPort)
|
||||
{
|
||||
synchronized(messageHandlers)
|
||||
{
|
||||
ClientMessageHandler aMessageHandler;
|
||||
messageHandlers.toFirst();
|
||||
|
||||
while (messageHandlers.hasAccess())
|
||||
{
|
||||
aMessageHandler = messageHandlers.getContent();
|
||||
if (aMessageHandler.getClientIP().equals(pClientIP) && aMessageHandler.getClientPort() == pClientPort)
|
||||
return (aMessageHandler);
|
||||
messageHandlers.next();
|
||||
}
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
package schule.ngb.zm.util.abi;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Generische Klasse Stack<ContentType>
|
||||
* </p>
|
||||
* <p>
|
||||
* Objekte der generischen Klasse Stack (Keller, Stapel) verwalten beliebige
|
||||
* Objekte vom Typ ContentType nach dem Last-In-First-Out-Prinzip, d.h., das
|
||||
* zuletzt abgelegte Objekt wird als erstes wieder entnommen. Alle Methoden
|
||||
* haben eine konstante Laufzeit, unabhaengig von der Anzahl der verwalteten
|
||||
* Objekte.
|
||||
* </p>
|
||||
*
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version Generisch_02 2014-02-21
|
||||
*/
|
||||
public class Stack<ContentType> {
|
||||
|
||||
/* --------- Anfang der privaten inneren Klasse -------------- */
|
||||
|
||||
private class StackNode {
|
||||
|
||||
private ContentType content = null;
|
||||
private StackNode nextNode = null;
|
||||
|
||||
/**
|
||||
* Ein neues Objekt vom Typ StackNode<ContentType> wird erschaffen. <br />
|
||||
* Der Inhalt wird per Parameter gesetzt. Der Verweis ist leer.
|
||||
*
|
||||
* @param pContent der Inhalt des Knotens
|
||||
*/
|
||||
public StackNode(ContentType pContent) {
|
||||
content = pContent;
|
||||
nextNode = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Verweis wird auf das Objekt, das als Parameter uebergeben wird,
|
||||
* gesetzt.
|
||||
*
|
||||
* @param pNext der Nachfolger des Knotens
|
||||
*/
|
||||
public void setNext(StackNode pNext) {
|
||||
nextNode = pNext;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return das Objekt, auf das der aktuelle Verweis zeigt
|
||||
*/
|
||||
public StackNode getNext() {
|
||||
return nextNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return das Inhaltsobjekt vom Typ ContentType
|
||||
*/
|
||||
public ContentType getContent() {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------- Ende der privaten inneren Klasse -------------- */
|
||||
|
||||
private StackNode head;
|
||||
|
||||
/**
|
||||
* Ein leerer Stapel wird erzeugt. Objekte, die in diesem Stapel verwaltet
|
||||
* werden, muessen vom Typ ContentType sein.
|
||||
*/
|
||||
public Stack() {
|
||||
head = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert den Wert true, wenn der Stapel keine Objekte
|
||||
* enthaelt, sonst liefert sie den Wert false.
|
||||
*
|
||||
* @return true, falls der Stapel leer ist, sonst false
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return (head == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Das Objekt pContentType wird oben auf den Stapel gelegt. Falls
|
||||
* pContentType gleich null ist, bleibt der Stapel unveraendert.
|
||||
*
|
||||
* @param pContent
|
||||
* das einzufuegende Objekt vom Typ ContentType
|
||||
*/
|
||||
public void push(ContentType pContent) {
|
||||
if (pContent != null) {
|
||||
StackNode node = new StackNode(pContent);
|
||||
node.setNext(head);
|
||||
head = node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Das zuletzt eingefuegte Objekt wird von dem Stapel entfernt. Falls der
|
||||
* Stapel leer ist, bleibt er unveraendert.
|
||||
*/
|
||||
public void pop() {
|
||||
if (!isEmpty()) {
|
||||
head = head.getNext();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert das oberste Stapelobjekt. Der Stapel bleibt
|
||||
* unveraendert. Falls der Stapel leer ist, wird null zurueckgegeben.
|
||||
*
|
||||
* @return das oberste Stackelement vom Typ ContentType oder null, falls
|
||||
* der Stack leer ist
|
||||
*/
|
||||
public ContentType top() {
|
||||
if (!this.isEmpty()) {
|
||||
return head.getContent();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package schule.ngb.zm.util.abi;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||
* </p>
|
||||
* <p>
|
||||
* Klasse Vertex
|
||||
* </p>
|
||||
* <p>
|
||||
* Die Klasse Vertex stellt einen einzelnen Knoten eines Graphen dar. Jedes Objekt
|
||||
* dieser Klasse verfuegt ueber eine im Graphen eindeutige ID als String und kann diese
|
||||
* ID zurueckliefern. Darueber hinaus kann eine Markierung gesetzt und abgefragt werden.
|
||||
* </p>
|
||||
*
|
||||
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||
* @version Oktober 2015
|
||||
*/
|
||||
public class Vertex{
|
||||
//Einmalige ID des Knotens und Markierung
|
||||
private String id;
|
||||
private boolean mark;
|
||||
|
||||
/**
|
||||
* Ein neues Objekt vom Typ Vertex wird erstellt. Seine Markierung hat den Wert false.
|
||||
*/
|
||||
public Vertex(String pID){
|
||||
id = pID;
|
||||
mark = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert die ID des Knotens als String.
|
||||
*/
|
||||
public String getID(){
|
||||
return new String(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Auftrag setzt die Markierung des Knotens auf den Wert pMark.
|
||||
*/
|
||||
public void setMark(boolean pMark){
|
||||
mark = pMark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Anfrage liefert true, wenn die Markierung des Knotens den Wert true hat, ansonsten false.
|
||||
*/
|
||||
public boolean isMarked(){
|
||||
return mark;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue