zwei Listen aneinanderhängen

Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Neue Antwort erstellen

UNZ

Betreff: zwei Listen aneinanderhängen

BeitragMo, Dez 24, 2012 15:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Moin Moin,

wie der Titel schon sagt, möchte ich zwei TLists aneinanderhängen, dass heißt aus zwei Listen soll eine werden.
Ich hatte gedacht, dafür gibts was vordefiniertes, aber ich finde im codearchiv/forum nichts und google konnte mir auch nicht helfen.

Man muss doch nur den letzen Link der ersten Liste auf das erste Element in der zweiten Liste zeigen lassen, um sie zu verketten, oder?

Aber wie macht man das?
Das muss besser als perfekt!

Thunder

BeitragMo, Dez 24, 2012 17:52
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich würde dem zu gerne nachgehen, aber ich habe mein BlitzMax nicht mit im Urlaub. Du scheinst dich aber eh damit auszukennen - und das Folgende gilt jetzt auch für die Sache mit TextAreaText: wenn man einen Blick in den Quelltext der Module wagt, lohnt sich das oft (->Lerneffekt, weil man selber draufgekommen ist). Kann natürlich sein, dass man in den Sources nix findet, also auch nicht verzweifeln Wink

Hatte jetzt nur die BlitzMax-Hilfe zur Verfügung und hab auch nicht lang geschaut, aber wenn du was schnelles, dreckiges brauchen kannst:
Code: [AUSKLAPPEN]
list = TList.FromArray(list.ToArray() + list2.ToArray())
Meine Sachen: https://bitbucket.org/chtisgit https://github.com/chtisgit
 

PhillipK

BeitragMo, Dez 24, 2012 19:52
Antworten mit Zitat
Benutzer-Profile anzeigen
Das, in array umwandeln und zurück umwandeln, hätte ich auch vorgeschlagen.
Leider war mir das ZU dreckig Smile

Die simpelste form wäre doch immernoch:
BlitzMax: [AUSKLAPPEN]
Local list1:TList = CreateList ()
Local list2:TList = CreateList()
....
For Local obj:Object = EachIn list2
list1.addLast(obj)
Next


hat so ziemlich den selben effekt.

Nun vermutungen:
Es kann sein, das die TList den ersten und / oder letzten link hält.
Ausserdem haben TLinks _value etc, als felder. da müsste auch eine art _prev _succ oder sonstwas bei sein. Keine ahnung genau, aber irgendwas in der art existiert, und eines davon musst du ändern Smile
Spiel einfach rum, wird schon hinhaun Smile
(und natürlich Liste.firstLink() und liste.LastLink() nicht vergessen!)

Tennisball

BeitragMo, Dez 24, 2012 20:22
Antworten mit Zitat
Benutzer-Profile anzeigen
Hi,

Hab's mal ausprobiert.

BlitzMax: [AUSKLAPPEN]
SuperStrict


Type TTest
Field X:Int
End Type


Local List1:TList = CreateList()
Local List2:TList = CreateList()


Local I:Int
Local Test:TTest

For I = 1 To 20
Test = New TTest
Test.X = I
If I < 11 Then
List1.AddLast( Test )
Else
List2.AddLast( Test )
End If
Next


List1.LastLink()._succ = List2.FirstLink()
List2.FirstLink()._pred = List1.LastLink()


For Test = EachIn List1
Print Test.X
Next


Funktioniert tatsächlich.

Gruß,
Tennisball

Nova

BeitragMo, Dez 24, 2012 20:31
Antworten mit Zitat
Benutzer-Profile anzeigen
Kein Quellcode, nur eine Idee (vielleicht geht das gar nicht)

Ich würde ja versuchen, beim letzten Element der ersten Liste die "nächster"-Variable auf das erste Element der zweiten Liste zu setzen (und umgekehrt). Wäre eine schöne Sache, falls es funktioniert. Wink
AMD Athlon II 4x3,1GHz, 8GB Ram DDR3, ATI Radeon HD 6870, Win 7 64bit
 

PhillipK

BeitragMo, Dez 24, 2012 20:57
Antworten mit Zitat
Benutzer-Profile anzeigen
Tennisball, nova, ihr habt recht.

Es funktioniert, wenn man liste1 letzter link auf liste2 erster link pointert, und umgekehrt.
ABER:
Das setzt die grundlegenden listenfunktionen ausser gefecht.

Nach ein wenig stöbern ist mir dann aufgefallen, das tlist ein "._head" hat. Dies ist ein leerer link, welcher mit _succ auf den ersten link zeigt sowiet mit _pred auf den letzten link.
Dieser _head link ist essentziell für zb Count(), da intern immer ein "solange weitermachen, bis der aktuell zu prüfende link = _head ist" vorherrscht.
Dies muss umbedingt mit geändert werden:

Liste1._head._pred = Letzter link liste 2
liste2.LastLink()._succ = head liste 1

