Page 1 of 1

Posted: Fri Feb 14, 2003 11:45 pm
by BackupUser
Restored from previous forum. Originally posted by pythagoras.

hi everyone,

is it possible to make a linked list inside a linked list, and if so, how to access it ?
I've been trying to make something like this :

Code: Select all

Structure player
  name.s
  NewList gangs.GANG()  <-- This would be my second linked list
EndStructure
I then create a player linked list (newlist player_ll()) and try to access the nested linked list (gangs()) but i don't know how to nor if its possible that way.

Can anybody point me to the good solution.

Thanks in advance.

Pythagoras

Posted: Sat Feb 15, 2003 11:03 am
by BackupUser
Restored from previous forum. Originally posted by Pupil.

See if this helps you some:
viewtopic.php?t=2478

Posted: Sat Feb 15, 2003 11:48 am
by BackupUser
Restored from previous forum. Originally posted by pythagoras.
Originally posted by Pupil

See if this helps you some:
viewtopic.php?t=2478
Yes, it helps in a way but in the example you posted in that topic (see below) if i understand it correctly, does it mean that you need to create a new streets linked list for each new element of your database ?


pythagoras

-- original code below --

Code: Select all

structure StreetType
  name.s
  nr.w
  *parent
  *child
endstructure

structure DataBaseType
  name.s
  etc.l
  *street
endstructure

newlist streets.StreetType()
newlist database.DataBaseType()

; ok now add an entry
addelement(database())
addelement(streets())
database()\name = "Vain"
database()\street = @streets()
*ptr.StreetType = @streets()
street()\name = "somewhere"
; he lives on another address too so..
addelement(street())
street()\name = "somewhere else"
*ptr\child = @street()

; now you can access this structure like this
resetlist(database())
while nextelement(database())
  *ptr = database()\*street
  if *ptr ; we have a street
    debug *ptr\name
    while *ptr\child
      *ptr = *ptr\child
      debug *ptr\name
    wend
  endif
wend

Posted: Sat Feb 15, 2003 12:08 pm
by BackupUser
Restored from previous forum. Originally posted by tinman.

You could use my linked list procedures whcih I posted to the resources site: http://www.reelmediaproductions.com/pb/ ... ppets.html. Linked lists inside linked lists is something I specifically wrote it for.

--
It's not minimalist - I'm increasing efficiency by reducing input effort.
(Win98first ed. + all updates, PB3.51, Ed3.53)

Posted: Sat Feb 15, 2003 1:08 pm
by BackupUser
Restored from previous forum. Originally posted by pythagoras.
Originally posted by tinman

You could use my linked list procedures whcih I posted to the resources site: http://www.reelmediaproductions.com/pb/ ... ppets.html. Linked lists inside linked lists is something I specifically wrote it for.
I'll have a look at it. Thanks for the tip:)

pythagoras

Posted: Sat Feb 15, 2003 1:13 pm
by BackupUser
Restored from previous forum. Originally posted by Pupil.

>Yes, it helps in a way but in the example you posted in that topic (see below) if
>i understand it correctly, does it mean that you need to create a new streets linked
>list for each new element of your database ?

No, you just add a new element. Might be that tinman's way is better, haven't tried his stuff but it's worth to take a look at it...

Posted: Sat Feb 15, 2003 5:48 pm
by BackupUser
Restored from previous forum. Originally posted by pythagoras.

