// This sets up the variables
value[0] = "a"
value[1] = "b"
value[2] = "c"
value[3] = "d"
value[4] = "e"
next[0] = 2
previous[0] = 4
next[2] = 4
previous[2] = 0
next[4] = 0
previous[4] = 2
// This prints the values
local integer i = next[0]
loop
exitwhen i == 0 // Ends when back at the beginning (the 'head')
call BJDebugMsg(value[i]) // Prints "a" -> "c" -> "e"
set i = next[i]
endloop
// This will remove value 2 from the previous linked list
set next[previous[2]]=next[2]
set previous[next[2]]=previous[2]
// next[0] = next[2] --> next[0] = 4
// previous[4] = previous[2] --> previous[4] = 0
// It forgets about the value "2" completely
// The function above will now print "a" -> "e"
// This will add value 1 to the list
set next[0] = 1
set previous[2] = 1
set next[1] = 2
set previous[1] = 0
// The print-function will now say "abce"
library LinkedListLib
struct LinkedListNode
integer dataTag = 0
thistype next = 0
thistype prev = 0
method onDestroy takes nothing returns nothing
set dataTag = 0
set next = 0
set prev = 0
endmethod
static method create takes integer dataTag, thistype next returns thistype
local thistype node = allocate()
set node.dataTag = dataTag
if next != 0 then
set node.next = next
set node.prev = next.prev
if node.prev != 0 then
set node.prev.next = node
endif
set node.next.prev = node
else
set node.next = 0
set node.prev = 0
endif
return node
endmethod
endstruct
struct LinkedList
LinkedListNode top
LinkedListNode bot
integer size = 0
// Returns the size of the linked list.
method getSize takes nothing returns integer
return size
endmethod
// Clean linked list elements
method onDestroy takes nothing returns nothing
local LinkedListNode n = top
local LinkedListNode t
loop
exitwhen n == 0
set t = n
set n = n.next
call t.destroy()
endloop
endmethod
// Returns the extracted 'top' element.
method extractTop takes nothing returns integer
local LinkedListNode t
local integer tag = 0
if not isEmpty() then
set t = top
set tag = t.dataTag
set top = top.next
call t.destroy()
set size = size - 1
endif
return tag
endmethod
// Returns the extracted 'bot' element.
method extractBot takes nothing returns integer
local LinkedListNode b
local integer tag = 0
if not isEmpty() then
set b = bot
set tag = b.dataTag
set bot = bot.prev
call b.destroy()
set size = size - 1
endif
return tag
endmethod
// Returns true if there are no elements in the list.
method isEmpty takes nothing returns boolean
return top == 0
endmethod
// Add element to front (top) of list.
method addToFront takes integer dataTag returns nothing
if isEmpty() then
set top = LinkedListNode.create(dataTag, 0)
set bot = top
else
set top = LinkedListNode.create(dataTag, top)
endif
set size = size + 1
endmethod
// Add element to back (bot) of list.
method addToBack takes integer dataTag returns nothing
if isEmpty() then
set top = LinkedListNode.create(dataTag, 0)
set bot = top
else
set bot.next = LinkedListNode.create(dataTag, 0)
endif
set size = size + 1
endmethod
endstruct
endlibrary
Link
objects when you destroy your lists. He never iterates through the list and cleans up these references, instead he simply sets the head/tail values to 0 (which, if this were java, would work fine).Link
API) starts deleting the ones that follow. This means that if you want to destroy a linked-list node that is in a list, you've got to destroy the entire list. There seems to be something funky he does with xparent
which is making it harder to read. Yeah, I know (otherwise I wouldn't have been able to write what I did).Its a fairly commen programming data structure, the idea is you have nodes which are "linked" to each other, The advantage is you can add to the list in O(1) time, and since I don't need to look at specific indexes the O(n) search time won't be a problem.
This is what I didn't know. I kind of assumed you were mixing up terms when you said "I need a linked list" (it's an odd way of saying you need a library for it).I think I didn't make myself too clear, what I was looking for were a vjass library with everything made.
I'm pretty sure that Ammorth's version leaksLink
objects when you destroy your lists. He never iterates through the list and cleans up these references, instead he simply sets the head/tail values to 0 (which, if this were java, would work fine).
I also don't know why he uses an O(n) iteration just to determine the size of the linked list. You can determine this with a simple variable. I'll add it to the above code.
You can search for a value and then just destroy that link. Kinda nice if you need it.Wow I really don't get what the hell he was trying to do in that Linked List library. The entire API is for each node in the linked-list, rather than the linked-list itself.
Seems to work versus a tested libraryJust typed this up now, seems to work:
JASS:library LinkedListLib struct LinkedListNode integer dataTag thistype next thistype prev static method create takes integer dataTag, thistype next returns thistype local thistype node = allocate() set node.dataTag = dataTag if next != 0 then set node.next = next set node.prev = next.prev if node.prev != 0 then set node.prev.next = node endif set node.next.prev = node else set node.next = 0 set node.prev = 0 endif return node endmethod endstruct struct LinkedList LinkedListNode top LinkedListNode bot integer size = 0 // Returns the size of the linked list. method getSize takes nothing returns integer return size endmethod // Clean linked list elements method onDestroy takes nothing returns nothing local LinkedListNode n = top local LinkedListNode t loop exitwhen n == 0 set t = n set n = n.next call t.destroy() endloop endmethod // Returns the extracted 'top' element. method extractTop takes nothing returns integer local LinkedListNode t = top local integer tag = t.dataTag set top = top.next call t.destroy() set size = size - 1 return tag endmethod // Returns true if there are no elements in the list. method isEmpty takes nothing returns boolean return top == 0 endmethod // Add element to front (top) of list. method addToFront takes integer dataTag returns nothing if isEmpty() then set top = LinkedListNode.create(dataTag, 0) set bot = top else set top = LinkedListNode.create(dataTag, top) endif set size = size + 1 endmethod // Add element to back (bot) of list. method addToBack takes integer dataTag returns nothing if isEmpty() then set top = LinkedListNode.create(dataTag, 0) set bot = top else set bot.next = LinkedListNode.create(dataTag, 0) endif set size = size + 1 endmethod endstruct endlibrary
Look carefully. In the List destructor he calls the destructor of xfirst which is a Link. Link recursivly calls destroy on its next Link. Done.
It's just a way to think. One uses a variable one uses recursion or iteration. If you really need that speed, you an always change his script.
You can search for a value and then just destroy that link. Kinda nice if you need it.
List
API, not the Link
API. The user shouldn't have to declare his/her node type variables. That should be handled through the List
.Seems to work versus a tested library
library LinkedListLib
struct LinkedListNode
integer dataTag = 0
thistype next = 0
thistype prev = 0
// Resets the values of all pointers so they don't get confused.
method onDestroy takes nothing returns nothing
if next != 0 then
set next.prev = prev
endif
if prev != 0 then
set prev.next = next
endif
set dataTag = 0
set next = 0
set prev = 0
endmethod
// Creates a node for the linked-list struct with a data tag and a 'next' pointer.
static method create takes integer dataTag, thistype next returns thistype
local thistype node = allocate()
set node.dataTag = dataTag
if next != 0 then
set node.next = next
set node.prev = next.prev
if node.prev != 0 then
set node.prev.next = node
endif
set node.next.prev = node
endif
return node
endmethod
endstruct
struct LinkedList
LinkedListNode top
LinkedListNode bot
integer size = 0
// Returns the size of the linked list.
method getSize takes nothing returns integer
return size
endmethod
// Returns true if there are no elements in the list.
method isEmpty takes nothing returns boolean
return top == 0
endmethod
// Prints the linked-list to the UI.
method print takes nothing returns nothing
local LinkedListNode node = top
loop
exitwhen node == 0
call BJDebugMsg(I2S(node)+".data = "+I2S(node.dataTag))
set node = node.next
endloop
endmethod
// Clean linked list elements
method onDestroy takes nothing returns nothing
local LinkedListNode n = top
local LinkedListNode t
loop
exitwhen n == 0
set t = n
set n = n.next
call t.destroy()
endloop
endmethod
// Returns the extracted element 'index' steps from the top node.
method extract takes integer index returns integer
local integer tag = 0
local integer i = 0
local LinkedListNode node = top
if index < size then
loop
exitwhen i == index
set node = node.next
set i = i + 1
endloop
set tag = node.dataTag
if node == top then
set top = top.next
endif
if node == bot then
set bot = bot.next
endif
call node.destroy()
set size = size - 1
endif
return tag
endmethod
// Returns the extracted 'top' element.
method extractTop takes nothing returns integer
local LinkedListNode t
local integer tag = 0
if not isEmpty() then
set t = top
set tag = t.dataTag
set top = top.next
call t.destroy()
set size = size - 1
endif
return tag
endmethod
// Returns the extracted 'bot' element.
method extractBot takes nothing returns integer
local LinkedListNode b
local integer tag = 0
if not isEmpty() then
set b = bot
set tag = b.dataTag
set bot = bot.prev
call b.destroy()
set size = size - 1
endif
return tag
endmethod
// Add element to front (top) of list.
method addToFront takes integer dataTag returns nothing
if isEmpty() then
set top = LinkedListNode.create(dataTag, 0)
set bot = top
else
set top = LinkedListNode.create(dataTag, top)
endif
set size = size + 1
endmethod
// Add element to back (bot) of list.
method addToBack takes integer dataTag returns nothing
if isEmpty() then
set top = LinkedListNode.create(dataTag, 0)
set bot = top
else
set bot.next = LinkedListNode.create(dataTag, 0)
set bot = bot.next
endif
set size = size + 1
endmethod
endstruct
endlibrary
scope LinkedListTest initializer init
private function init takes nothing returns nothing
local LinkedList L = LinkedList.create()
call L.addToFront(5)
call L.addToFront(8)
call L.addToFront(11)
call L.addToFront(19)
call L.addToFront(21)
call L.extract(3)
call L.addToBack(9)
call L.print()
call BJDebugMsg("End of printing.")
endfunction
endscope
For me it wasn't confusing. I think it's a nice library.Yea I realized that after following the node destructor.
It's a very confusing way of doing things in any scenario though; a
linked-list is an extremely simple data structure but Ammorth's
library makes it confusing and unnatural to use.
You know, "Just typed this up now, seems to work" versus a thread withWell what do you mean, tested library? Are you saying that
wc3c.net has more credit than me simply because they approve resources?
Rising_Dusk's "intuitive damage detection" still has bugs in it
that have been there for the past couple of years. If it were properly tested
this would have been discovered, but it wasn't, so how properly do you think
the libraries at wc3c.net are actually tested.
Never said it was a matter of memory but a matter of style.The Warcraft III engine can handle one more member on a vJass struct I think, so it's not a matter of memory. If it were, I can see why the integer would pose a problem. Since memory isn't an issue, why waste processing resources. Since obtaining O(1) operating time could be achieved with little to no work, I'm surprised that the prestigious community of wc3c.net didn't require that he do this to approve the submission.
Sometimes you need that control. If you want i can name you some, but i bet youThe user shouldn't be creating/destroying his/her own linked-list nodes. A linked-list should provide the user with an API to use the data-structure that allows him/her to associate data together much like an array would. In an array you simply have to declare an array, you don't have to declare elements of the array and then insert them at the correct location.
But this should be done through theList
API, not theLink
API. The user shouldn't have to declare his/her node type variables. That should be handled through theList
.
For me it wasn't confusing. I think it's a nice library.
You know, "Just typed this up now, seems to work" versus a thread with
4 pages of discussion.
size
method that has to iterate through the linked-list when it is not necessary and it is in fact slower. By a lot.Never said it was a matter of memory but a matter of style.
Languages like Haskell also don't store an extra paramter but use
(tail-)recursion to loop through the list and get its length [1].
But for the two of us this discussion is senseless anyway. I won't change your
opinion you probably won't change mine.
On the other hand everyone can make their own thoughts base on this discussion.
That would make me happy Kind of a reward for my long thoughtfull posts ;p
LinkedListNode
(that's from my script) but I truly believe that those reasons could be adopted to with a better linked-list API. In my opinion if the user is going to be removing something from a linked-list then it is only sensible that it be extracted (unless the list is being destroyed).You see, analyze your code and only optimize the part which is worth optimizing.We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
size
method is minimal, thus there is no harm in "prematurely" optimizing it. In fact, the optimization is more simple than the alternative.In fact, the optimization is more simple than the alternative.
--untested. just wrote it down.
data List = Cons a (List a)
| Nil
length :: List a -> Int
length x = len_helper 0 xs
where len_helper i (Cons _ xs) = len_helper (i + 1) xs
len_helper i Nil = i
local LinkedList L = LinkedList.create()
local LinkedListNode N
// Do stuff to L.
call L.addToFront(8)
call L.addToBack(10)
call L.addToFront(13)
call L.addToBack(9)
call L.addToBack(11)
call L.addToBack(3)
call L.extract(4)
call L.extract(2)
set N = L.top
loop
exitwhen N == 0
// Iteration.
set N = N.next
endloop
So I have to use the extract method. At first it is an O(n) operation (Ammorth's is O(1)), but that is not the worst problem; the method expects the number of the thing in the list. So I have to keep track of what element it is while iterating and calculate the corrections of this number when I insert and remove values while I am iterating over the list (wait, inserting in the middle of the list is not possible, my bad, I thought it was like Ammorth's list where this was no problem) or I have to use the by now nonexisting search method on the list, I have to write by myself before. I have to dive into the implementation of your list like a bucket full of crap. (This method would be O(n) again; by the way all this solve Ammorth's by a simple 20 line O(1) function)
you think that your library deserves to be compared against Ammorth's
size
method was not O(1). Then I said that it was more of a linked-list-node library than a linked-list library, and I said that it was written in a confusing manner.First you're aggressive
Well,Berb said:I'd like to see you quote me on that.
LeP said:Seems to work versus a tested library
and a general attitude surrounding any mention of Ammoth's library. Maybe you're right and 'aggressive' was too strong a term. In that case, I guess I'm sorry that I can't think of a better one. Regardless, the thread was becoming silly.Berb said:Well what do you mean, tested library? Are you saying that wc3c.net has more credit than me simply because they approve resources? Rising_Dusk's "intuitive damage detection" still has bugs in it that have been there for the past couple of years. If it were properly tested this would have been discovered, but it wasn't, so how properly do you think the libraries at wc3c.net are actually tested.
Really, no. I don't care how important or unimportant you might think I am. I was just stating that the thread was becoming silly because of the hostility. And I never told you what I thought you deserved to do. I told you what I thought you thought your library deserved. This in no way reflects what I think about your library. In fact I haven't even reviewed either libraries.Berb said:That's just some bullshit you pulled out of your ass to make yourself seem important enough to tell me what I deserve to do and not do.
Nope, I haven't actively visited wc3c in a very long time, and I haven't written Jass in a very long time. I was just lurking. Maybe you shouldn't make "assumptions" like this.Berb said:I bet this is just a bunch of wc3c.net members who take extreme personal offense to something I have written. That would explain why you're here, HINDYhat, and why somebody just randomly made an account today so they could reply to what I've said.
I told you what I thought you thought your library deserved
and a general attitude surrounding any mention of Ammoth's library. Maybe you're right and 'aggressive' was too strong a term. In that case, I guess I'm sorry that I can't think of a better one. Regardless, the thread was becoming silly.
What did you expect? You criticize Ammorths library and post a new, in your eyes better one. Did you realy expect to NOT get some criticism? Nobody is perfect, neither Ammorth nor you.God man this starts off as a simple help thread, I type up some library for somebody and then all hell breaks lose. Jesus if you don't have anything pleasant to say then don't say it, LeP, HINDYhat, and HxOrg or whatever, you've contributed nothing to this other than arguments.