THeap: Heap Datenstruktur (Effizientes Minimum / Maximum)

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

 

Dreamora

Betreff: THeap: Heap Datenstruktur (Effizientes Minimum / Maximum)

BeitragDo, Aug 24, 2006 11:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Beschreibung:
Ein Heap ist eine Datenstruktur die es erlaubt auf sehr effiziente Art und Weise (O(log n)) jeweils das Maximum bzw. das Minimum aus einer beliebigen Menge von Objekten zu ziehen. Dies kann man zB sehr gut benutzten, wenn man Prioritätsschlagen (priority queues) implementieren möchte, welche mit einer normalen, linear verketteten Liste nie unter O(n) gelangen können.


Verbesserungen und Anmerkungen / Kommentare erwünscht.



Heap Test.bmx
Code: [AUSKLAPPEN]

Strict

Import "ds_heap.bmx" 'dreamora.ds_heap

Global heap:THeap   = THeap.create(,False)
Global heap2:THeap   = theap.create(,False,compareNumbers)
Local elem:Object
For Local i:Int = 1 To 20
   elem   = String(110-3*i)
   heap.add(elem)
   heap2.add(elem)
Next

Print "Heap ohne Vergleichsfunktion: "
Print "Heap Grösse: " + heap.count()

While Not heap.isEmpty()
   Print "Element: " + heap.getTop().tostring()
Wend
Print "Huh, was ist denn da los? Warum soll auf einmal 102 kleiner sein als 50?"

Print "~n~nHeap mit Vergleichsfunktion: "
Print "Heap Grösse: " + heap2.count()

While Not heap2.isEmpty()
   Print "Element: " + heap2.getTop().tostring()
Wend

Print "Ahh. Siehst du, mit einer eigenen Vergleichsfunktion kannst du den Fehler beim Grössenvergleich von Nummern beseitigen!"


Function compareNumbers:Int(one:Object, two:Object)
   Return Int(one.tostring())-Int(two.tostring())
End Function







ds_heap.bmx
Code: [AUSKLAPPEN]

Strict
Rem
    bbdoc: Heap
    about: Heap Klasse. Kann für PrioritätsQueues genutzt werden sowie um aus einer Menge von Objekten immer effizient das kleinste / grösste zu ziehen.
End Rem
Rem
Module dreamora.ds_heap

ModuleInfo "Version: 1.0"
ModuleInfo "Author: Marc 'Dreamora' Schaerer"
ModuleInfo "License: Public domain"
ModuleInfo "Copyright: 2006  Marc 'Dreamora' Schaerer"
ModuleInfo "Modserver: dreamora"

ModuleInfo "History:"
moduleinfo "-   1.0 Veröffentlichung"
End Rem
Import brl.retro

Rem
   bbdoc: THeap
   about: Heap Klasse
