aktuelles Element einer LinkedList()

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
stab
Beiträge: 96
Registriert: 24.02.2006 16:09
Computerausstattung: 286er Big Tower; 16MHz; 1MB Ram; 40MB Festplatte, 5 1/4" und 3 1/2" Diskettenlaufwerk; VGA Farbmonitor 14"; Windows 3.1; PureBasic 0.5
Wohnort: Hardt
Kontaktdaten:

aktuelles Element einer LinkedList()

Beitrag von stab »

Hallo,

lt. Hilfe gibt es ja mind. 2 Möglichkeiten, sich ein Element in einer LinkedList() merken zu wollen.

Code: Alles auswählen

*Old_Element = @mylist()   ; Ermittelt die Adresse des aktuellen Elements
ChangeCurrentElement(mylist(), *Old_Element) ; Wiederherstellen des letzten aktuellen Elements (von vor der Suche)
und mittels

Code: Alles auswählen

PushListPosition(Numbers())
PopListPosition(Numbers())
Gibt es bei den Methoden entscheidende Vor- und Nachteile?

Danke, danke !!
Zuletzt geändert von stab am 14.05.2014 17:51, insgesamt 1-mal geändert.
Paul sagt: "Max lügt."
Max sagt: "Otto lügt."
Otto sagt: "Max und Paul lügen."

Wer lügt hier wirklich und wer sagt die Wahrheit?

_________________________________________

286er Big Tower; 16MHz; 1MB Ram; 40MB Festplatte, 5 1/4" und 3 1/2" Diskettenlaufwerk; VGA Farbmonitor 14"; Windows 3.1; PureBasic 0.5
Benutzeravatar
Kiffi
Beiträge: 10711
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: aktuelles Element einer LinkedList()

Beitrag von Kiffi »

hier noch die dritte:

Code: Alles auswählen

ListIndex = ListIndex(Numbers())
SelectElement(Numbers(), ListIndex)
zu Vor- und Nachteilen kann ich nichts sagen.

Grüße ... Kiffi
a²+b²=mc²
BSP
Beiträge: 201
Registriert: 01.02.2009 14:04

Re: aktuelles Element einer LinkedList()

Beitrag von BSP »

Hallo stab.

Ich arbeite gerade sehr stark mit Listen und kann vielleicht etwas dazu sagen:
Ich bastel gerad (mal wieder) an einem Steuerprg. für meine Modelbahn.
Früher habe ich das mit Arrays gemacht, nun benutze ich mal Listen.
Aber ich gestehe, das nächste mal mache ich das wieder mit Arrays.

Du kannst Dir immer nur den Zeiger oder die Nummer auf das Element merken, das gerade aktuell ist.
(Aber das ist bei Listen grundsätzlich so).
Mein_drittes_element = @Liste
Oder:
Mein_drittes_element = ListIndex(Liste())
Was aber, wenn gerade das 5te Element aktuell ist?

Zur Frage:
PushListPosition(Numbers())
PopListPosition(Numbers())

Diese Anweisungen arbeiten mit einem Stapel.
Das heisst:
Das zuletzt gemerkte wird als erstes wieder hergestellt.
Das zu verstehen ist wichtig.
Du kannst damit kein Element direkt anspringen und wiederherstellen.
Verzählst Du Dich beim wiederherstellen, landes Du in einem falschen Element und suchst Dich bei der Fehlerfindung tot.
Ich persönlich benutze das garnicht.

*Old_Element = @mylist() ; Ermittelt die Adresse des aktuellen Elements
ChangeCurrentElement(mylist(), *Old_Element) ; Wiederherstellen des letzten aktuellen Elements (von vor der Suche)

Diese Möglichkeit ist sehr schnell, da Du ein Element „direkt“ anspringen kannst.
Es arbeitet mit Zeigern auf den Speicherort im Pc, wo die Elemente sich befinden.
Diese Zeiger musst Du Dir ermitteln und merken. (*Old_Element = @mylist())
Du solltest sie z.B. nicht speichern, da die Zeiger in einem späteren Neustart des Prg wahrscheinlich nicht mehr stimmen.
Das Prg legt die Liste vielleicht an einem ander Ort im Speicher ab und dann stimmen die Zeiger nicht mehr.
Du musst die Adressen nach einem Prg- Start neu ermitteln und eventuell bei Bedarf in einer weiteren Liste (einem Array ?) speichern.

