Kategoriearchiv: Programmierung

Mindstorm: Brainstorming mit Mindmaps – direkt im Browser, von überall

Mit Mindstorm gibt es von Capri Soft jetzt ein Mindmapping-Werkzeug, das komplett im Browser läuft – ohne Installation, auf jedem Gerät und mit deinen Mindmaps immer griffbereit. Du findest es unter mindstorm.capri-soft.de.

Warum Ideen eine Landkarte brauchen

Gute Ideen kommen selten der Reihe nach. Sie springen, verzweigen sich und hängen an Gedanken, die man vor zehn Minuten hatte. Eine Liste zwingt sie in eine Reihenfolge, die es gar nicht gibt. Eine Mindmap lässt sie so wachsen, wie sie entstehen: vom Kernthema in der Mitte nach außen, Ast für Ast.

Genau dafür ist Mindstorm gebaut. Der Aufbau ist dem bewährten Klassiker FreeMind nachempfunden. Das Wichtigste dabei: Eine Mindmap soll sich so schnell anlegen lassen, wie man denkt. Ein Tastendruck für einen neuen Gedanken, einfach lostippen, fertig.

Mindmapping als Brainstorming-Methode

Mindmapping hilft beim Brainstorming, weil es Ideen sichtbar verbindet statt sie nur zu sammeln. Bekannt gemacht hat die Methode der britische Autor Tony Buzan in den 1970er-Jahren. Seitdem gehört sie zum Standard in Schule, Studium, Projektarbeit und Workshops.

Warum es funktioniert

  • Assoziativ statt linear: Jeder Gedanke bekommt einen Platz neben dem, was ihn ausgelöst hat. So entstehen neue Ideen fast von selbst.
  • Überblick auf einen Blick: Das Kernthema steht in der Mitte, die Hauptaspekte strahlen davon aus. Man sieht sofort, wo viel und wo wenig gedacht wurde.
  • Keine Bewertung im ersten Schritt: Ein neuer Ast kostet nichts. Sortieren, zusammenfassen und streichen kommt später.
  • Ein Bild bleibt hängen: Farben und die räumliche Anordnung machen eine Mindmap leichter zu merken als eine Stichpunktliste.

So läuft ein Brainstorming mit Mindstorm ab

  1. Kernthema festlegen: Klicke auf „Neu“ und tippe die Frage oder das Thema in den Hauptknoten, zum Beispiel „Produktlaunch Herbst“.
  2. Hauptäste sammeln: Mit Tab legst du einen Ast an, mit Enter den nächsten daneben. Schreib alles auf, was dir einfällt, ohne zu bewerten.
  3. Ideen weiterspinnen: Zu jedem Ast entstehen Unteräste. Was zusammengehört, ziehst du einfach mit der Maus auf den passenden Ast.
  4. Verdichten: Klappe erledigte Bereiche mit der Leertaste ein, lösche Doppeltes und schiebe Wichtiges nach oben.
  5. Festhalten: Hinterlege zu einzelnen Knoten Notizen, Links oder Bilder. Am Ende kopierst du die Mindmap als Bild in dein Protokoll oder exportierst sie als Gliederung.

Tipp: Halte die Knoten kurz, ein bis drei Wörter reichen. Die Details gehören in die Notiz darunter, so bleibt die Karte übersichtlich.

Von überall verfügbar: deine Ideen sind da, wo du bist

Mindstorm läuft im Browser, und deine Mindmaps liegen in deinem Konto. Das heißt: Du brauchst nur eine Internetverbindung und einen Browser, egal ob am Schreibtisch, im Meeting oder unterwegs.

  • Keine Installation: Kein Download, kein Setup, keine Updates. Adresse aufrufen und loslegen, auch auf fremden Rechnern oder im Firmennetz ohne Adminrechte.
  • Jedes Gerät, jedes System: Windows, macOS, Linux, Tablet oder Smartphone. Wo ein aktueller Browser läuft, läuft Mindstorm.
  • Ein Konto für alles: Du meldest dich mit deinem Google-Konto an. Danach siehst du auf jedem Gerät sofort alle deine Mindmaps. Was du am Büro-PC angefangen hast, machst du abends auf dem Tablet weiter.
  • Automatisch gespeichert: Jede Änderung wird nach einem Augenblick gesichert. Es gibt keinen Speichern-Knopf, den man vergessen könnte.
  • Oder einfach als Gast: Wer sich nicht anmelden möchte, arbeitet als Gast. Die Mindmaps bleiben dann in diesem Browser auf diesem Gerät. Mit dem Häkchen „Auswahl merken“ fragt Mindstorm beim nächsten Besuch nicht mehr nach.
  • Weltweit in deiner Sprache: In Deutschland erscheint Mindstorm auf Deutsch, in allen anderen Ländern auf Englisch. Mit einem Klick lässt sich jederzeit umschalten.

Gerade beim Brainstorming ist das Gold wert: Ideen kommen nicht nur am Schreibtisch. Mit Mindstorm hältst du sie fest, wo sie entstehen, und findest sie später genau dort wieder, wo du weiterarbeiten willst.

Alle Features im Überblick

Mindstorm deckt den ganzen Weg ab, von der ersten Idee bis zum fertigen Bild im Protokoll.

Mindmaps anlegen und bearbeiten

  • Aufbau wie FreeMind: Hauptknoten in der Mitte, Äste nach links und rechts, geschwungene Verbindungslinien und eine eigene Farbe für jeden Hauptast.
  • Schnell per Tastatur: Tab für einen Unterknoten, Enter für einen Knoten daneben, einfach lostippen zum Bearbeiten. Mit den Pfeiltasten springst du zwischen den Knoten.
  • Auch ohne Tastatur: Ein +-Knopf am ausgewählten Knoten legt einen Unterknoten an. Ein Doppelklick auf die freie Fläche erzeugt einen neuen Hauptast.
  • Ziehen und ablegen: Knoten mit der Maus auf einen anderen ziehen hängt sie dort samt allen Unterästen ein.
  • Ein- und ausklappen: Mit der Leertaste klappst du Äste zu. Ein kleiner Kreis zeigt, wie viele Unterknoten darin stecken.
  • Mehrfachauswahl: Mit Strg– oder Shift-Klick markierst du mehrere Knoten und löschst sie mit Entf auf einmal.
  • Kopieren, Ausschneiden, Einfügen: Ganze Äste lassen sich mit Strg+C / X / V duplizieren und verschieben. Eingerückter Text aus anderen Programmen wird beim Einfügen automatisch zu Ästen.
  • Rückgängig und Wiederholen: Strg+Z und Strg+Y nehmen jeden Schritt zurück oder stellen ihn wieder her.
  • Feste Knotenbreite: Die Breite stellst du zwischen 160 und 380 Pixeln ein, oder du lässt sie automatisch anpassen.
  • Große Karten im Griff: Scrollleisten in beide Richtungen, Zoom per Strg+Mausrad oder Knöpfen und „Alles zeigen“ für den Gesamtüberblick.
  • Mehrere Mindmaps: Lege beliebig viele Mindmaps an und wechsle über die Auswahl oben zwischen ihnen. Der Titel ist automatisch der Text des Hauptknotens.