Meine funktion:
BlitzMax: [AUSKLAPPEN]

Local list1:TList = CreateList()
For Local i:Int = 1 To 10
list1.AddLast("Zahl " + i)
Next
Local list2:TList = CreateList()
For Local i:Int = 11 To 20
list2.AddLast("Z4h1 " + i)
Next

'aufbau:
' _succ zeigt auf den nächsten Link. der letzte link hält immer _head (ein leerer link) als _succ.
' _head._pred zeigt auf den letzten, _head._succ zeigt auf den ersten link.
'link2._pred = link1 'erster link liste 2, vorgänger auf den letzten link liste1 .
'link1._succ = link2 'letzter link liste 1, nachfolger auf den ersten link von liste2 .
'list1._head._pred = list2._head._succ 'den head von liste1 anpassen, sodass er auf den neuen, letzten link zeigt
'list2.lastLink()._succ = list1._head 'den nachfolger vom letzen link in liste2 auf den head von liste 1 setzen
'Nun sind die links neu verkabelt. Aber das ganze ist sehr unsauber! Das WIRD zwangsweise die 2te liste zerstören, da diese nicht nutzbare links enthält.
'hier mal als funktion:
Function MergeLists:TList(liste:TList, toInsert:TList)
Local endLink:TLink = liste._head._pred
Local startLink:TLink = toInsert._head._succ
Local head:TLink = liste._head
Local newEndLink:TLink = toInsert._head._pred
Print("wtf")
endLink._succ = startLink
startLink._pred = endLink
newEndLink._succ = head
head._pred = newEndLink

toInsert._head._pred = toInsert._head 'clear funzt nichtmehr: Selbst die links entkoppeln. SIE SIND NICHT GELÖSCHT! Aber werden vom Garbage Collector eingesammelt
toInsert._head._succ = toInsert._head 's.o.

Return liste
End Function

MergeLists(list1, list2)

For Local str:String = EachIn list1
Print("String: " + str)
Next
Print("Anzahl einträge in list1: " + list1.Count())
Print("Anzahl einträge in list2: "+list2.count())


Ein paar anmerkungen:

Der kommentarbetzen ernhält die erste variante wie ich es getestet hab. Ist nur sch... unleserlich gewesen. Ich lasse es einfach mal drin.

_Head._pred = Letzter link. Nach dem mergen wirds also der letzte link aus der einzufügenden liste sein.
Dieser besagte letzte link muss nun auch ausserdem auf _head zeigen.

DAS MERGEN AUF DIESE WEISE (ohne kopieren sämtlicher links) WIRD DIE 2te LISTE UNWEIGERLICH ZERSTÖREN!!!
Nichtmal mehr toInsert.Clear() ging mehr.

Deshalb habe ich sicherheitshalber die liste von hand "geleert", dh die Tlink kette entfernt, sodass die toInsert liste für das programm leer ist.
Die Links sind derweil zwar noch im ram, sollten aber vom GarbageCollector entfernt werden.

Hoffe ich konnte helfen. Wenns zu undeutlich war, einfach nochmal nachfragen. Ps: Tut mir leid, das sibly & co so bescheuerte kurznamen gewählt haben.. _pred und _succ sind irgendwie nicht aussagekräftig für mich :3

Meine erkenntnis:
_pred = vorgänger link
_succ = nachfolger link

_head = masterlink, welcher sowohl auf den letzten wie auf den ersten link einer liste zeigt.

BladeRunner

Moderator

BeitragMo, Dez 24, 2012 21:03
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich halte das Verbinden per umschreiben der _head etc.-fields btw für wesentlich dreckiger als das kurze umcasten in ein Array und zussammenführen in dieser Form, da hier keine Liste zerstört (und somit Datenmüll) wird.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92
 

PhillipK

BeitragMo, Dez 24, 2012 21:38
Antworten mit Zitat
Benutzer-Profile anzeigen
der punkt geht an dich, BR Smile
allerdings ist beim umcasten in einen array wahrscheinlich mehr leistung gefordert, wie die kleinere liste durchgehen und den inhalt der größeren liste hinzuzufügen.

Alles in allem kommts auf den nutzen an, wie ich feststellen musste.
Wenn man, warum auch immer, 2 getrennte listen erschafft und am ende nur eine braucht (und deshalb mergen möchte), ist der umschreibe weg der _head links etc der schnellste, da hier praktisch nur 4 pointer geändert werden.

Hier ist es egal, wie groß die listen sind.
Alle anderen möglichkeiten (for each + addlast sowie 2 arrays erschaffen, zusammenfügen (braucht nochmal extrem, da 2 arrays addieren direkt den platz für die kombi fordert)) dauern länger je mehr objekte in liste 1, liste 2 bzw beim array weg in liste 1 + 2 sind.

Kurzum: Muss jeder selbst wissen, ist alles ziemlich dreckig, auf seine art Smile