ChangeCurrentElement(mylist(), *Old_Element) konntroliert nicht, ob es das Element gibt.
Es geht ja auch „ChangeCurrentElement(mylist(), 0)
Dann kann es an anderen Stellen im Prg zum Absturz kommen, und dann heraus zu finden, wo Deine Zeiger falsch eingestellt wurden, kann sehr schwer werden.

Ich arbeite z.Z. mit mehreren Listen deren Elemente auch noch abhängigkeiten zueinander haben.
Daher finde ich es teilweise sehr unübersichtlich, jedesmal
ChangeCurrentElement(mylist(),Mein_xtes_element)
aufzurufen. Oder die gesuchten Elemente erst einmal zu ermitteln.

If SelectElement(Numbers(), ListIndex)
Hat den Vorteil, Du kannst damit direkt das xte Element anspringen. (So vorhanden).
Das dritte Element ist immer das Dritte, egal wo die Liste im Speicher ist.
Die Methode ist aber langsamer, weil die Liste intern jedesmal durchlaufen wird, bis das gewünschte Element erreicht ist.
Diese Nummern kannst Du aber speichern.

Gruß : Bernd
PB 5.31 (x86) & (x64) Win10
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: aktuelles Element einer LinkedList()

Beitrag von ts-soft »

Eine weitere Möglichkeit, die aber nur bedingt passt, wäre das Beispiel aus der Hilfe:
Verwendung einer Map zur Indexierung einer verketteten Liste
zu finden im "Einsteiger-Kapitel".
Entspricht mehr oder weniger aber der SelectElement Variante, aber etwas komfortabler :wink:

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
stab
Beiträge: 96
Registriert: 24.02.2006 16:09
Computerausstattung: 286er Big Tower; 16MHz; 1MB Ram; 40MB Festplatte, 5 1/4" und 3 1/2" Diskettenlaufwerk; VGA Farbmonitor 14"; Windows 3.1; PureBasic 0.5
Wohnort: Hardt
Kontaktdaten:

Re: aktuelles Element einer LinkedList()

Beitrag von stab »

Danke für die Antworten. Mittels PUSH und POP sollte es dann funktionieren.

Meine Intention:

Ich fülle 3 Listen mit Dateiinformationen aus einem Netzwerk.
Dies können 1ne oder auch 1000 sein.
Danach werden Informationen aus den Listen nacheinander abgerufen.
Da Netzwerk = manchmal lansam dauert dieser Vorgang entsprechend.
Ich möchte diese Listen gerne im Thread füllen und gleichzeitig schon mit der Abarbeitung der Listen beginnen.
Dazu muss ich mir halt das jeweilige Element merken, um die Reihenfolge einzuhalten. Ich denke, das bekomme ich auch hin.

Ich habe es nur noch nicht geschafft, eine LinkedList() einer ThreadProzedur zu übergeben.
Ich kann es zwar auch anders lösen, fände es aber geschickter und würde auch gerne wissen, wie es geht.
Das sollte doch mittels einer Structure gehen. Einfache Beispiele finde ich aber nicht.
Kann mir jemand einen Link geben oder ganz einfach die Übergabe mal zeigen?

Danke!
Paul sagt: "Max lügt."
Max sagt: "Otto lügt."
Otto sagt: "Max und Paul lügen."

Wer lügt hier wirklich und wer sagt die Wahrheit?

_________________________________________

286er Big Tower; 16MHz; 1MB Ram; 40MB Festplatte, 5 1/4" und 3 1/2" Diskettenlaufwerk; VGA Farbmonitor 14"; Windows 3.1; PureBasic 0.5
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: aktuelles Element einer LinkedList()

Beitrag von ts-soft »

