Seite 1 von 1

Abstrakter Datentyp: Set (mehr oder weniger)

Verfasst: 20.07.2015 12:34
von Derren
Hier mal eine Implementation eines abstrakten Datentyps.
In diesem Fall: Das Set oder die Menge. Eine Liste von Daten, in der jedes Element nur einmal vorkommen darf. Der Versuch identische Elemente hinzuzufügen schlägt fehl.

Ein Set kann viele Funtionen haben, ich habe mich hier auf 3 beschränkt. Einfügen, Entfernen und Überprüfen ob ein Element im Set enthalten ist.
Das ganze ist OOP-mäßig aufgebaut.
Vielleicht kann es jemand gebrauchen

Code: Alles auswählen

;--- USAGE:
;-

;-? CREATE ?
; New_Set() creates a new Set by the name of [1st parameter] containing elements of the given structure [2nd parameter]
; [1st param] is now an "object" with its own methods (Add(), Delete(), Contains())
NEW_SET(X, point)

;-? ADD ?
; Time to create some variables that we want to add to the set.
Define bla.point ; Define a variable with the structure that we used to initiate our set
bla\x =1
bla\y =2
Debug "Add 1/2: " + X\add(bla) ; Use the name of the set followed by "\add( var )" to add the variable "var" to the set.

bla\x =5
bla\y =6
Debug "Add: 5/6: " + X\add(bla) ; Add another variable

bla\x =1
bla\y =2
Debug "Add: 1/2: " + X\add(bla) ; Try adding a variable already contained in the set -> False


;-? CONTAINS ?
Define blub.point ; Let's create a variable and see if "it" (an identical element) is already contained in the set.
blub\x = 1
blub\y = 2
Debug "Does Set X contain [1/2]: " + X\contains(blub) ; \contains() returns #True (1) if found or #False (0) otherwise

Debug "Delete [1/2] from set"
X\delete(blub)
Debug "Does Set X contain [1/2]: " + X\contains(blub) ; \contains() returns #True (1) if found or #False (0) otherwise
Debug "Re-ad [1/2] to the set: " +  X\add(bla)


;-? CUSTOM FILTER ?
; This allows you to define a custom "filter" function to specify when exactly an item should be added. The default filter would prevent identical entries
; With a custom filter you could, as an example, specify that only POINT elements that are farther than N pixels away from 0.0 are added.
; Or "twins" of sorts. For example a ".point 3,1" must not be added when 1,3 or 3,1 are already in the set? A custom filter lets you achieve this. 
; The filter shown here is no filter at all. It just shows you quickly how to define a custom filter and how to access the elements already in the set 
; (To prevent double entries and such)
;
; The name of the parameters is arbitrary, as per normal procedure definition. 
; The Structure of the first parameter is the structure of your elements in your set (as defined in New_Set()). 
; The Structure of the second parameter is the actual name of your set (in this case "X"). 
; Unfortunately this means you can't use the same filter function for two sets (even though they might be virtually identical).
; This is a restriction laid upon us by the lack of OOP functionality. At least I wasn't able to find a work-around so far.

Procedure myFilter(*any.point, *bla.X)  
	Debug *bla\elements()\y	
EndProcedure 

; Lastly, you can "activate" this custom filter by using the Set_Filter() command. The first parameter is again the name of your set. 
; The second parameter the name of your filter function. I added the @ that is needed in the macro Set_Filter.
; If you're used to working with Callbacks and like the call using the @ more, simply edit the Macro to your needs ;-)
; Or you could just ignore the macro that I just added for esthetic reasons and use "X\FILTER = @myFilter()" where X is of course the name of your set again.

Set_Filter(X, myFilter())
X\FILTER = @myFilter()   ;use either line (not both ;-))


Include:

Code: Alles auswählen

;---BEGIN INCLUDE
EnableExplicit 
Structure STRUC ;Dummy Structure needed for the prototypes. Could use point or whatever, but this way it's clear that it's a dummy.
	DUMMY.i
EndStructure 

; Prototypes of the functions/methods the abstract data type "SET" should have.
Prototype Proto_Set_Add(*var.STRUC)
Prototype Proto_Set_Delete(*var.STRUC)
Prototype Proto_Set_Contains(*var.STRUC)
Prototype Proto_Set_FILTER(*var.STRUC, set)

Macro Set_Filter(SET, FILTERFUNCTION) ; Just a macro for esthetic reasons. See "> ?CUSTOM FILTER ?" in the USAGE section
	SET\FILTER = @FILTERFUNCTION
EndMacro 


Macro New_Set(NAME, STRUCT) ; The Macro that creates the "object".
	
	Structure NAME	; The structure of the "object". Contains pointers (prototyped) to the methods. A list of elements 
		SizeOf.i	; as well as the size of the user defined structure
		*contains.Proto_Set_Contains
		*add.Proto_Set_Add
		*delete.Proto_Set_Delete
		*FILTER.Proto_Set_FILTER
		List elements.STRUCT()
	EndStructure 	
	
	Define NAME.NAME				; Create the actual new Object Variable
	NAME\SizeOf = SizeOf(STRUCT)	; Save the size of the structure within the object variable, as it is needed for ComparyMemory() etc. later on.
	
	
	; Definition of the methods our data type uses:
	
	Procedure NAME#_FILTER(*IN.STRUCT, *NAME.NAME) ;FILTER() - RETURN FALSE to ABORT insertion
		
		ForEach *NAME\elements()
			If CompareMemory(*IN, *NAME\elements(), *NAME\SizeOf)
				ProcedureReturn #False
			EndIf 
		Next 
		
		ProcedureReturn #True  
	EndProcedure 
	
	
	
	Procedure NAME#_add(*var.STRUCT) ; add() - adds an element to the list. Uses the filter() function to check whether or not to add the element
		Shared NAME
		
		ForEach NAME\elements()
			If NAME\FILTER(*var, NAME)=#False
				ProcedureReturn #False
			EndIf 
		Next 
		
		AddElement(NAME\elements())
		CopyMemory(*var, @NAME\elements(), NAME\SizeOf)
		ProcedureReturn #True
	EndProcedure 
	
	
	Procedure NAME#_contains(*var.STRUCT) ; contains() - checks if an element is contained in the set.
		Shared NAME
			
		ResetList(NAME\elements())
		While NextElement(NAME\elements())
			
			If CompareMemory(*var, @NAME\elements(), NAME\SizeOf)
				ProcedureReturn #True
			EndIf 			
		Wend 
		
	EndProcedure 	
	
	
	Procedure NAME#_delete(*var.STRUCT) ; delete() - Delete an element from the set.
		Shared NAME
		
		ForEach NAME\elements()
			If CompareMemory(*var, NAME\elements(), NAME\SizeOf)
				DeleteElement(NAME\elements(), #True)
			EndIf 
		Next 
				
	EndProcedure 
	
	NAME\contains 		= @NAME#_contains()		;Add Functions to Object Variable
	NAME\add 			= @NAME#_add()			;Add Functions to Object Variable
	NAME\delete 		= @NAME#_delete()		;Add Functions to Object Variable
	NAME\FILTER 		= @NAME#_FILTER()		;Add Functions to Object Variable
EndMacro 

DisableExplicit 
;--- END INCLUDE

Re: Abstrakter Datentyp: Set (mehr oder weniger)

Verfasst: 20.07.2015 12:52
von NicTheQuick
Es wäre noch wichtig zu erwähnen, dass das ganze nicht funktioniert, wenn in der Struktur Strings, Listen, dynamische Arrays oder Maps enthalten sind.