FlipLinkedList() - Umdrehen der Reihenfolge einer LinkedList

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

FlipLinkedList() - Umdrehen der Reihenfolge einer LinkedList

Beitrag von PureLust »

Angeregt druch >diesen< Thread hab ich mal eine universell einsetzbare Routine geschrieben mit der man die Reihenfolge einer LinkedList umdrehen kann.
Da hierbei nicht der Inhalt der LinkedList-Einträge sondern nur die Zeiger auf das nächste/vorhergehende Elemente getauscht wird sollte sie recht performant sein.

Sie ist so gestalltet, dass es möglich ist eine x-beliebige LinkedList umzudrehen - egal von welchem Typ oder ob strukturiert oder nicht.

Als Parameter wird die Adresse eines Elements der LinkedList benötigt (@myLinkedList()) - welches ist dabei egal.

Weiterhin wird noch die Größe der Struktur benötigt.
Diese kann wie üblich durch SizeOF() ermittelt werden:
- SizeOf(BYTE)
- SizeOf(LONG)
- SizeOf(STRING)
- SizeOf(MyStructure)

Hier mal die Prozedur als Include ("FlipLinkedList_Include.pbi"):

Code: Alles auswählen

; ###############################################################################
; ###  Procedure    : FlipLinkedList()                                        ###
; ###  Date         : 03.08.2007                                              ###
; ###  Author       : Albert Cremers (alias PureLust)                         ###
; ###  PB-Version   : 4.x (testet - should work on older versions as well)    ###
; ###  OS           : Windows (tested), Lunix, Max OSX (should work as well)  ###
; ###  Forum-Thread : http://www.purebasic.fr/german/viewtopic.php?t=13816    ###
; ###                                                                         ###
; ###  With this Routine you can flip the order of a LinkedList().            ###
; ###  Because it just changes the Next/Prev-Pointer instead of the whole     ###
; ###  content of the list it should be quite performant.                     ###
; ###                                                                         ###
; ###  It works with any kind of LinkedList and it doesn't matter if it's     ###
; ###  structured or not.                                                     ###
; ###                                                                         ###
; ###  Parameters:                                                            ###
; ###                                                                         ###
; ###  - *PointerToLinkedListElement : a Pointer to a valid Element of the    ###
; ###                                  LinkedList whose order should be       ###
; ###                                  flipped.                               ###
; ###                                  e.g.: @myLinkedList()                  ###
; ###                                                                         ###
; ###  - SizeOfLinkedListStruckture  : the size of the LinkedList-Structure   ###
; ###                                  e.g.: SizeOf(LONG)                     ###
; ###                                        SizeOf(STRING                    ###
; ###                                        SizeOf(YourStructure)            ###
; ###                                                                         ###
; ###  It includes some error-handling which it notifies through the          ###
; ###  Debug-window.                                                          ###
; ###                                                                         ###
; ###  Results:                                                               ###
; ###  It results the number of Elements which where flipped.                 ###
; ###  This number should be equal to CountList().                            ###
; ###  if an error occurs, the result will be "-1".                           ###
; ###                                                                         ###
; ###  Example:                                                               ###
; ###                                                                         ###
; ###  NewList MyLinkedList.w()                                               ###
; ###  ....                                                                   ###
; ###  FlipLinkedList(@MyLinkedList(), SizeOf(WORD))                          ###
; ###                                                                         ###
; ###############################################################################