stab hat geschrieben:Ich habe es nur noch nicht geschafft, eine LinkedList() einer ThreadProzedur zu übergeben.
Das macht ja auch nicht unbedingt Sinn. Da die Liste sowieso per Mutex gesichert werden muß, damit nur ein Thread
zur selben Zeit darauf zugreifen kann, spricht nichts dagegen, eine globale oder shared Liste zu nutzen.

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Deluxe0321
Beiträge: 336
Registriert: 19.05.2006 00:31
Kontaktdaten:

Re: aktuelles Element einer LinkedList()

Beitrag von Deluxe0321 »

Als bsp für eine queue (copy & pasta aus projekt - entschuldigt mögliche nicht abgefangene fehler):

Code: Alles auswählen

DeclareModule Processor
  
  Enumeration ;CMD
    #CMD_FIRST
    #CMD_RUN
    #CMD_LOAD
    #CMD_BUILD
    #CMD_GET
    #CMD_POST
    #CMD_END
    #CMD_LAST
  EndEnumeration
  
  Enumeration ;TStatus
    #STATUS_ON
    #STATUS_OFF
  EndEnumeration  
    
  Declare Init()
  
  Declare PostCMD(Handle.i,CMD.i,*UserData = 0)
  
  Declare Release(Handle.i,Wait.i = #True)
  
EndDeclareModule

Module Processor
  
  ;{ - internal
  Structure List_MyList
    CMD.i
    *Data
  EndStructure
  
  Structure Processor
    HSemaphore.i
    HMutex.i
    TStatus.i
    TThreadID.i
    List LElements.List_MyList() ;< -- liste
  EndStructure

  Macro IsHandle() 
    If Not Handle.i : ProcedureReturn #False : EndIf 
  EndMacro
  
  Procedure Processor(*Processor.Processor)
    
    Protected SElement.List_MyList
    Protected HSemaphore.i, HMutex.i
    
    If Not *Processor
      ProcedureReturn #False  
    EndIf    
    
    LockMutex(*Processor\HMutex.i)
      *Processor\TStatus.i = #STATUS_ON
    UnlockMutex(*Processor\HMutex.i)
    
    Debug "Processor starting.."
    
    Repeat
      
      Debug "<-- Waiting for CMD :)"
      
      WaitSemaphore(*Processor\HSemaphore.i)
      
      LockMutex(*Processor\HMutex.i)
        ResetList(*Processor\LElements())
        FirstElement(*Processor\LElements())
        CopyStructure(@*Processor\LElements(),@SElement,List_MyList)
        DeleteElement(*Processor\LElements())
      UnlockMutex(*Processor\HMutex)
      
      Select SElement\CMD.i
        Case  #CMD_RUN
          Debug " --> #CMD_RUN"
          ;delay um etwas "workload" zu simulieren
          Delay(2000)
        Case  #CMD_LOAD
          Debug " --> #CMD_LOAD"
          ;delay um etwas "workload" zu simulieren
          Delay(300)
          
        Case  #CMD_BUILD
          Debug " --> #CMD_BUILD"
          ;delay um etwas "workload" zu simulieren
          Delay(6000)          
          
        Case  #CMD_END  
          Debug " --> #CMD_END --> ENDE!"
          
          LockMutex(*Processor\HMutex.i)
            *Processor\TStatus.i = #STATUS_OFF
          UnlockMutex(*Processor\HMutex.i)
          
          Debug "<-- ending now.."
          
          Break
          
      EndSelect
      
    ForEver
    
    
  EndProcedure
  
  ;} - internal
  
  Procedure Init()
    
    *Processor.Processor = AllocateMemory(SizeOf(Processor))
    
    If Not *Processor : ProcedureReturn #False : EndIf
    
    InitializeStructure(*Processor,Processor)
    
    *Processor\HMutex     = CreateMutex()
    *Processor\HSemaphore = CreateSemaphore()
    
    ;start thread
    *Processor\TThreadID.i = CreateThread(@Processor(),*Processor)
    
    If Not *Processor\TThreadID.i
      FreeMutex(*Processor\HMutex.i)
      FreeSemaphore(*Processor\HSemaphore.i)
      ClearStructure(*Processor,Processor)
      FreeMemory(*Processor)
    EndIf
    
    ProcedureReturn *Processor
    
  EndProcedure  
  
  Procedure PostCMD(Handle.i,CMD.i,*UserData = 0)
    
    IsHandle()
    
    If Not (CMD.i > #CMD_FIRST And CMD.i < #CMD_LAST) 
      ProcedureReturn #False 
    EndIf
    
    Protected *Processor.Processor = Handle.i
    
    LockMutex(*Processor\HMutex)
      If AddElement(*Processor\LElements())
        With *Processor\LElements()
          \CMD.i = CMD.i 
          \Data  = *UserData
        EndWith
      Else
        UnlockMutex(*Processor\HMutex)
        ProcedureReturn #False
      EndIf
      
    UnlockMutex(*Processor\HMutex)
    
    SignalSemaphore(*Processor\HSemaphore.i)
    
    ProcedureReturn #True
    
  EndProcedure
  
  Procedure Release(Handle.i,FinishQueue.i = #True)
    
    IsHandle()
    
    Protected *Processor.Processor = Handle.i
    
    If Not Wait.i
      LockMutex(*Processor\HMutex.i)
        ClearList(*Processor\LElements())
      UnlockMutex(*Processor\HMutex.i)
    EndIf

    ;"ende" senden
    PostCMD(*Processor,#CMD_END)    

    While IsThread(*Processor\TThreadID.i)
      Delay(10)
    Wend 
    
    FreeMutex(*Processor\HMutex.i)
    FreeSemaphore(*Processor\HSemaphore.i)
    
    ClearStructure(*Processor,Processor)
    FreeMemory(*Processor)
    
    Debug "release done!"
    
    ProcedureReturn #True
    
  EndProcedure  
  
  
EndModule


Process = Processor::Init()

If Not Process : End : EndIf
  
OpenConsole("Queue Test")
Repeat
  
  PrintN("CMD: (type them) -->  run, load, build, end") 
  
  Line.s = Input()
  
  Select LCase(Line.s)
    Case "run"
      Processor::PostCMD(Process,Processor::#CMD_RUN)
      PrintN(" --> RUN send, check debug output..") : PrintN("")
    Case "load"
      Processor::PostCMD(Process,Processor::#CMD_LOAD)
      PrintN(" --> LOAD send, check debug output..") : PrintN("")
    Case "build"
      Processor::PostCMD(Process,Processor::#CMD_BUILD)
      PrintN(" --> BUILD send, check debug output..") : PrintN("")
    Case "end"
      PrintN(" --> END send, check debug output..")
      If Processor::Release(Process)
        Break  
      EndIf
    Default
      PrintN("kenne ich nicht =P")
  EndSelect
  
ForEver
Grüße
Ich habe keine Lösung, aber ich bewundere das Problem.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: aktuelles Element einer LinkedList()

Beitrag von NicTheQuick »

Mit einer ConcurrentQueue kann ich auch dienen: Video: [PB] HowTo: ConcurrentQueue. Und hier noch mal auf meiner Seite: Wie schreibe ich eine ConcurrentQueue.
Benutzeravatar
stab
Beiträge: 96
Registriert: 24.02.2006 16:09
Computerausstattung: 286er Big Tower; 16MHz; 1MB Ram; 40MB Festplatte, 5 1/4" und 3 1/2" Diskettenlaufwerk; VGA Farbmonitor 14"; Windows 3.1; PureBasic 0.5
Wohnort: Hardt
Kontaktdaten:

Re: aktuelles Element einer LinkedList()

Beitrag von stab »

Hallo,

danke noch mal für die Tipps.
Das Video von NicTheQuick hatte ich mir schon vorher mal angesehen und gestaunt, wie einfach doch programmieren sein kann.
Ich bekomme aber schon Stirnrunzeln, wenn ich die zwei "::" sehe, kann damit garnichts anfangen und weiß auch nicht, ob das in den Anfängerbereich gehört. Ich finde dazu auch nichts in der Hilfe. Suchen kann man danach jedenfalls nicht. Vielleicht zeigt mir jemand mal, wo das erklärt wird.

Warum nicht Listen in eine ThreadProzedur übergeben?
Ich finde, das macht schon Sinn. Wenn ich 10 Listen bearbeiten will, müsste ich ja 10 Prozeduren anlegen. Bei einer Programmänderung ganz schön aufwendig.

Also, was ich gesucht habe war ein simples Beispiel für Anfänger, nach langem probieren hat es dann geklappt:

Code: Alles auswählen

Structure mitlisten
   List zahlen.l()
EndStructure

Procedure ListeImThread(*zeiger.mitlisten)
    LastElement(*zeiger\zahlen())
    AddElement(*zeiger\zahlen())
    *zeiger\zahlen() = 1
EndProcedure
  
Define.mitlisten adresse
  
CreateThread(@ListeImThread(),@adresse)
  
; etc
Daraus gemacht habe ich folgendes:

Code: Alles auswählen


Structure mitlisten
   List zahlen.l()
   List namen$()
   ; usw
EndStructure

Global listposition = 0
Global MaxListgroesse = 20

Procedure ListeImThread(*zeiger.mitlisten)
  For z = 0 To MaxListgroesse -1
    d.l = Random(3,1)*1000
    Delay (d)
    LastElement(*zeiger\zahlen())
    AddElement(*zeiger\zahlen())
    *zeiger\zahlen() = d + z
    Debug "neuer Wert nach: "  + Str(d/1000) + " Sekunden:  " + Str(d+z)
  Next
  
  ; z.B noch weitere Listen bearbeiten
  AddElement(*zeiger\namen$()) : *zeiger\namen$() = "Willi"
  AddElement(*zeiger\namen$()) : *zeiger\namen$() = "Moritz"
    
EndProcedure
  
Define.mitlisten adresse
  
CreateThread(@ListeImThread(),@adresse)
  
Procedure leseListe(List z.l())
  If ListIndex(z()) =  MaxListgroesse -1
    listposition = 0
  EndIf  
  If ListSize(z()) > listposition
    SelectElement(z(), listposition)
    Debug "Juhu: " + Str(z())
    listposition +1
  Else
    Debug "Mist! Nichts neues!"
  EndIf
EndProcedure
  
Repeat
  leseListe(adresse\zahlen())
  Delay(1500)
ForEver
Die Liste wird im Hintergrund gefüllt. Mal schneller, mal langsamer.
Ich kann aber schon daraus lesen, sofern Elemente vorhanden sind.

Bisher hat es funktioniert.
Oder spricht irgendwas dagegen, das so umzusetzen?

vg stab
Zuletzt geändert von stab am 14.05.2014 17:50, insgesamt 1-mal geändert.
Paul sagt: "Max lügt."
Max sagt: "Otto lügt."
Otto sagt: "Max und Paul lügen."

Wer lügt hier wirklich und wer sagt die Wahrheit?

_________________________________________

286er Big Tower; 16MHz; 1MB Ram; 40MB Festplatte, 5 1/4" und 3 1/2" Diskettenlaufwerk; VGA Farbmonitor 14"; Windows 3.1; PureBasic 0.5
Benutzeravatar
stab
Beiträge: 96
Registriert: 24.02.2006 16:09
Computerausstattung: 286er Big Tower; 16MHz; 1MB Ram; 40MB Festplatte, 5 1/4" und 3 1/2" Diskettenlaufwerk; VGA Farbmonitor 14"; Windows 3.1; PureBasic 0.5
Wohnort: Hardt
Kontaktdaten:

Re: aktuelles Element einer LinkedList()

Beitrag von stab »

Ich sehe gerade, habe Quote mit Code verwechselt.
Sorry.
Paul sagt: "Max lügt."
Max sagt: "Otto lügt."
Otto sagt: "Max und Paul lügen."

Wer lügt hier wirklich und wer sagt die Wahrheit?

_________________________________________

286er Big Tower; 16MHz; 1MB Ram; 40MB Festplatte, 5 1/4" und 3 1/2" Diskettenlaufwerk; VGA Farbmonitor 14"; Windows 3.1; PureBasic 0.5
Antworten