Notizen mit Text, Links und Bildern

  • Notizbereich unten: Klickst du einen Knoten an, erscheint unten seine Notiz. Den Bereich ziehst du größer oder kleiner, ein Doppelklick blendet ihn aus.
  • WYSIWYG-Editor: Überschriften, Fett, Kursiv, Unterstrichen, Durchgestrichen, Textfarbe, Aufzählungen, nummerierte Listen, Zitate, Code und Links.
  • HTML-Ansicht: Mit einem Klick auf „</> HTML“ bearbeitest du den Quelltext direkt.
  • Bilder einfügen und skalieren: Über den Bild-Knopf, per Einfügen aus der Zwischenablage oder durch Hineinziehen. Große Bilder werden automatisch verkleinert. Die Größe änderst du an der Ecke oder mit Klein, Mittel, Volle Breite und Original.
  • Notiz-Symbol: Knoten mit Notiz tragen ein kleines Symbol, damit nichts übersehen wird.

Import und Export

  • FreeMind-Dateien: Bestehende .mm-Dateien aus FreeMind oder Freeplane importierst du direkt, inklusive Notizen. Genauso exportierst du wieder als .mm.
  • Als Bild kopieren: Die ganze Mindmap landet als Bild in der Zwischenablage, bereit zum Einfügen in Word, PowerPoint oder eine E-Mail. Das Bild ist immer hell und gut lesbar, auch wenn du im dunklen Modus arbeitest.
  • Als PNG speichern: Dieselbe Grafik als Bilddatei, in doppelter Auflösung.
  • Gliederung (.md): Die Mindmap als eingerückte Liste mit Notizen, ideal für Protokolle und Wikis.
  • Sicherung (.json): Eine vollständige Kopie, die sich jederzeit wieder importieren lässt.

Darstellung und Sprache

  • Dunkler und heller Modus: Standardmäßig dunkel im Capri-Soft-Design, mit einem Klick auf Sonne oder Mond hell. Die Wahl wird gemerkt.
  • Deutsch und Englisch: Alle Texte gibt es in beiden Sprachen, automatisch passend zum Land oder per Knopf umgeschaltet.

Konto und Datenschutz

  • Anmeldung mit Google: Kein neues Passwort, keine Registrierung. Jede Mindmap ist nur für ihren Besitzer sichtbar.
  • Bilder privat: Auch eingefügte Bilder werden nur an dich ausgeliefert.
  • Gastmodus: Wer kein Konto nutzen möchte, speichert nur lokal im eigenen Browser.

Die wichtigsten Tastenkürzel

Auf dem Mac nimmst du statt Strg die Cmd-Taste.

TasteWirkung
Tab oder EinfgUnterknoten anlegen
EnterKnoten darunter anlegen (Shift+Enter: darüber)
Lostippen oder F2Text des Knotens ersetzen oder bearbeiten
Entf oder ⌫Markierte Knoten löschen
LeertasteAst ein- oder ausklappen
PfeiltastenZwischen Knoten wechseln
Strg+↑ / Strg+↓Knoten nach oben oder unten schieben
Strg+C / X / VKopieren, Ausschneiden, Einfügen
Strg+AAlle Knoten markieren
Strg+Z / Strg+YRückgängig, Wiederholen
Strg+MausradZoomen

Fazit: Brainstorming ohne Hürden

Mindstorm verbindet die bewährte Mindmap-Methode mit einem Werkzeug, das überall bereitsteht. Keine Installation, kein Gerätewechsel-Chaos, keine verlorenen Ideen: Du öffnest den Browser, meldest dich an und arbeitest genau dort weiter, wo du aufgehört hast. Und wenn es schnell gehen muss, startest du einfach als Gast.

Probier es aus: mindstorm.capri-soft.de

Fragen, Ideen oder Wünsche für neue Funktionen? Schreib sie gern in die Kommentare.

Web DAW – Die browserbasierte DAW

Ein Song entsteht selten an einem einzigen Rechner. Der Groove kommt vom Drummer, die Bassline vom Bassisten, der Gesang aus einem dritten Wohnzimmer. Genau dafür habe ich Web DAW gebaut: eine Digital Audio Workstation, die komplett im Browser läuft. Niemand muss etwas installieren, kaufen oder einrichten, um an einem gemeinsamen Musikprojekt mitzuarbeiten.

Die Idee ist einfach: Ich lege ein Projekt an und gebe es weiter. Wer es bekommt, öffnet es im Browser, hört, was schon da ist, und nimmt seinen Teil dazu auf. Dann reicht er es an den Nächsten weiter. So wächst ein Song Spur für Spur, egal wo die Beteiligten sitzen und welchen Rechner sie haben.

Das Problem: Zusammenarbeit scheitert oft an der Software

Wer schon einmal mit anderen Musikern an einem Song gearbeitet hat, kennt die Hürden:

  • Unterschiedliche DAWs: Der eine arbeitet mit Cubase, die andere mit Logic, der Dritte mit Ableton. Projektdateien lassen sich untereinander nicht öffnen.
  • Installation und Lizenzen: Eine vollwertige DAW kostet Geld, braucht Speicherplatz und oft Administratorrechte. Auf dem Firmenlaptop oder im Proberaum-PC geht das nicht mal eben.
  • Plugins und Versionen: Fehlt beim Gegenüber ein Plugin oder die passende Version, klingt das Projekt plötzlich anders – oder lässt sich gar nicht laden.
  • Dateichaos: Am Ende werden einzelne WAV-Dateien per Mail verschickt, jemand muss sie von Hand an die richtige Stelle legen, und niemand weiß mehr, welche Version die aktuelle ist.

Das Ergebnis: Viele gute Ideen bleiben als Handy-Sprachmemo liegen, weil der technische Aufwand größer ist als die Lust aufs Musikmachen.

Die Idee: Ein Projekt, das von Hand zu Hand wandert

