-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlinked_list.f90
More file actions
395 lines (327 loc) · 10.6 KB
/
linked_list.f90
File metadata and controls
395 lines (327 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
!*********************************************
!Layne Price, University of Auckland, 5/9/2012
!*********************************************
!This is a module that has everything necessary to create a linked list. Each node in the list is represented by some data --- in this case an allocatable array --- with one pointer pointing down the list.
!The list is started by a node-pointer, called the "head," and ended by a node-pointer, called the "tail." "Head" points at the first element in the list, itself a node-pointer that points to a real node. The real nodes have a pointer going down the list. These point to the next node-pointer in the chain. This is shown below:
! node1 ===========V node2 ============V node-end
! ^ ^ ^
! HEAD => NODE1-POINT / NODE2-POINT / ... / NODE-END-POINT <= TAIL
!It is necessary that the naiive elements of the chain be node-pointers --- as opposed to nodes themselves --- so that we can ALLOCATE(node-pointer). Doing this creates an unnamed area in memory that the node-pointer implicitly points to. For example, let p=>unnamed and q=2 be an integer. Setting p=q changes the unnamed spot in memory to unnamed=2. We can refer to this spot in memory by referencing the node-pointer. In this way, we are able to dynamically create spots in the memory which we can then add to the list.
module linked_list
use types, only : dp
implicit none
!This is a node in the link.
type :: llnode
!This point to the next node. Initializes to null.
type(llnode), pointer :: next=>null()
!This is the data.
real(dp), dimension(:), allocatable :: a
end type llnode
!A linked list is specified by what the head and tail point to --- and what
!those subsequently point to in a chain. It initializes to null.
type :: linkedlist
type(llnode), pointer :: head=>null(), tail=>null()
end type linkedlist
!A double linked list extends the notion of a linked list by inheriting its
!attributes and adding a pointer going back up the chain.
!NOTE: Requires Fortran 2003.
! type, extends(llnode) :: ll_dnode
! type(llnode), pointer :: prev
! end type ll_dnode
!
!Default to public.
contains
!Subroutine which returns the nth node in list, where head is counted as the zeroth
!node. Can optionally return the previous and next node, too. If n=1, then
!previous node is head and if n=n_end, then next node is null() for both next and
!prev. If list is empty, then previous is head, next is tail, and sel has null() !pointers. If n is out-of-bounds, then returns tail for all pointers.
!NOTE: this is much slower than the random access given by a simple array ---
!O(n) vs O(1)
subroutine ll_nav(n,list,sel,plus,minus)
implicit none
integer, intent(in) :: n
type(linkedlist), intent(in) :: list
type(llnode), pointer, intent(out) :: sel
type(llnode), pointer, optional, intent(out) :: plus, minus
type(llnode), pointer :: move
integer :: i
!Make space in memory for a dummary type(llnode).
allocate(sel)
if(present(plus)) allocate(plus)
if(present(minus)) allocate(minus)
!Check to see if n is too small.
if (n==0) then
if (present(plus)) plus=>list%head
return
else if (n<0) then
return
end if
!Check if list is empty.
if (.not. associated(list%head)) then !List is empty.
sel%next=>null()
if (present(minus)) minus=>list%head
if (present(plus)) plus=>list%tail
else
!See if n=1.
if (n==1) then
sel=>list%head
if(present(plus)) plus=>list%head%next
return
end if
!Navigate down list.
move => list%head
do i=1, n
if (i==1) then
move => list%head
else
!Point to the next node in list.
move => move%next
end if
!Check if we're at the end of list.
if (.not. associated(move)) then !we're at the end.
!Out of bounds.
if(i==n) then
if (present(minus)) minus=>list%tail
end if
return
end if
end do
!If haven't reached end, then load nodes.
if (present(plus) ) then
if (associated(move%next)) then
!Setting obj=pointer sets obj=pointer's target.
plus=>move%next
end if
end if
sel=move
end if
end subroutine ll_nav
!Add a node to the end of the list. Takes as input a pointer which points to the
!node which we want to add.
subroutine ll_append(new, list)
implicit none
type(linkedlist), intent(inout) :: list
type(llnode), pointer, intent(inout) :: new
!Check if the list is empty.
if (associated(list%head)) then !Not empty.
!Whichever node is tail, connect to new.
!This should point to an unnamed llnode.
!i.e. new=>unnamed node defined via allocate.
list%tail%next => new
new%next => null()
list%tail => new
else
!Attach new node to end of head, making it the first node.
list%head => new
!Attach the tail, indicated new is the end.
list%tail => new
!No successor to node that new points to.
list%tail%next => null()
end if
end subroutine ll_append
!Add a node to the end of the nth node in a list, making the new node the (n+1)st node
subroutine ll_insert(n,new,list)
implicit none
type(linkedlist), intent(inout) :: list
type(llnode), pointer, intent(inout) :: new
type(llnode), pointer :: sel, plus
integer, intent(in) :: n
if(n==0) then
call ll_nav(n,list,sel,plus)
list%head=>new
new%next=>plus
return
end if
!Navigate to nth node in list.
call ll_nav(n,list,sel,plus)
!Check if n is more than numb nodes in list.
if (.not. associated(sel%next)) then !n or less nodes in list.
!Stick new on the end of list.
call ll_append(new,list)
return
else
new%next => plus
sel%next => new
end if
end subroutine
!Print a list.
subroutine ll_print(list)
implicit none
type(linkedlist), intent(in) :: list
type(llnode), pointer :: move
integer :: i
!Check if list is empty.
if (.not. associated(list%head)) then
print*, "The list is empty."
else
move=>list%head
do
print*,(move%a(i),i=1,size(move%a))
if (.not. associated(move%next)) then
exit
else
move=>move%next
end if
end do
end if
end subroutine ll_print
!Write a list to file, "fname". Optional input are formt, and unit.
subroutine ll_write(list,fname,frmt,unumb)
implicit none
type(linkedlist), intent(in) :: list
character(len=*), intent(in) :: fname
character(len=*), optional, intent(in) :: frmt
integer, optional, intent(in) :: unumb
type(llnode), pointer :: move
integer :: i, numb
!Open the file which we will write to.
if (present(unumb)) then
numb = unumb
else
numb = 31415927
end if
if (present(frmt)) then
open(unit=numb,file=fname,form=frmt)
else
open(unit=numb,file=fname,form="unformatted")
end if
!Check if list is empty.
if (.not. associated(list%head)) then
print*, "The list is empty."
else
move=>list%head
do
write(unit=numb),(move%a(i),i=1,size(move%a))
move=>move%next
if (.not. associated(move)) exit
end do
end if
!Close the file.
close(unit=numb)
end subroutine ll_write
!Make a new node from an array.
subroutine ll_make(node,array)
implicit none
type(llnode), pointer, intent(inout) :: node
real(dp), dimension(:), intent(in) :: array
!Creates an unnamed node of the specified size. Since this is unnamed, it
!can only be referred to by a pointer and it does this implicitly whenever
!the pointer is called. This is the main point in creating
!memory space dynamically for pointers!
allocate(node)
!Sets the array component equal to array.
allocate(node%a(size(array)))
node%a=array
!Sets pointer components to point to null.
node%next=>null()
end subroutine ll_make
!Change a list to an array that it is conformable with. Assumes that all the
!vectors in the list are of the same dimension.
subroutine ll_to_array(list, table)
implicit none
type(linkedlist), intent(inout) :: list
real(dp), dimension(:,:), allocatable, intent(out) :: table
type(llnode), pointer :: move
integer :: counter, i
!Check if empty.
if (.not. associated(list%head)) then
return
else
!Count number of elements in array st can allocate array.
!O(n)
counter=1
move=>list%head
do
if (.not. associated(move%next)) then
exit
else
counter = counter + 1
move=>move%next
end if
end do
!Allocate table
allocate(table(counter,size(list%head%a)))
!Load the table with the list.
move=>list%head
do i=1, counter
table(i,:)=move%a
if (associated(move%next)) move=>move%next
end do
end if
end subroutine ll_to_array
!Delete the first element in a linked list. Returns a pointer to the first node.
subroutine ll_del_first(list, first)
implicit none
type(linkedlist), intent(inout) :: list
type(llnode), pointer :: test
type(llnode), pointer, intent(out) :: first
!Check to see if list is empty.
if (associated(list%head)) then !list not empty.
!Check if more than 1 node.
if (associated(list%head%next)) then !more than one node.
first => list%head
list%head => list%head%next
first%next => null()
else
first => list%head
list%head => null()
list%tail => null()
end if
else
!List empty.
first => null()
end if
end subroutine ll_del_first
!Delete all elements in a list. Leaves the list initialized.
subroutine ll_del_all(list)
implicit none
type(linkedlist), intent(inout) :: list
type(llnode), pointer :: move
do
!Check if list empty.
if (.not. associated(list%head)) then
exit
else
call ll_del_first(list,move)
deallocate(move)
nullify(move)
end if
end do
end subroutine
!Change a list to an array and delete the list in same motion.
subroutine ll_to_array_and_del(list, table)
implicit none
type(linkedlist), intent(inout) :: list
real(dp), dimension(:,:), allocatable, intent(out) :: table
type(llnode), pointer :: move, delete
integer :: counter, i
!Check if empty.
if (.not. associated(list%head)) then
return
else
!Count number of elements in array st can allocate array.
!O(n)
counter=1
move=>list%head
do
if (.not. associated(move%next)) then
exit
else
counter = counter + 1
move=>move%next
end if
end do
!Allocate table
allocate(table(counter,size(list%head%a)))
!Load the table with the list.
move=>list%head
do i=1, counter
table(i,:)=move%a
if (associated(move%next)) move=>move%next
call ll_del_first(list,delete)
deallocate(delete)
nullify(delete)
end do
end if
end subroutine ll_to_array_and_del
end module linked_list