End Rem
Type THeap
   Field _data:Object[]
   Field _ascending:Int
   Field _length:Int = 1
   Field _sortingFunction:Int(one:Object,two:Object)
   
   Rem
      bbdoc: Create
      about: Erzeugt eine neues THeap Objekt und gibt eine Referenz auf dieses zurück.<br>
      <b>elements:</b> Anzahl Elemente mit welcher der Heap initialisiert werden soll.<br>
      "ird bei Bedarf effizient dynamisch vergrössert und verkleinert.<br>
      Dient primär dazu, dass der Heap bereits entsprechend gross erzeugt werden kann, wenn du in etwa weisst, wieviele Objekte gleich rein gesteckt werden.<br>
      Defaultwert ist 16.<br>
      <b>maximum:</b> Definiert ob oben auf dem Heap jeweils das grösste (true) oder das kleinste Objekt liegen soll.<br>
      Defaultwert ist Maximum also true.<br>
      <b>ComparisionFunction:int( one:Object,two:Object):</b> Lässt dich eine eigene Vergleichsfunktion definieren, die 2 Objekte vergleicht.<br>
      Die Beispielanwendung zeigt wie man das benützt und auch in welchen Dingen es besonders Sinn machen kann.<br>
      Defaultwert für die Vergleichsfunktion ist BlitzMaxs eigene Compare Methode von Objekten.
      returns: Gibt eine Referenz auf den erzeugten Heap zurück.
   End Rem
   Function Create:THeap(elements:Int = 16, maximum:Int = True, ComparisionFunction:Int( one:Object,two:Object)=compareObjects)
      Local result:THeap   = New THeap
      result._data      = New Object[elements]
      result._ascending   = maximum
      result._sortingFunction   = ComparisionFunction
      Return result
   End Function
   
   Rem
      bbdoc: Add
      about: Fügt ein neues Objekt dem Heap hinzu.<br>
      <b>obj:</b> Referenz auf das Objekt, das dem Heap hinzugefügt werden soll.
   End Rem
   Method Add(obj:Object)
      If _length = _data.length      _data   = _data[.._data.length*2]
      _data[_length] = obj
      Local ret:Int = _bubbleUp(_length)
      If ret > 0      _siftDown(ret)
      _length   :+ 1
   End Method
   
   Rem
      bbdoc: Top
      about: Gibt euch eine Referenz auf das oberste Objekt im Heap zurück, ohne es vom Heap zu entfernen.
      returns: Referenz auf das oberste Objekt im Heap.
   End Rem
   Method Top:Object()
      If isEmpty()         Throw "THeap.Top: Not supported on an empty heap!"
      Return _data[1]
   End Method
   
   Rem
      bbdoc: GetTop
      about: Gibt eine Referenz auf das oberste Objekt im Heap zurück. Dieses wird dabei vom Heap entfernt!
      returns: Referenz auf das oberste Objekt im Heap.
   End Rem
   Method GetTop:Object()
      If isEmpty()      Throw "THeap.GetTop: Not supported on an empty heap!"
      Local tmp:Object   = _data[1]
      _data[1]   = _data[_length-1]
      _length   :- 1
      _siftDown(1)
      If _data.length <= 0.35 * _length      _data   = _data[.._data.length/2]
      Return tmp
   End Method
   
   Rem
      bbdoc: Count
      about: Gibt die Anzahl Elemente im Heap zurück.
      returns: Anzahl Elemente im Heap.
   End Rem
   Method Count:Int()
      Return _length-1
   End Method
   
   Rem
      bbdoc: isEmpty
      about: Teilt euch mit, ob der Heap leer ist oder nicht.
      returns: True falls er leer ist, sonst false.
   End Rem
   Method isEmpty:Int()
      Return _length = 1
   End Method
   
   Rem
      interne Funktion
   End Rem
   Method _bubbleUp:Int(index:Int)
      Local tmp:Object      = _data[index]
      If _ascending
         While index > 1 And _sortingFunction(tmp,_data[index/2]) > 0
            _data[index]   = _data[index/2]
            index         :/ 2
         Wend
      Else
         While index > 1 And _sortingFunction(tmp,_data[index/2]) < 0
            _data[index]   = _data[index/2]
            index         :/ 2
         Wend
      EndIf
      _data[index]      = tmp
      Return index
   End Method
   
   Rem
      interne Funktion
   End Rem
   Method _siftDown(index:Int)
      Local tmp:Object         = _data[index]
      Local j:Int
      Local N:Int               = _length - 1
      If _ascending
         While index <= N/2
            j   = index+index
            If _data[j+1] And _sortingFunction(_data[j + 1],_data[j]) > 0   j :+ 1
            If _sortingFunction(tmp,_data[j]) >  0               Exit
            _data[index]      = _data[j]
            index            = j
         Wend
      Else
         While index <= N/2
            j   = index+index
            If _data[j+1] And _sortingFunction(_data[j + 1],_data[j]) < 0   j :+ 1
            If _sortingFunction(tmp,_data[j]) <  0               Exit
            _data[index]      = _data[j]
            index            = j
         Wend
      EndIf
      _data[index]         = tmp
   End Method
End Type



Function CompareObjects:Int(o1:Object, o2:Object)
   Return o1.compare(o2)
End Function
Ihr findet die aktuellen Projekte unter Gayasoft und könnt mich unter @gayasoft auf Twitter erreichen.
  • Zuletzt bearbeitet von Dreamora am Do, Aug 24, 2006 17:22, insgesamt einmal bearbeitet

Vertex