Web DAW braucht nur einen aktuellen Browser – am besten Chrome oder Edge – und eine Internetadresse: webdaw.de. Das Audio-Interface wird direkt im Browser erkannt, die Aufnahme läuft lokal auf dem eigenen Rechner. Nichts wird installiert, nichts muss freigeschaltet werden.

Das Herzstück für die Zusammenarbeit ist die Projektdatei. Ein Klick auf „Speichern“ packt alles in eine einzige ZIP-Datei:

  • alle Spuren mit Lautstärke, Panorama, EQ- und Effekt-Einstellungen,
  • jede Audioaufnahme verlustfrei als WAV-Datei,
  • jeden MIDI-Part als Standard-MIDI-Datei, dazu die Einstellungen der Instrumente,
  • Tempo, Locatoren und Ansicht.

Diese eine Datei schicke ich per Mail, Messenger oder Cloud-Ordner weiter. Wer sie öffnet, sieht und hört das Projekt genau so, wie ich es gespeichert habe – und kann sofort seine eigene Spur dazulegen. Weil die Klangerzeuger und Effekte Teil von Web DAW sind, gibt es keine fehlenden Plugins und keine Versionskonflikte.

So läuft die Zusammenarbeit in der Praxis

Zusammenarbeit mit Web DAW: vier Stationen, eine ZIP-Datei

Zwischen den Stationen wandert nur die Projektdatei, und jede Station braucht nichts außer dem Browser. Wer später noch eine Gitarre oder ein Synth-Pad ergänzen möchte, steigt einfach in die nächste Runde ein. Die MIDI-Parts lassen sich bei Bedarf auch in Cubase oder einer anderen DAW weiterverwenden.

Was Web DAW heute schon kann

Web DAW orientiert sich bewusst an der Arbeitsweise von Cubase, damit sich erfahrene Musiker sofort zurechtfinden.

BereichFunktionen
AufnahmeMono- und Stereospuren über das Audio-Interface, Overdub während die anderen Spuren laufen, automatischer Latenzausgleich, Metronom
ArrangementTimeline mit Takten, Locatoren und Cycle, Clips und Parts verschieben, kopieren, duplizieren, Mehrfachauswahl per Rahmen
Audio-BearbeitungClips nicht-destruktiv kürzen, Schnitte auf Nulldurchgängen, Fade-in und Fade-out
InstrumenteWebSynth mit 8 Oszillatoren, DrumSynth mit Kick, Snare, Clap, HiHat und Becken
MIDIKey-Editor mit Raster, Quantisierung und Anschlagstärke, Drum-Noten als Rauten
MixerKanäle mit Fader, Panorama, Mute/Solo, 4-Band-EQ, Inserts (Reverb, Delay, Compressor, Distortion)
ProjekteSpeichern und Laden als ZIP mit WAV- und MIDI-Dateien, Mixdown als WAV

Ehrlich gesagt: Was noch nicht geht

Web DAW ist ein junges Projekt, und ich möchte keine falschen Erwartungen wecken:

  • Kein gleichzeitiges Arbeiten: Zusammengearbeitet wird nacheinander, indem die Projektdatei geteilt (Button „Teilen“) oder weitergegeben wird. Zwei Leute können nicht live im selben Projekt sitzen.
  • Kein automatisches Speichern: Das Projekt liegt nur im Browser-Tab. Wer nicht speichert, verliert beim Schließen seine Arbeit.
  • Kein Cycle-Recording: Beim Aufnehmen läuft die Aufnahme linear durch, mehrere Takes pro Durchlauf gibt es noch nicht.
  • Keine fremden Plugins: Effekte und Instrumente sind fest eingebaut. Dafür klingt jedes Projekt bei allen gleich.
  • Browser: Am zuverlässigsten läuft Web DAW in Chrome und Edge, und nur über eine sichere Verbindung (https).
  • Betriebssystem: Ich habe mehrere Rechner und die Latenz scheint auf einem Apple-Gerät am geringsten zu sein.

Gerade das gleichzeitige Arbeiten steht ganz oben auf meiner Liste: Ein gemeinsamer Projektraum, in dem neue Spuren der anderen automatisch auftauchen, wäre der nächste große Schritt. Dazu kommen MIDI-Keyboards zum Einspielen und eine Wiederherstellung nach einem Absturz.

Ausprobieren und mitmachen

Web DAW läuft unter webdaw.de – einfach öffnen, „Audio starten“ klicken und loslegen. Am besten schnappst du dir gleich einen Bandkollegen: Leg einen Groove an, speichere das Projekt und schick es weiter. Dann sieh zu, wie dein Song mit jeder Runde wächst.

Mich interessiert, wie ihr Web DAW nutzt und was euch beim gemeinsamen Musikmachen fehlt. Schreibt es mir in die Kommentare – die nächsten Funktionen entstehen genau aus diesem Feedback.

Beerthrower Professional (3D-Spiel im Browser)

Intention

Das ist eine Spinnerei, die ich schon länger hatte. Ein Bayer in einem Festzelt schiebt ein Bier über den Tisch und am Ende muss es einem anderem Bayer in den Mund kippen. Hier nun als 3D-Spiel im Browser.

Spiel

Am Besten klickt ihr rechts unten im Spielebreich auf die Vollbild-Taste und spielt es an einem Desktop-Computer.

https://www.capri-soft.de/beerthrower

Video

Geräte identifizieren über Web Audio API / Audio-Fingerprint / Nutzer identifizieren über Audiosignal / AliExpress-Methode zur Geräteidentifikation

Intention

Dieser Artikel zeigt einen Beispielcode um über die Web Audio API den Fingerprint eines Gerätes zu identifzieren. Bitte beachten Sie, dass die Identifikation nicht mit den Richtlinien der DSGVO-konform ist, daher sollte sie nur zu lokalen Testzwecken genutzt werden.

Ich wurde durch den folgenden Heise-Artikel auf das Audio-Fingerprinting aufmerksam:

https://www.heise.de/news/AliExpress-trackt-Nutzer-via-unhoerbarem-Audio-Fingerprinting-11424127.html

Grundidee: Was wir messen

Wir nutzen die Web Audio API, um:

  • ein synthetisches Signal zu erzeugen (Oszillator),
  • es durch einen DynamicsCompressorNode zu schicken,
  • das Ergebnis in einem OfflineAudioContext zu rendern,
  • aus dem fertigen Audiopuffer einen Zahlwert zu berechnen, der vom Gerät abhängt.

Dieser Zahlwert ist der Audio-Fingerprint für das Gerät und kann genutzt werden um das Geräte eindeutig zu identifizieren.