Procedure.l FlipLinkedList(*PointerToLinkedListElement, SizeOfLinkedListStruckture)
	Structure LinkedListHeader
		Next.l
		Prev.l
	EndStructure
	Protected Buffer, Counter, Error = #False
	Protected *AktElement.LinkedListHeader = *PointerToLinkedListElement-8
	Protected *FirstElement.LinkedListHeader
	Protected *LastElement.LinkedListHeader
	Protected *Dummy.LinkedListHeader
	If SizeOfLinkedListStruckture > 0
		Buffer = AllocateMemory(SizeOfLinkedListStruckture)
		If Not Buffer
			Debug "FlipLinkedList Error !!! Could not allocate Memory for LinkedList-Structure ("+Str(SizeOfLinkedListStruckture)+" Bytes)."
			ProcedureReturn -1
		EndIf
	Else
		Debug "FlipLinkedList Error !!! Illegal Size of LinkedList-Structure ("+Str(SizeOfLinkedListStruckture)+" Bytes)."
		ProcedureReturn -1
	EndIf
	; ############################################################################
	; ###  First make sure, that it's a valid Pointer to a LinkedList-Element  ###
	; ############################################################################
	If *AktElement\Next
		*Dummy = *AktElement\Next
		If *Dummy\Prev <> *AktElement : Error = #True : EndIf
	ElseIf *AktElement\Prev
		*Dummy = *AktElement\Prev
		If *Dummy\Next <> *AktElement : Error = #True : EndIf
	Else
		Debug "FlipLinkedList Error !!! Given Parameter was either not a valid Pointer to a LL-Element or LL was empty !!!"
		FreeMemory(Buffer)
		ProcedureReturn 0
	EndIf
	If Error
		Debug "FlipLinkedList Error !!! Given Parameter was not a valid Pointer to a LinkedList-Element !!!"
		FreeMemory(Buffer)
		ProcedureReturn -1
	EndIf
	; ######################################################
	; ###  Now find the first Element of the LinkedList  ###
	; ######################################################
	While *AktElement\Prev
		*AktElement = *AktElement\Prev
	Wend
	*FirstElement = *AktElement
	; #######################################################################
	; ###  Now run through the LinkedList and swap all Next/Prev-Pointer  ###
	; #######################################################################
	*AktElement = *AktElement\Next
	While *AktElement\Next
		*Dummy = *AktElement\Next
		*AktElement\Next = *AktElement\Prev
		*AktElement\Prev = *Dummy
		*AktElement = *Dummy
		Counter + 1
	Wend
	; #####################################
	; ###  Now swap First/Last Element  ###
	; ##################################################################################
	; ###  Because I don't know how to tell PB where the first/last Element is,      ###
	; ###  I leave them as they are and swap the content of the 2 Elements instead.  ###
	; ##################################################################################
	CopyMemory(*FirstElement+8, Buffer         , SizeOfLinkedListStruckture)
	CopyMemory(*AktElement  +8, *FirstElement+8, SizeOfLinkedListStruckture)
	CopyMemory(Buffer         , *AktElement  +8, SizeOfLinkedListStruckture)
	FreeMemory(Buffer)
	*Dummy = *FirstElement\Next					; \
	*FirstElement\Next = *AktElement\Prev		;  } Swap Next/Prev of First/Last Element
	*AktElement\Prev = *Dummy						; /
	*Dummy\Next = *AktElement						; Set Next-Pointer of the now next-to-last Element to the last Element
	*AktElement\Prev = *FirstElement				; Set Prev-Pointer of the now 2nd Element to the first Element
	ProcedureReturn Counter + 2
EndProcedure
Und hier mal eine kleine Demonstration dazu:

Code: Alles auswählen

EnableExplicit
XIncludeFile #PB_Compiler_Home + "Includes\FlipLinkedList_Include.pbi"

NewList Numbers.POINT()
Define k, flipped

For k=1 To 10
	AddElement(Numbers())
	Numbers()\x = k
Next

ForEach Numbers()
	Debug Numbers()\x
Next

flipped = FlipLinkedList(@Numbers(), SizeOf(POINT))
Debug ""
Debug Str(flipped) + " Elements flipped"
Debug ""

ForEach Numbers()
	Debug Numbers()\x
Next
Wenn's jemand gebrauchen kann oder Feedback dazu abgeben möchte: Comments are welcome. :mrgreen:

Gruß, PureLust.
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

Hi,

Code sieht super aus wird wohl auch so funktionieren, daher hab ich ihn mir mal kopiert und für künftige Projekte vorgemerkt.

Gruß
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Antworten