2.4 Listenpräfix
Ein Array erlaubt es uns, auf das Element
#include <stdio.h>
int main () {
char *name = "psarallel algorithms";
printf("%cn", *(name + 7)); // statt printf("%cn", name[7]);
int primes[7] = {2,3,5,7,11,13,17};
printf("%dn", *(primes + 5)); // statt printf("%dn", primes[5]);
}
Arrays erlauben also Zugriff in konstanter Zeit, haben allerdings andere Nachteile.
So können wir in Arrays nicht an Stelle
Ein Datentyp, der effizientes Löschen und Einfügen unterstützt ist die verkettete Liste, auf Englisch linked list. Ein Element besteht aus einem Datensatz und einem Zeiger auf das nächste Element. Das stellen wir gerne graphisch dar:
Diese Darstellung kann leicht irreführend sein, weil sie "zu übersichtlich" ist. In der Wirklichkeit eines Rechnerspeichers sieht es eher so aus:
Wir wollen nun auch auf solchen verketteten Listen schnell parallel Präfixsummen berechnen.
Sei also
enthält. Sicherlich haben Sie gemerkt: wir summieren hier von
Wir führen die Konvention ein, dass die Liste mit einer
Unsere Liste hat nun also
Die Lage sieht also eher so aus:
Beachten Sie, dass in der ersten Zeile Adressen und in der zweiten Zeile Werte
stehen. In unserer Vorstellung kann jede Speicherzelle
Pointer Jumping
Der erste Algorithmus, den wir untersuchen werden, verwendet ein als Pointer Jumping
bekanntes Prinzip. Wir ordnen jeder Speicherzelle einen Prozessor zu. Wir haben also insgesamt
Wir illustrieren diesen Algorithmus anhand des obigen Beispiels:
Überzeugen Sie sich, dass dies tatsächlich die korrekten Werte sind. Wie analysieren wir diesen
Algorithmus? Wir betrachten für die "Länge" des Pointers
Rechnermodell?
Sie haben vielleicht schon bemerkt: der Schritt Schaue an gegebener Speicheradresse nach und tu dann dies und das passt nicht in unsere bisherige Schaltkreis-Metapher. Die greift nur, so lange die "Adressen" von vornherein feststehen und nicht von den Input-Daten selbst abhängen. Wir haben nun ein neues Modell, in welchem der Input in einem gemeinsamen Speicher liegt, und jeder Prozessor kann in konstanter Zeit auf eine Speicherzelle lesend oder schreibend zugreifen. Dieses Modell ist flexibler als das Schaltkreis-Modell des letzten Teilkapitels, allerdings auch schwieriger exakt zu definieren. Hierfür nehmen wir uns im nächsten Kapitel Zeit.