I've used tinman's method and it seems to work even though i find it a bit confusing (but maybe i'm doing it wrong).
This is how i do it :

Code: Select all

structure GANG
    Id.b
EndStructure

Structure GANGLIST
    lw_Node.ListNode
    *gang.GANG
EndStructure

Structure PLAYER
    *mylist.ListHeader
    *gangs.GANGLIST
EndStructure

Dim player.PLAYER(3)
exterminators.GANG


dll_NewList(@player(0)\mylist, SizeOf(PLAYER) - SizeOf(ListNode))
player(0)\gangs = dll_AddElement(@player(0)\mylist)
player(0)\gangs\gang = @exterminators

dll_NewList(@player(1)\mylist, SizeOf(PLAYER) - SizeOf(ListNode))
player(1)\gangs = dll_AddElement(@player(1)\mylist)
player(1)\gangs\gang = @exterminators
Is this the good way of doing it ?

Pythagoras

Posted: Sat Feb 15, 2003 11:20 pm
by BackupUser
Restored from previous forum. Originally posted by tinman.
Originally posted by pythagoras

Is this the good way of doing it ?
No. You have used pointers in some places where you should not. It's my fault, the documentation provided with the code isn't too great.

Here is an example showing how to use linked lists inside linked lists. The main thing to get right is the way you pass a pointer to the linked lists. But generally once you have done it correctly once then it never changes. If you have more questions please ask.

Code: Select all

xincludefile "double_linked_lists.pb"


; Simple structure for storing data about all characters
; or people (as an example)
Structure Character
    c_Node.ListNode     ; This must be the first item, and should be a regular variable, not a pointer

    ; Now you put all the data you want to store in the structure
    ; Only name for now since this is simple
    c_Name.s        ; Character name
EndStructure


; Simple structure for storing a list of gangs
Structure Gang
    g_Node.ListNode     ; Again, this must be first since each gang will be stored in a list

    ; Now your data comes here
    g_Name.s                ; Gang name
    g_Hood.s                ; Area of control

    g_Members.ListHeader    ; List for the members of the gang. Thie list must not be a pointer
EndStructure


DefType.ListHeader  gang_list   ; The main list for storing gangs
DefType.Gang        *gang       ; Pointer to a gang item, for working with list
DefType.Character   *char       ; Pointer to a character item, for working with lists


If OpenConsole()

    PrintN(Str(dll_NewList(@gang_list, SizeOf(Gang) - SizeOf(ListNode))))

    Repeat
        Print("Enter gang name or leave blank to quit: ")
        gang_name.s = Input()
        PrintN("")

        If gang_name""
            ; Gang name entered, create new item
            *gang = dll_AddElement(@gang_list)

            ; make sure we only try to use it if successful
            If *gang
                *gang\g_Name = gang_name
                
                Print("Enter area of control: ")
                *gang\g_Hood = Input()
                PrintN("")

                ; Create the list for members - you must use the full
                ; name to the lh_Head field due to a bug in PB you cannot
                ; simply use the g_Member item.
                dll_NewList(@*gang\g_Members\lh_Head, SizeOf(Character) - SizeOf(ListNode))

                ; Now we add the gang members, in a similar way to
                ; when we create the gangs
                Repeat
                    Print("  Enter member name or leave blank to stop: ")
                    member_name.s = Input()
                    PrintN("")

                    If member_name""
                        *char = dll_AddElement(@*gang\g_Members\lh_Head)
                        If *char
                            *char\c_Name = member_name
                        EndIf
                    EndIf
                Until member_name=""
            EndIf
        EndIf
        
    Until gang_name=""


    ; Now we display the contents of the lists to show you it worked
    *gang = gang_list\lh_Head
    While *gang
        PrintN("The gang '"+*gang\g_Name+"' controls "+*gang\g_Hood+". Members are:")

        *char = *gang\g_Members\lh_Head
        While *char
            Debug *char
            PrintN("foo")
            PrintN("  "+*char\c_Name)
            
            *char = *char\c_Node\ln_Succ
        Wend

        PrintN("End of members")
        
        ; Move onto next item
        *gang = *gang\g_Node\ln_Succ
    Wend


    PrintN("Freeing memory")
    
    ; Call this to free up memory in each list
    ; First we go to the first item in the gangs
    *gang = gang_list\lh_Head

    ; And go round this loop until the pointer is null (end of gang list)
    While *gang

        ; Clear the list for members of the gang
        ; Must use the @ symbol to get the address of the start
        ; of the list header inside the gang item structure
        dll_DeleteList(@*gang\g_Members\lh_Head)

        ; Move onto next item
        *gang = *gang\g_Node\ln_Succ
    Wend


    ; Finally we must clear the main list
    dll_DeleteList(@gang_list)

    PrintN("Press return to exit")
    Input()
    CloseConsole()
EndIf

End

--
It's not minimalist - I'm increasing efficiency by reducing input effort.
(Win98first ed. + all updates, PB3.51, Ed3.53)

Posted: Sun Feb 16, 2003 12:17 am
by BackupUser
Restored from previous forum. Originally posted by pythagoras.
No. You have used pointers in some places where you should not. It's my fault, the documentation provided with the code isn't too great.

Here is an example showing how to use linked lists inside linked lists. The main thing to get right is the way you pass a pointer to the linked lists. But generally once you have done it correctly once then it never changes. If you have more questions please ask.
Your example is great and i understand my error. This is very close to what i want to achieve. I have a problem though, the example is crashing when attempting to create a second gang (ie. adding a second element to the gang_list). I'm looking into the code but can't figure the problem.

Anyway, thanks for your very useful help :)

Pythagoras

Posted: Sun Feb 16, 2003 10:29 am
by BackupUser
Restored from previous forum. Originally posted by tinman.
Originally posted by pythagoras

to what i want to achieve. I have a problem though, the example is crashing when attempting to create a second gang (ie. adding a second element to the gang_list). I'm looking into the code but can't
I'll take a look at it and post any fixes here. It was late last night and I didn't have much chance to fully test it :)

Update: OK, I figured out the problem and have uploaded a new archive (v1.5) to the Resources site (it includes a new version of the linked list code and an updated version of the above example). I had forgot to include a workaround for a PureBasic problem (you cannot directly pass something like *foo\blah\bar + Sizeof(whatever) to a procedure).

It seems to work, but let me know if you have any other problems.

--
It's not minimalist - I'm increasing efficiency by reducing input effort.
(Win98first ed. + all updates, PB3.51, Ed3.53)