Prof. Franz Schweiggert Abteilung Angewandte Informationsverarbeitung 6. Dezember 2004
Christian Ehrhardt Blatt 7


Uni Logo



Allgemeine Informatik 3 (WS 2004/2005)


Abgabetermin 21.12.2004

Priority Queue (20 Punkte)

Eine Priority Queue ist eine Datenstruktur, die die folgenden Operationen (in effizienter Weise) erlaubt:
INSERT
Ein (im allgemeinen beliebiges) Objekt wird zu der Datenstruktur hinzugefügt. Dabei wird zusätzlich eine positive Zahl - die Priorität des Elements - angegeben.
GET
Bei dieser Operation wird das Element mit der höchsten Priorität aus der Datenstruktur entfernt und zurückgeliefert.
EMPTY
Diese Operation liefert TRUE, wenn keine Elemente in der Priority Queue sind.
Das Ganze funktioniert also fast wie eine normale Queue oder wie ein Stack: Man kann Elemente einfügen und wieder entfernen. Allerdings werden die Elemente bei einer normalen Queue genau in der Reihenfolge entfernt, wie sie eingefügt wurden, und bei einem Stack wird das Element, das zuletzt eingefügt wurde zuerst entfernt. Bei einer Priority Queue wird dagegen immer das Element mit der zur Zeit höchsten Priorität entfernt.
In diesem Blatt sollen verschiedene Implementierungen einer solchen Datenstruktur im gleichen Programm implementiert, parallel zueinander verwendet und verglichen werden. Dabei soll das Programm sinnvoll in verschiedene Module aufgeteilt werden.
Der Einfachheit halber sind die eingefügten Elemente in diesem Blatt nur ganze Zahlen und der Wert der Zahl ist gleichzeitig die Priorität.

Zwei Implementierungen

Ein Array als Priority Queue

Bei dieser Implementierung werden die eingefügten Elemente in einem (dynamisch wachsenden!) Array unsortiert gespeichert. Neu hinzukommende Elemente werden am Ende angefügt, das Element mit der höchsten Priorität muß bei GET erst gesucht werden. Beim Entfernen eines Elements aus dem Array kann der frei werdende Platz einfach mit dem letzten Eintrag im Array aufgefüllt werden.

Eine sortierte Liste als Priority Queue

Bei dieser Variante werden alle Elemente in einer nach Priorität sortierten Liste verwaltet. GET nimmt einfach das erste Element der Liste. Bei INSERT muß der geeignete Platz in der Liste erst gesucht werden.

Zwei Module (6 Punkte)

Schreibt für die beiden vorgestellten Implementierungen je ein Modul, das eine Priority Queue entsprechend implementiert. Beide Implementierungen sollen gleichzeitig in einem einzigen Programm verwendet werden können. Testet Eure Implementierungen mit einem geeigneten Hauptprogramm.
Wie verhält sich bei den beiden Implementierungen der Aufwand für INSERT bzw. GET zur Anzahl der Elemente in der Queue.

Ein Interface (4 Punkte)

Jetzt sollen beide Implementierungen auf die gleiche Art und Weise verwendet werden können. Ob die Arrayimplementierung oder die Listenimplementierung verwendet wird, soll nur noch beim Erzeugen der Queue eine Rolle spielen. Bei den drei Operationen INSERT, GET und EMPTY soll dem Aufruf nicht mehr anzusehen sein, welche Implementierung verwendet wird. So könnte also ein Fragment des Hauptprogramms aussehen:

      /* Eine mit Hilfe eines Arrays implementierte
       * Priority Queue erzeugen.
       */
      q1 = array_priority_queue_create ();

      /* Eine weiter mit Hilfe einer Liste
       * implementierte Priority Queue erzeugen.
       */
      q2  = list_priority_queue_create ();

      /* Das Element 30 in die Queue q1 einfuegen. */
      insert (q1, 30);

      /* Das Element 10 in die Queue q2 einfuegen. */
      insert (q2, 10);

      /* Das Element mit der h"ochsten Priorit"at
       * aus der Queue q2 holen. ==> ret = 10
       */
      ret = get (q2);

      /* Das Element mit der h"ochsten Priorit"at
       * aus der Queue q1 holen. ==> ret = 30
       */
      ret = get (q1);

Die Funktionen array_priority_queue_create und list_priority_queue_create werden von der jeweiligen Implementierung zur Verfügung gestellt, insert, get und empty von dem neu geschriebenen Interface.
Hinweis: Funktionszeiger und Zeiger vom Typ void * können bei diesem Teil sehr nützlich sein.

Eine effiziente Implementierung (6 Punkte)

Wird eine wirklich effiziente Implementierung benötigt, so wird meinst ein etwas anderes Verfahren verwendet (N ist die Anzahl der Elemente, die Moment in der Priority Queue sind):

Schreibt ein weiteres Modul, das eine Priority Queue wie oben beschrieben implementiert und überlegt auch hier, wie sich der Aufwand für INSERT bzw. GET zur Anzahl der Elemente in der Queue verhält.
Anmerkung: Diese Datenstruktur wird in der Literatur in der Regel Heap genannt. Trotz der Namensgleichheit hat diese Datenstruktur aber nur wenig mit dem Begriff Heap zu tun, der im Zusammenhang mit Speicherverwaltung und malloc auftaucht.

Ein Makefile (4 Punkte)

Nachdem das gesamte Projekt jetzt aus ca. 4 Modulen und einem Hauptprogramm besteht, lohnt es sich, ein Makefile dafür zu schreiben. Eventuell ist es auch sinnvoll, diesen Teil der Aufgabe etwas früher anzupacken.



Christian Ehrhardt 2004-12-06