Warum das pro Gerät anders ist

  • Floating‑Point‑Arithmetik unterscheidet sich je nach CPU/Instruction‑Set.
  • Browser‑Engine (Chromium, Gecko, WebKit) implementiert DSP leicht unterschiedlich.
  • Audio‑Stack des OS kann Einfluss haben, je nach Implementierung.

Das Ergebnis: derselbe Code → auf Rechner A ein anderer Wert als auf Rechner B, aber bei Rechner A stabil über viele Aufrufe.

Code

<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="utf-8" />
  <title>Audio-Fingerprint Test (OfflineAudioContext)</title>
  <style>
    body { font-family: system-ui, sans-serif; margin: 2rem; }
    button { padding: 0.5rem 1rem; font-size: 1rem; }
    #result { margin-top: 1rem; font-family: monospace; }
  </style>
</head>
<body>
  <h1>Audio-Fingerprint Test</h1>
  <p>
    Diese Seite erzeugt einen <strong>OfflineAudioContext</strong>, rendert ein festes Signal
    und berechnet daraus einen Fingerprint-Wert. Es wird <strong>kein Ton abgespielt</strong>
    und <strong>keine Daten übertragen</strong.
  </p>

  <button id="run">Fingerprint berechnen</button>
  <div id="result"></div>

  <script>
    async function getAudioFingerprint() {
      // 1 Kanal, 5000 Frames, 44100 Hz
      const sampleRate = 44100;
      const length = 5000;
      const offlineCtx = new OfflineAudioContext(1, length, sampleRate);

      // Oszillator als Testsignal
      const osc = offlineCtx.createOscillator();
      osc.type = 'triangle';
      osc.frequency.value = 10000; // 10 kHz

      // DynamicsCompressor verstärkt Floating-Point-Unterschiede
      const comp = offlineCtx.createDynamicsCompressor();
      comp.threshold.value = -24;
      comp.knee.value = 30;
      comp.ratio.value = 12;
      comp.attack.value = 0.003;
      comp.release.value = 0.25;

      osc.connect(comp);
      comp.connect(offlineCtx.destination);
      osc.start(0);

      // Offline rendern (kein Audio-Ausgang)
      const buffer = await offlineCtx.startRendering();
      const data = buffer.getChannelData(0);

      // Aus einem festen Bereich eine kompakte Zahl ableiten
      const start = 4500;
      const end = 5000;
      let sum = 0;
      let hash = 0;

      for (let i = start; i < end; i++) {
        const v = Math.abs(data[i]);
        sum += v;
        // einfache Hash-Mischung
        hash = (hash * 31 + Math.floor(v * 1e6)) >>> 0;
      }

      return {
        rawSum: sum,
        hash: hash.toString(16).padStart(8, '0')
      };
    }

    document.getElementById('run').addEventListener('click', async () => {
      const resultEl = document.getElementById('result');
      resultEl.textContent = 'Berechne...';

      try {
        const fp = await getAudioFingerprint();
        resultEl.innerHTML =
          '<p><strong>Roh-Summe:</strong> ' + fp.rawSum.toFixed(6) + '</p>' +
          '<p><strong>Hash (hex):</strong> ' + fp.hash + '</p>' +
          '<p>Auf demselben Gerät sollte dieser Wert relativ stabil sein, ' +
          'auf anderen Geräten/Browsers unterschiedlich.</p>';
      } catch (e) {
        resultEl.textContent = 'Fehler: ' + e;
      }
    });
  </script>
</body>
</html>

Neues Projekt: Tabulaturen.de – Der kostenlose Online-Tab-Editor

Features

Hier eine Übersicht aller Features der aktuellen Version:

  • Instrumente & Stimmungen
    • Gitarre: 6-saitig (Standard, Drop D, Open G, Halbton tiefer), 7-saitig (Standard, Drop A), 8-saitig (Standard, Drop E)
    • Bass: 4-saitig (Standard, Drop D), 5-saitig (Standard)
    • Saitenzahl/-dicke passt sich automatisch an
  • Notenraster-Editor
    • Klicken zum Auswählen, Zifferneingabe (0–24) für Bundnummern, auch zweistellig
    • Pfeiltasten-Navigation, auch ohne aktive Auswahl (setzt dort fort, wo zuletzt gewählt wurde)
    • Rücktaste/Entf löscht eine Note
    • Akustisches Feedback (Tonvorschau) beim Eintippen einer Note
    • Fokus-Logik: Tippen in ein externes Textfeld hebt die Tab-Auswahl auf; Dropdowns/Buttons, die mit der Auswahl arbeiten, lassen sie bestehen
  • Rhythmus/Notenwerte
    • Viertel, Achtel, Sechzehntel – jeweils auch punktiert
    • Vierteltriole, Achteltriole, Sechzehnteltriole, Sixtole, Septole
    • Automatische Notenhälse, Balken und Tuplet-Klammern
    • Neue Schritte übernehmen automatisch den Notenwert des zuvor eingefügten Schritts (bis manuell geändert)
  • Takt & Tempo
    • Taktarten 4/4 (Standard), 3/4, 6/8, 2/4, 7/8, 5/4 – je Takt wählbar, wirkt für den ganzen Takt
    • Globales Tempo (BPM) plus Tempo-Markierungen an einzelnen Schritten (gelten bis zur nächsten Angabe)
    • BPM-Anzeige im Notenblatt-Kopf und beim Drucken
  • Artikulationen
    • Hammer-On, Pull-Off, Slide (mit Zielnote), Slide Up, Slide Down (frei, ohne Zielnote)
    • Tapping, Tremolo, Vibrato, Release
    • Bends: ¼, ½, Ganzton, 1½, Doppelbend
    • Dead Note (x), Let Ring
    • Harmonic/Flageolet, Pinch Harmonic
    • Downstroke (⊓), Upstroke (V)
    • Palm Mute: manuell je Schritt oder als dauerhafter Modus (neue Noten automatisch gedämpft, bis deaktiviert)
  • Wiedergabe
    • Web-Audio-Synthese mit Zupf-Klang, berücksichtigt Zählzeiten, Tempowechsel, Taktarten und Triolen/Tuplets korrekt
    • Artikulationsgerechte Klänge: echte Bend-/Slide-/Release-Pitchverläufe, Vibrato-LFO, Tremolo-Nachschlagen, perkussiver Dead-Note-Sound, oktavierter Harmonic-Klang, weicher Legato-Anschlag, Downstroke/Upstroke-Akzent, verlängertes Let Ring
  • Optik
    • Weißes Papier-Notenblatt-Design (Songsterr-artig) auf dunklem Werkstatt-Hintergrund
    • Mehrere Systeme/Takte untereinander wie ein echtes Blatt, inkl. Taktnummern und Taktart-Anzeige
  • Drucken
    • DIN-A4-Ansicht mit identischer Notation (Notenhälse, Tuplets, Artikulationen, Taktarten, Tempo) wie am Bildschirm
    • Titel, Autor, Tempo, Datum im Druckkopf
  • Server-Speichern/Laden (eigenes PHP/MySQL-Backend)
    • Speichern mit Titel, Autor, IP-Erfassung, Captcha-Schutz (bildbasiert, tokenbasiert)
    • Suche mit Anfangsbuchstaben-Filter, Autor-Filter, Titel-Type-Ahead
    • Zeigt standardmäßig nur die neueste Version jedes Songs; Aufklapp-Pfeil zeigt bei Bedarf ältere Versionen
    • Versionierung: erneutes Speichern nach dem Laden erzeugt automatisch eine neue, verknüpfte Version – die alte bleibt erhalten
    • Sicherheitsabfrage (Ja/Nein) vor „Alles löschen“
    • Aufklappbarer Bereich „Laden / Speichern / Einbinden“ (standardmäßig zugeklappt)
  • Einbetten
    • Embed-Modus per URL-Parameter (?embed=1&id=...): zeigt nur Notenblatt, Abspielen- und Drucken-Button
    • Button „Vollständig auf Tabulaturen.de öffnen“ (neuer Tab, volle Editor-Ansicht)
    • Ein-Klick-Kopieren von Einbettungscode: HTML/iFrame, WordPress (Custom-HTML-Block), phpBB-BBCode, reiner Link