(habe eben überlegt, ob man nicht die schlüssel-links, sprich die zu kombinierenden sowie den letzten link der 2ten liste, nicht kopieren könnte.
Das wäre ein 2schneidiges schwert: Das würde klappen, aber auch nur solange, wie die 2te liste unangetastet bleibt. und selbst wenn man ihr was hinzufügt, kanns noch klappen. wird aber der vorletzte link geändert, gibts krieg)

UNZ

BeitragMi, Dez 26, 2012 1:31
Antworten mit Zitat
Benutzer-Profile anzeigen
Danke erstmal,

die zweite implementierung von PhillipK war genau, was ich gesucht hatte.
Das die Liste dabei draufgeht war mir klar aber ist für mich nicht relevant.

Zur Zeit habe ich es auch in der Form
Code: [AUSKLAPPEN]

Local list1:TList = CreateList ()
Local list2:TList = CreateList()
....
For Local obj:Object = EachIn list2
     list1.addLast(obj)
Next

bei mir umgesetzt.

Allerdings hat das dann eine Laufzeit abhängig von der Länge der Liste2.
Die konstante Laufzeit des "umsteckens" finde ich bei einer so wichtigen Datenstruktur wie einer Liste schöner.
Danke dafür Very Happy
Das muss besser als perfekt!

UNZ

BeitragMi, Dez 26, 2012 15:22
Antworten mit Zitat
Benutzer-Profile anzeigen
Es gab noch ein Problem mit einer leeren Liste.
Hab es deshalb noch etwas überarbeitet.

Code: [AUSKLAPPEN]

Local list1:TList[1000]
Local list2:TList[1000]
For Local j:Int = 0 To 999
   list1[j] = New TList
   For Local i:Int = 1 To 10
      list1[j].AddLast("A"+i)
   Next
   
   list2[j] = New TList
   If j Mod 2 = 0
      For Local i:Int = 1 To 10
         list2[j].AddLast("B"+i)
      Next
   EndIf
Next

'aufbau:
' _succ zeigt auf den nächsten Link. der letzte link hält immer _head (ein leerer link) als _succ.
' _head._pred zeigt auf den letzten, _head._succ zeigt auf den ersten link.
'link2._pred = link1 'erster link liste 2, vorgänger auf den letzten link liste1.
'link1._succ = link2 'letzter link liste 1, nachfolger auf den ersten link von liste2 .
'list1._head._pred = list2._head._succ 'den head von liste1 anpassen, sodass er auf den neuen, letzten link zeigt
'list2.lastLink()._succ = list1._head 'den nachfolger vom letzen link in liste2 auf den head von liste 1 setzen
'Nun sind die links neu verkabelt.
'Das ZERSTÖRT die zweite Liste, da diese nicht nutzbare links enthält.
Function appendLists(lst:TList Var, toInsert:TList Var)
   
   If lst = Null Or toInsert = Null
      Return
   EndIf
   If toInsert.isEmpty()
      Return
   EndIf
   
   Local endLink:TLink= lst._head._pred
   Local startLink:TLink= toInsert._head._succ
   Local head:TLink= lst._head
   Local newEndLink:TLink= toInsert._head._pred

   endLink._succ = startLink
   startLink._pred = endLink
   newEndLink._succ = head
   head._pred = newEndLink

   'destroy list
   toInsert._head._pred = toInsert._head
   toInsert._head._succ = toInsert._head
   toInsert = Null
End Function

GCCollect()
Print GCMemAlloced()

For Local i:Int = 0 To 999
   appendLists(list1[i], list2[i])
   'list2[i] = Null
Next

Print GCMemAlloced()
GCCollect()
Print GCMemAlloced()

If list1[0]
   Print("Anzahl einträge in list1: " + list1[0].Count() )
   For Local str:String = EachIn list1[0]
      Print("String: " + str)
   Next
EndIf

'////////////////////////////////////////////////////////////////////////////////////////////////////////////
'kann man so ins brl modul bei "linkedlist.bmx" werfen

Rem
bbdoc: Adds a list
about: The last link of this list is headed to the first link of the list to add.
            THIS DESTROYS THE LIST TO ADD!
end rem

Rem
Method append(toInsert:TList Var)
   
      'no list to add
      If toInsert = Null
         Return
      EndIf
      'list is empty -> add nothing
      If toInsert.isEmpty()
         Return
      EndIf
      
      Local endLink:TLink = _head._pred
      Local startLink:TLink = toInsert._head._succ
      Local head:TLink = _head
      Local newEndLink:TLink = toInsert._head._pred
      
      endLink._succ = startLink
      startLink._pred = endLink
      newEndLink._succ = head
      head._pred = newEndLink
      
      'destroy list
      toInsert._head._pred = toInsert._head
      toInsert._head._succ = toInsert._head
      toInsert = Null
End Method
end rem
Das muss besser als perfekt!

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group