BeitragDo, Aug 24, 2006 17:03
Antworten mit Zitat
Benutzer-Profile anzeigen
Hmmm,

Code: [AUSKLAPPEN]
result._sortingFunction   = sortingFunction
hier fehlt ihm sortingFunction.

So richtig habe ich das jezt noch nicht verstanden. Für mich ist ein Heap vom Programmtechnischen ein Speicherort in dem dyn. Speicher alloziert wird. Das geschieht dann, je nach OS, effizient im Bereich Geschwindigkeit und Speicherausnutzung.

Jetzt frage ich mich, was das mit Prioritätsschlangen zu tun hat.

OT:
Wäre nett, wenn du demnächst im SuperStrict Modus verfährst. Weiterhin muss man bedenken, dass Tabulatoren von IDE zu IDE anders dargestellt werden.

Beispiel:
Code: [AUSKLAPPEN]
While Abc
   If Blub("Erste Zeile Erste Zeile", ..
           "Zweite Zeile Zweite Zeile", ..
           "Dritte Zeile Dritte Zeile") Then
      DoAnything()
      DoAnything()
      DoAnything()
   EndIf
Wend


Wird so überall korrekt dargestellt:
Code: [AUSKLAPPEN]
While Abc
°If Blub("Erste Zeile Erste Zeile", ..
°........"Zweite Zeile Zweite Zeile", ..
°........"Dritte Zeile Dritte Zeile") Then
°°DoAnything()
°°DoAnything()
°°DoAnything()
°EndIf
Wend

(° Tabulator, . Leerzeichen)

Ich muss mal demnächst ein Styleguide dafür ausarbeiten.
 

Dreamora

BeitragDo, Aug 24, 2006 17:31
Antworten mit Zitat
Benutzer-Profile anzeigen
sorry zuweisung war mein Fehler weil ich den übergabenamen fürs Posting im D Board geändert habe.
Danke für den Hinweis, wurde gefixt.

Ein Heap ist einfach eine Datenstruktur bei der zu oberst entweder immer das grösste oder kleinste ist und bei dem dies für jeden Unterbaum weiterhin gilt. Eine andere Ordnungsvorschrift gibt es nicht. (ok doch: Alle x obersten Ebenen sind immer vollständig gefüllt, die unterste wird von links nach rechts aufgefüllt. Aber das lässt sich ohne Grafik net gescheit erklären)
Er ist daher hervorragend geeignet um "get Max / Min" Situationen zu lösen bei beliebigen Mengen. Er besitzt keine Form von interner Sortierung oder so, wie es beim Bin Baum der Fall ist, weswegen er normalerweise auch mit einem Array gemacht wird und nicht mit Zeigern, denn man muss nicht baumteile umhängen oder so um Ordnungsvorschriften zu erfüllen.


SuperStrict steht jedem frei zu nutzen.
Da ich alle rückgabetypen etc deklariere, sollte es damit keine Probleme geben.
Ich ziehe es persönlich nur vor, das implizit zwischen Zahlentypen gecastet wird etc, weswegen ich es auch nicht nutze.
Andere unterschiede von Strict zu SuperStrict gibt es nicht.


Was es mit Priority Queues zu tun hat:
Diese werden normalerweise mit Heap als zu Grunde liegender Datenstruktur implementiert (nicht mit selbstanordnenden verketteten Listen, wie man vielleicht glauben möchte).
Da es bei einer Priority Queue primär darum geht, jeweils das nächstwichtigste Objekt zu bekommen, ist ein Heap dafür hervorragend geeignet. (kenne nur noch etwas was eine noch bessere Laufzeit hat. Aber Fibonacci Heap zu implementieren ist ein Akt der Selbstzerstörung)
Ihr findet die aktuellen Projekte unter Gayasoft und könnt mich unter @gayasoft auf Twitter erreichen.

Vertex

BeitragFr, Aug 25, 2006 16:02
Antworten mit Zitat
Benutzer-Profile anzeigen
OK, danke!

Ich werde darauf sicher nochmal zurückkommen, da ich für ein UDP Server mit prioritätsorientierten Nachrichtenschlangen arbeiten werde. Da sollte Geschwindigkeit und wenig Speicherverbrauch im Vordergrund stehen.

mfg olli

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group