Einbetten

https://www.tabulaturen.de/?embed=1&id=7

Zwei Netzwerkverbindungen gleichzeitig unter Windows trotz Policy erlauben

Problem

Sie arbeiten in einer administrierten Organisation mit einer Windows-Domäne und verlieren bei zwei Netzwerkverbindungen eine Verbindung, weil eine Netzwerk-Policy nur eine Verbindung erlaubt.

Korrekterweise wäre der richtige Weg, dies über ein Ticket mit ihrer IT zu regeln, nur leider ist es Administrator-seitig nicht so einfach möglich diese Policy zu ändern, da man vermutlich zu Gunsten der IT-Sicherheit diese Policy bewusst eingerichtet hat. Daher ist die Resonanz Ihrer IT oft die Ablehnung und das unbearbeitete Schließen.

Dennoch gibt es Situationen, in denen das Vorhandensein von 2 Netzwerkverbindungen notwendig ist und ich arbeite in einer solchen Konstilation:

  • Ich befinde mich hauptsächlich im Homeoffice
  • Ich brauche die RJ45-Schnittstelle meines Notebooks um mit einer Peripherie, welche ich als Softwareentwickler programmiere, zu kommunizieren. Bei der Kommunikation kommt ein eigenes Protokoll zum Einsatz, welches nicht auf TCP/IP basiert.
  • Ich nutze neben der eigentlichen Programmiertätigkeit das Notebook um mit meinen Kollegen über Microsoft Teams zu kommunizieren oder neue Programmversionen in eine Cloud hochzuladen.
  • Ich nutze das firmeninterne Ticketsystem auf Basis von JIRA um meine täglichen Aufgaben zu erhalten, zu bearbeiten und zu kommentieren.
  • Ich commite meine Änderungen in ein Quellcode-Verwaltungssystem (GIT), welches sich in der Cloud befindet und Pflege meine Änderungen harmonisch in das Gesamtkonstrukt der Anwendung ein (Team-Programmierung).
  • …

Analyse

Im Allgemeinen liegt das Problem darin, dass der Rechner die folgende Policy immer wieder ändert:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WcmSvc\GroupPolicy]
"fBlockNonDomain"=dword:00000001
"fMinimizeConnections"=dword:00000000

Diese Änderungen werden periodisch von der Organisation über Azure-Mechanismen auf meinen Firmenrechner übertragen, was dazu führt, dass ich entweder nicht mehr arbeiten kann, oder dass ich nicht mehr über Microsoft-Teams erreichbar bin und meine Quellcode-Änderungen commiten kann.

Lösung

Für Windows 11 (und auch Windows 10) führe ich die folgende Batch-Datei als Administrator aus (Rechtsklick auf .bat-Datei -> Als Administrator ausführen):

@echo off
chcp 65001

:Start
echo Importiere Registry-Einstellungen...
regedit.exe /s change_group_policy.reg
echo Fertig.

:Frage
set /p Antwort=Moechten Sie den Vorgang wiederholen? (j/n): 
if /I "%Antwort%"=="j" goto Start
if /I "%Antwort%"=="n" exit
echo Ungueltige Eingabe. Bitte geben Sie "j" oder "n" ein.
goto Frage

Der unter Abschnitt „Analyse“ gezeigte Registry-Key, den ich unter dem Namen change_group_policy.reg gespeichert habe, lege ich in das gleiche Verzeichnis.

Diese Konsoleneingabe lasse ich geöffnet, da nach ein paar Stunden die Policy neu übertragen wird und ich eine Verbindung verliere.

Wenn jemand eine bessere Lösung dafür hat wäre ich für einen Kommentar unter dem Beitrag dankbar.

Die beiden Dateien hänge ich hier an:

Auf der Batch-Datei einfach „Rechtsklick -> Als Administrator ausführen“ machen.

C : List all network devices with their properties / attributes like GUID, adapter name, MAC address, Description

Problem

In some cases mighty libs like NPCap or WinPCap are used to get a list of all network devices with common properties like GUID and so on.

Approach

#pragma comment(lib, "iphlpapi.lib")
This links the IP Helper API library, which provides functions for retrieving network configuration and statistics, such as:

  • Network adapter information
  • IP address tables
  • Routing tables

#pragma comment(lib, "ws2_32.lib")
This links the Winsock 2 library, which is essential for network programming on Windows. It provides:

  • Socket APIs for TCP/UDP communication
  • DNS resolution
  • Network initialization and cleanup functions

Solution

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <iphlpapi.h>
#include <ws2tcpip.h>

#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")

int main() {
    DWORD dwSize = 0;
    DWORD dwRetVal = 0;

    IP_ADAPTER_ADDRESSES *pAddresses = NULL;
    IP_ADAPTER_ADDRESSES *pCurrAddresses = NULL;

    ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
    ULONG family = AF_UNSPEC;

    // Erste Abfrage zur Bestimmung der Puffergröße
    dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &dwSize);
    if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
        pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(dwSize);
        if (pAddresses == NULL) {
            printf("Speicher konnte nicht reserviert werden.\n");
            return 1;
        }
    }

    // Zweiter Aufruf mit gültigem Puffer
    dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &dwSize);
    if (dwRetVal == NO_ERROR) {
        pCurrAddresses = pAddresses;
        while (pCurrAddresses) {
            printf("Adapter GUID: %s\n", pCurrAddresses->AdapterName);
            printf("Adaptername: %ws\n", pCurrAddresses->FriendlyName);
            printf("Beschreibung: %ws\n", pCurrAddresses->Description);
            if (pCurrAddresses->PhysicalAddressLength != 0) {
                printf("MAC-Adresse: ");
                for (DWORD i = 0; i < pCurrAddresses->PhysicalAddressLength; i++) {
                    printf("%02X", pCurrAddresses->PhysicalAddress[i]);
                    if (i < pCurrAddresses->PhysicalAddressLength - 1)
                        printf(":");
                }
                printf("\n");
            }
            
            printf("--------------------------------------------------\n");
            pCurrAddresses = pCurrAddresses->Next;
        }       
    } else {
        printf("GetAdaptersAddresses fehlgeschlagen mit Fehler: %lu\n", dwRetVal);
    }

    if (pAddresses) {
        free(pAddresses);
    }

    return 0;
}

Output

PS C:\Betriebssysteme\Übung 6> .\ListNetworkDevices  
Adapter GUID: {E01CE7A3-099B-4184-8C16-1F5054A8317F}
Adaptername: Ethernet
Beschreibung: Intel(R) Ethernet Connection (7) I219-LM
MAC-Adresse: 34:48:ED:61:86:BA
--------------------------------------------------
Adapter GUID: {4012AE18-3341-4541-892C-BC0286FA6504}
Adaptername: Ethernet 2
Beschreibung: Check Point Virtual Network Adapter For Endpoint VPN Client
MAC-Adresse: 54:DF:6F:F5:98:06
--------------------------------------------------
Adapter GUID: {6EFE57EA-027E-45AA-9BFD-8071CE36C5FD}
Adaptername: Ethernet 7
Beschreibung: VirtualBox Host-Only Ethernet Adapter
MAC-Adresse: 0A:00:27:00:00:0F
--------------------------------------------------
Adapter GUID: {1A8FA3D8-A753-4453-8362-78FA3A6B314C}
Adaptername: Local Area Connection* 1
Beschreibung: Microsoft Wi-Fi Direct Virtual Adapter
MAC-Adresse: B8:9A:2A:2F:51:8F
--------------------------------------------------
Adapter GUID: {4BE430BD-CB19-4CBB-BA70-0D4EE0F6AECE}
Adaptername: Local Area Connection* 2
Beschreibung: Microsoft Wi-Fi Direct Virtual Adapter #2
MAC-Adresse: BA:9A:2A:2F:51:8E
--------------------------------------------------
Adapter GUID: {DFDC464C-3487-4D61-B1AE-28733CA18E2E}
Adaptername: Wi-Fi
Beschreibung: Intel(R) Wi-Fi 6 AX200 160MHz
MAC-Adresse: B8:9A:2A:2F:51:8E
--------------------------------------------------
Adapter GUID: {BAA489E2-AF2D-4A75-A99C-2E4C19B04F44}
Adaptername: Bluetooth Network Connection
Beschreibung: Bluetooth Device (Personal Area Network)
MAC-Adresse: B8:9A:2A:2F:51:92
--------------------------------------------------
Adapter GUID: {88CB09EB-7A9D-11EF-986B-806E6F6E6963}
Adaptername: Loopback Pseudo-Interface 1
Beschreibung: Software Loopback Interface 1
--------------------------------------------------
PS C:\Betriebssysteme\Übung 6>

REST-Client für Visual Studio Code (Extension: „REST Client“)

Intention

Zum Testen / Aufrufen von REST-API’s benötigt man am Besten einen Client, der nicht unbedingt im Webspace der selben Domain gehostet ist, da man Testen möchte ob die Cross-Origin Resource Policy (CORP) / Cross Site Policy korrekt konfiguriert ist.

Problem

Würde man einen Javascript-REST-Client im Web-Root / wwwroot / inetpub der selben Domain hosten, könnte dieser ohne Verletzung der Policy auf die REST-Services der selben Domain zugreifen. Würde man die Endpoints / Endpunkte an einen Konsumenten weitergeben, könnte dieser bei einer Fehlkonfiguration diese trotzdem nicht aufrufen.

Beispiel für einen Javascript-REST-Client, der durch den Response-Body ein JSON-Array iteriert (für Tests nicht empfohlen):

<button id="loadData">Get Rides</button>
<div id="rideData"></div>

<script>
    async function fetchRideData() {
        const response = await fetch("/Ride");
        if (!response.ok) {
            document.getElementById("rideData").innerText = "Fehler beim Laden der Daten.";
            return;
        }
        const data = await response.json();
        let html = "<ul>";
        data.forEach(item => {
            html += `<li>ID: ${item.id}, Datum: ${item.timestamp}, GPS Position: ${item.gpS_Position}, Kennzeichen: ${item.kennzeichen}</li>`;
        });
        html += "</ul>";
        document.getElementById("rideData").innerHTML = html;
    }

    document.getElementById("loadData").addEventListener("click", fetchRideData);
</script>

Lösung

Die Extension „REST Client“ kann als autarker REST-Client, der nicht in der Domäne des Webspaces läuft, sondern lokal vom Rechner aus den Aufruf tätigt, genutzt werden:

Im Screenshot oben wurde die Extension „REST Client“ installiert und eine neue Datei mit dem Namen „restapi.http“ angelegt.

Die Datei hat den folgenden Inhalt (im Body wird ein JSON-Array übermittelt, dieses müsste dem Service entsprechend ersetzt werden):

POST https://www.domain.info/GenericRequest
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
X-WS-RateLimit-Limit: 1000
X-WS-RateLimit-Remaining: 999
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Wed, 07 May 2025 10:27:38 GMT

[ {
"ts": 1530536430,
"lat":-34.1868759,
"lng":-56.9065776,
"head": 30,
"speed": 50,
"id": "SBV3399",
"temp": "20",
"motor":"on"

},
{
"ts": 1530536430,
"lat":-34.1868759,
"lng":-56.9065776,
"head": 0,
"speed": 50,
"id": "MAV4099",
"temp": "8",
"motor":"off"
}]

Fazit

REST API’s lassen sich am Besten mit einem REST-Client testen / aufrufen, der nicht auf dem Domain-Space läuft, auf dem die Endpunkte gehostet sind um CORP zu testen. Dies verhindert unangenehme Überraschungen zwischen der aufrufenden und aufzurufenden Seite.

Die Regeln in einem Rot-Schwarz-Baum

Eine Einführung in die Eigenschaften und Funktionsweise

Ein Rot-Schwarz-Baum ist eine spezielle Art von selbstbalancierendem binären Suchbaum, der in der Informatik weit verbreitet ist. Er wurde entwickelt, um das Einfügen, Löschen und Suchen von Elementen in logarithmischer Zeit zu ermöglichen. Die wichtigsten Eigenschaften von Rot-Schwarz-Bäumen sind ihre Balance und die Tatsache, dass sie eine garantierte Worst-Case-Performance bieten. Die Regeln, die einen Rot-Schwarz-Baum definieren, sind entscheidend für seine Funktionsweise.

Grundregeln eines Rot-Schwarz-Baums

Ein Rot-Schwarz-Baum hält sich an fünf grundlegende Regeln, die sicherstellen, dass der Baum immer balanciert bleibt. Diese Regeln sind:

1. Jeder Knoten ist entweder rot oder schwarz.

Jeder Knoten eines Rot-Schwarz-Baums hat eine Farbeigenschaft, die entweder rot oder schwarz sein kann. Diese Eigenschaft ist entscheidend, um die Struktur und Balance des Baums zu erhalten.

2. Die Wurzel ist immer schwarz.

Die Wurzel des Baums muss immer schwarz sein. Diese Regel stellt sicher, dass der Baum im Gleichgewicht bleibt und dass die Pfadlänge von der Wurzel zu jedem Blattknoten konsistent bleibt.

3. Alle Blätter (Nil-Knoten) sind schwarz.

In einem Rot-Schwarz-Baum sind alle Blätter, die als Nil-Knoten bezeichnet werden und keine Daten speichern, immer schwarz. Diese Regel hilft, die Struktur des Baums zu vereinheitlichen.

4. Rote Knoten haben keine roten Kinder (keine zwei aufeinanderfolgenden roten Knoten).

Ein roter Knoten darf keine roten Kinder haben. Dies bedeutet, dass in einem Rot-Schwarz-Baum keine zwei roten Knoten aufeinanderfolgen dürfen. Diese Regel verhindert, dass der Baum aus dem Gleichgewicht gerät.

5. Jeder Pfad von einem Knoten zu seinen Nil-Knoten-Blättern enthält die gleiche Anzahl schwarzer Knoten.

Diese Regel, auch als Schwarzhöhenregel bekannt, stellt sicher, dass die Anzahl der schwarzen Knoten auf jedem Pfad von einem Knoten zu seinen Nachkommen konsistent ist. Diese Konsistenz ist entscheidend für die Balance des Baums.

Operationen in einem Rot-Schwarz-Baum

Die Einhaltung der oben genannten Regeln ist entscheidend für die Durchführung von Operationen im Rot-Schwarz-Baum. Zu den wichtigsten Operationen gehören das Einfügen, Löschen und Suchen von Knoten. Jede dieser Operationen muss sicherstellen, dass die Regeln des Rot-Schwarz-Baums nach ihrer Durchführung weiterhin gültig sind.

1. Einfügen

Beim Einfügen eines neuen Knotens in einen Rot-Schwarz-Baum wird der neue Knoten initial als rot markiert. Dies geschieht, um sicherzustellen, dass die Schwarzhöhenregel nicht verletzt wird. Nach dem Einfügen wird der Baum rebalanciert und die Farben der Knoten werden angepasst, um die Rot-Schwarz-Regeln zu erfüllen. Dies kann Rotationen und Farbänderungen der Knoten erfordern.

2. Löschen

Das Löschen eines Knotens aus einem Rot-Schwarz-Baum ist komplexer als das Einfügen. Es erfordert, dass der Baum rebalanciert wird, um die Rot-Schwarz-Regeln nach dem Löschen aufrechtzuerhalten. Wenn der zu löschende Knoten schwarz ist, kann dies die Schwarzhöhenregel verletzen, und zusätzliche Schritte wie Rotationen und Farbänderungen sind notwendig, um das Gleichgewicht wiederherzustellen.

3. Suchen

Das Suchen in einem Rot-Schwarz-Baum folgt denselben Prinzipien wie das Suchen in einem gewöhnlichen binären Suchbaum. Die Suchoperation ist effizient aufgrund der garantierten logarithmischen Höhe des Baums, die durch die Rot-Schwarz-Regeln gewährleistet wird.

Beispiele und Anwendungen

Rot-Schwarz-Bäume finden in vielen Bereichen der Informatik Anwendung. Sie werden häufig in der Implementierung von assoziativen Arrays, symbolischen Tabellen und Priority Queues verwendet. Ihre Eigenschaften machen sie ideal für Situationen, in denen konsistente Leistung und effiziente Operationen erforderlich sind.

Ein Beispiel für die Anwendung von Rot-Schwarz-Bäumen ist die Implementierung von Dictionaries in Programmiersprachen wie C++ (std::map) und Java (java.util.TreeMap). Diese Datenstrukturen basieren auf der Effizienz und Selbstbalancierungsfähigkeit von Rot-Schwarz-Bäumen.

Fazit

Rot-Schwarz-Bäume sind eine leistungsstarke Datenstruktur, die durch ihre spezifischen Regeln eine effiziente und balancierte Organisation von Daten ermöglicht. Das Verständnis und die Einhaltung dieser Regeln sind entscheidend für die Implementierung und Nutzung von Rot-Schwarz-Bäumen in der Informatik. Ihre Anwendungen und Vorteile machen sie zu einem unverzichtbaren Werkzeug für Entwickler und Ingenieure, die effiziente Datenstrukturen benötigen.

Algorithmen und Datenstrukturen: Der Radix Sort in Java

Der Algorithmus

Der Radix Sort-Algorithmus sortiert Zahlensysteme anhand ihrer Stellen. Der Radix Sort wird daher auch Base Sort genannt. Dies bedeutet, dass je Stelle ein eigenes Sortierverfahren (zumeist Counting Sort weil Wertebereich überschaubar) eingesetzt wird. Man würde also bei 3 Stellen auch 3x sortieren.

Es gibt einen Most- und Least-Significant-Radix-Sort (MSD / LSD Radix Sort). LSD beginnt bei der niedrigsten Stelle (z.B. den Einern) und bewegt sich zu den höheren Stellen (z.B. Zehner, Hunderter). Bei MSD Radix Sort ist das umgekehrt.

Eine wichtige Voraussetzung ist, das man die gleiche Anzahl an Stellen hat (also z.B. 2 (Tupel), 3 (Tripel) oder mehr Stellen). Weiterhin müssen die vorhandenen Elemente in dem Zahlensystem (z.B. Dezimal 0-9) in einer Reihenfolge nach Rang sortierbar sein. D.h. es sollte z.B. klar sein dass ein A vor einem B ist (z.B. durch ASCII-Werte).

Nehmen wir an, wir möchten die Zahlen [170, 45, 75, 90, 802, 24, 2, 66] sortieren:

LSD Radix Sort (von rechts nach links):

  1. Sortierung nach der 1er-Stelle: [170, 90, 802, 2, 24, 45, 75, 66]
  2. Sortierung nach der 10er-Stelle: [802, 2, 24, 45, 66, 170, 75, 90]
  3. Sortierung nach der 100er-Stelle: [2, 24, 45, 66, 75, 90, 170, 802]

    Anwendung: Oft bei der Sortierung von Zahlen und Wörtern verwendet.
    Vorteil: Einfacher zu implementieren und erfordert weniger komplexe Vergleiche.

MSD Radix Sort (von links nach rechts):

  1. Sortierung nach der 100er-Stelle: [170, 24, 2, 45, 66, 75, 802, 90]
  2. Sortierung nach der 10er-Stelle: [2, 24, 45, 66, 75, 90, 170, 802]
  3. Sortierung nach der 1er-Stelle: [2, 24, 45, 66, 75, 90, 170, 802]

    Anwendung: Eignet sich gut für große Zahlenmengen oder lange Zeichenketten.
    Vorteil: Kann effizienter sein, wenn die Daten ungleichmäßig verteilt sind.

Code von LSD Radix Sort

Der folgende Code hat die vergangenen Implementierungen von QuickSort und Counting Sort (ohne Stellensortierung durch Radix / Base Sort) mit einer Zeitmessung in Echtzeit verglichen und muss angepasst werden. Das nachfolgende Beispiel sortiert Dezimalzahlen (also ein Zahlensystem zur Basis 10).

package AlgoDat;

import java.util.Arrays;

public class RadixSort {
    // Zu sortierendes Array
    private static int myArrayRadixSort[] = {22, 6, 2, 4, 10, 3, 9, 7, 5, 8, 1};
    
    public boolean verbose = false;

    // Hält die Klassen als instanziertes Objekt
    @SuppressWarnings("unused")
    private static RadixSort programRadixSort;
    @SuppressWarnings("unused")
    private static HelperUtil helper;

    // Hilfsfunktion für das Ausgeben des Arrays
    public void OutputOfIntArray(int myArray[])
    {
        if (myArray != null)
        {
            for (int i = 0; i < myArray.length; i++) {
                if (i > 0) System.out.print(";");
                System.out.print(myArray[i]);
            }

            System.out.println();
        }
    }

    public void radixSort(int[] arr) 
    { 
        int max = Arrays.stream(arr).max().getAsInt();
        if (verbose) System.out.println("Größte Zahl im Array: " + max);
        
        // Bei Dezimalzahlen muss die Basis 10 genommen werden
        // ... bei Großbuchstaben z.B. die Basis 27
        for (int exp = 1; max / exp > 0; exp *= 10) 
        { 
            if (verbose) System.out.println("Suche " + exp + "er.");
            countingSort(arr, exp); 
        } 
    } 
    
    public void countingSort(int[] arr, int exp) 
    { 
        int n = arr.length; 
        int[] output = new int[n]; 
        int[] count = new int[10]; 
        
        // Alle 10 Elemente mit 0 initialisieren
        for (int i = 0; i < 10; i++) 
        { 
            count[i] = 0; 
        } 
        
        // Histogramm erstellen
        for (int i = 0; i < n; i++) 
        { 
            count[(arr[i] / exp) % 10]++; 
        } 
        
        // Kummuliere, so dass die Anfangspositionen in dem Array stehen
        for (int i = 1; i < 10; i++) 
        { 
            count[i] += count[i - 1]; 
        } 
        
        // Ausgabearray erstellen
        for (int i = n - 1; i >= 0; i--) 
        { 
            output[count[(arr[i] / exp) % 10] - 1] = arr[i]; 
            count[(arr[i] / exp) % 10]--; 
        } 
        
        // Kopiere das neu erstellte Array auf das zu ändernde Array
        for (int i = 0; i < n; i++) 
        { 
            arr[i] = output[i]; 
        } 
    } 
    
    // Konstruktor
    public RadixSort(int[] toSort)
    {
        this.radixSort(toSort);
    }

    // Konstruktor
    public RadixSort()
    {
        System.out.print("Vorher: ");
        this.OutputOfIntArray(myArray);

        this.radixSort(myArray); 
        
        System.out.print("Nachher: ");
        this.OutputOfIntArray(myArray);
    }

    public static void main(String[] args) 
    {
        helper = new HelperUtil();

        // Es gibt 80 Mio Menschen in Deutschland, von denen keiner älter als 120 ist -> Kleiner Wertebereich
        int[] alterDerMenschenInDeutschlandRS = helper.generateIntegerArrayOfSize(80000000, 120);
        int[] alterDerMenschenInDeutschlandQS = alterDerMenschenInDeutschlandRS.clone();
        int[] alterDerMenschenInDeutschlandCS = alterDerMenschenInDeutschlandRS.clone();
        // Erwartung: Da Counting Sort eine lineare Laufzeit hat sollte er bei kleinem Wertebereich am Besten performen
        
        System.out.println("\nEs gibt 80 Mio Menschen in Deutschland, von denen keiner älter als 120 ist -> Kleiner Wertebereich");
        System.out.println("===================================================================");
        
        long startZeitRS = System.nanoTime();
        programRadixSort = new RadixSort(alterDerMenschenInDeutschlandRS);
        long endZeitRS = System.nanoTime();
        System.out.println((endZeitRS-startZeitRS) + " ns (Radix Sort)");
    }
}

Ausgabe

Es gibt 80 Mio Menschen in Deutschland, von denen 
keiner älter als 120 ist -> Kleiner Wertebereich
=======================================================
347584000 ns (Counting Sort)
2544168000 ns (Radix Sort)
3335958900 ns (Quick Sort)

Komplexität: O-Notation (Ordnung)

O(n*l) (l=Länge also bei ABC = Länge: 3 – Anzahl der max. Stellen0)
‣ Sortieren von Strings über einem endlichen Alphabet durch
mehrmaliges Anwenden von Counting Sort.
‣ Angenommen: Alle Wörter haben die Länge
‣ Z.b. Postleitzahlen

Laufzeit von Radix Sort: 𝒪(n), weil l ⋅ n Durchläufe