linked_lists 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop.yml +8 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +96 -0
- data/LICENSE.txt +21 -0
- data/README.md +70 -0
- data/Rakefile +24 -0
- data/benchmark/append.rb +26 -0
- data/benchmark/benchmark_helper.rb +5 -0
- data/benchmark/pop.rb +26 -0
- data/benchmark/shift.rb +25 -0
- data/benchmark/unshift.rb +26 -0
- data/ext/linked_lists/extconf.rb +5 -0
- data/ext/linked_lists/linked_lists.c +9 -0
- data/ext/linked_lists/linked_lists.h +6 -0
- data/lib/linked_lists/linked_list/node.rb +63 -0
- data/lib/linked_lists/linked_list.rb +985 -0
- data/lib/linked_lists/version.rb +5 -0
- data/lib/linked_lists.rb +11 -0
- data/linked_lists.gemspec +43 -0
- data/sig/linked_lists.rbs +4 -0
- metadata +72 -0
@@ -0,0 +1,985 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'linked_list/node'
|
4
|
+
|
5
|
+
# An `Enumerable` data structure
|
6
|
+
# which implements a singly linked list.
|
7
|
+
# It's a proper `Enumerable` object like `Array`, `Hash` or `Set`.
|
8
|
+
#
|
9
|
+
# Its API has been heavily inspired by `Set` and `Array`.
|
10
|
+
#
|
11
|
+
# list = LinkedList[1, 2, 3, :foo]
|
12
|
+
#
|
13
|
+
# Prepending and shifting items is very fast and happens in *O(1)*.
|
14
|
+
#
|
15
|
+
# list = LinkedList[:foo]
|
16
|
+
# list.unshift :bar
|
17
|
+
# list.prepend :baz
|
18
|
+
# list >> 'foobar'
|
19
|
+
# list #=> LinkedList["foobar", :baz, :bar, :foo]
|
20
|
+
#
|
21
|
+
# Appending is possible but requires the entire list to be traversed, which gives
|
22
|
+
# a time complexity of *O(n)*.
|
23
|
+
#
|
24
|
+
# list = LinkedList[:foo]
|
25
|
+
# list.push :bar
|
26
|
+
# list.append :baz
|
27
|
+
# list << 'foobar'
|
28
|
+
# list #=> LinkedList[:foo, :bar, :baz, 'foobar']
|
29
|
+
#
|
30
|
+
# Optimal traversing is only possible in one direction, from head (first element)
|
31
|
+
# to tail (last element).
|
32
|
+
#
|
33
|
+
# To get the length of a linked list, the entire list has to be traversed
|
34
|
+
# which happens in *O(n)*.
|
35
|
+
#
|
36
|
+
# LinkedList[].size #=> 0
|
37
|
+
# LinkedList[:foo].length #=> 1
|
38
|
+
# LinkedList[:foo, 1, 2, 3].count #=> 4
|
39
|
+
#
|
40
|
+
# Getting items by index is possible, but the list needs to be
|
41
|
+
# traversed from head to the index, which gives a time complexity of *O(n)*.
|
42
|
+
#
|
43
|
+
# list = LinkedList["foobar", :baz, :bar, :foo]
|
44
|
+
# list[0] #=> "foobar"
|
45
|
+
# list.slice(0) #=> "foobar"
|
46
|
+
# list[2] #=> :bar
|
47
|
+
# list[-1] #=> :foo
|
48
|
+
# list[1, 2] #=> [:baz, :bar]
|
49
|
+
# list.slice(1, 2) #=> LinkedList[:baz, :bar]
|
50
|
+
# list[1..3] #=> [:baz, :bar, :foo]
|
51
|
+
#
|
52
|
+
class LinkedList
|
53
|
+
include ::Enumerable
|
54
|
+
|
55
|
+
class << self
|
56
|
+
# Create a new `LinkedList` with these elements
|
57
|
+
# inserted.
|
58
|
+
#
|
59
|
+
# @param elements [Array]
|
60
|
+
def [](*elements)
|
61
|
+
new(elements)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# The first element of the linked list.
|
66
|
+
# Time complexity: *O(1)*
|
67
|
+
#
|
68
|
+
# @return [Node, nil]
|
69
|
+
attr_accessor :head
|
70
|
+
|
71
|
+
# @param enum [Object] Enumerable object that will be converted.
|
72
|
+
def initialize(enum = nil)
|
73
|
+
@head = nil
|
74
|
+
return if enum.nil?
|
75
|
+
|
76
|
+
concat(enum)
|
77
|
+
end
|
78
|
+
|
79
|
+
# The last element of the linked list.
|
80
|
+
#
|
81
|
+
# Keep in mind that in order to retrieve it the entire
|
82
|
+
# list needs to be traversed.
|
83
|
+
#
|
84
|
+
# Time complexity is *O(n)*.
|
85
|
+
#
|
86
|
+
# @return [Node, nil]
|
87
|
+
def tail
|
88
|
+
each_node { |node| return node if node.next.nil? }
|
89
|
+
end
|
90
|
+
|
91
|
+
# Freezes the list and its every node.
|
92
|
+
#
|
93
|
+
# Time complexity is *O(n)*.
|
94
|
+
#
|
95
|
+
# @return [self]
|
96
|
+
def freeze
|
97
|
+
super
|
98
|
+
each_node(&:freeze)
|
99
|
+
|
100
|
+
self
|
101
|
+
end
|
102
|
+
|
103
|
+
# Removes all elements from `self`.
|
104
|
+
# Sets the `head` to `nil`.
|
105
|
+
#
|
106
|
+
# Time complexity: *O(1)*.
|
107
|
+
#
|
108
|
+
# @return [self]
|
109
|
+
def clear
|
110
|
+
@head = nil
|
111
|
+
self
|
112
|
+
end
|
113
|
+
|
114
|
+
# Checks if `head` is `nil`.
|
115
|
+
#
|
116
|
+
# Time complexity: *O(1)*.
|
117
|
+
#
|
118
|
+
# @return [Boolean]
|
119
|
+
def empty?
|
120
|
+
@head.nil?
|
121
|
+
end
|
122
|
+
|
123
|
+
# The number of elements in the list.
|
124
|
+
# Keep in mind that the entire list needs to be traversed in order
|
125
|
+
# to find out it's length.
|
126
|
+
#
|
127
|
+
# Time complexity is *O(n)*.
|
128
|
+
#
|
129
|
+
# @return [Integer]
|
130
|
+
def size
|
131
|
+
return 0 if empty?
|
132
|
+
|
133
|
+
length = 0
|
134
|
+
each_with_index { |_, i| length = i }
|
135
|
+
|
136
|
+
length + 1
|
137
|
+
end
|
138
|
+
alias length size
|
139
|
+
|
140
|
+
# Returns the last element, or the last `length` elements, of the linked list.
|
141
|
+
# If the list is empty, the first form returns `nil`, and the second form returns an empty list.
|
142
|
+
#
|
143
|
+
# Keep in mind that it's only possible to traverse this list in one direction
|
144
|
+
# from head to tail. So the entire list has to be traversed in order
|
145
|
+
# to retrieve the last elements.
|
146
|
+
#
|
147
|
+
# Time complexity is *O(2n)*.
|
148
|
+
#
|
149
|
+
# @param length [Integer]
|
150
|
+
# @return [Object, Array]
|
151
|
+
def last(*args)
|
152
|
+
to_a.last(*args)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Returns the index of the first object in the linked list such that the object is `==` to `obj`.
|
156
|
+
# Time complexity: *O(n)*
|
157
|
+
#
|
158
|
+
# If a block is given instead of an argument, returns the index
|
159
|
+
# of the first object for which the block returns `true`. Returns `nil` if no match is found.
|
160
|
+
#
|
161
|
+
# Time complexity: *O(n)*
|
162
|
+
#
|
163
|
+
# @param obj [Object] Value that will be compared with the nodes of this list.
|
164
|
+
# @return [Object, nil]
|
165
|
+
def index(obj = nil)
|
166
|
+
if block_given?
|
167
|
+
each_with_index do |element, i|
|
168
|
+
return i if yield(element)
|
169
|
+
end
|
170
|
+
|
171
|
+
return
|
172
|
+
end
|
173
|
+
|
174
|
+
each_with_index do |element, i|
|
175
|
+
return i if obj == element
|
176
|
+
end
|
177
|
+
|
178
|
+
nil
|
179
|
+
end
|
180
|
+
|
181
|
+
# Returns the node at the provided index.
|
182
|
+
# This list in not indexed so the entire list will have to
|
183
|
+
# be traversed in the worst case.
|
184
|
+
# Time complexity: *O(n)*
|
185
|
+
#
|
186
|
+
# @param index [Integer]
|
187
|
+
# @return [Node, nil]
|
188
|
+
def node_at(index)
|
189
|
+
index = index.to_int
|
190
|
+
return each_node.to_a.at(index) if index.negative?
|
191
|
+
|
192
|
+
each_node.with_index do |node, i|
|
193
|
+
return node if i == index
|
194
|
+
end
|
195
|
+
|
196
|
+
nil
|
197
|
+
end
|
198
|
+
|
199
|
+
# Returns the item at the provided index.
|
200
|
+
# This list in not indexed so the entire list will have to
|
201
|
+
# be traversed in the worst case.
|
202
|
+
# Time complexity: *O(n)*
|
203
|
+
#
|
204
|
+
# @param index [Integer]
|
205
|
+
# @return [Object, nil]
|
206
|
+
def at(index)
|
207
|
+
node_at(index)&.value
|
208
|
+
end
|
209
|
+
|
210
|
+
# Get the elements at the specified index. Head of the list is `0`.
|
211
|
+
#
|
212
|
+
# This list in not indexed so the entire list will have to
|
213
|
+
# be traversed in the worst case.
|
214
|
+
# Time complexity: *O(n)*
|
215
|
+
#
|
216
|
+
# @param index [Integer]
|
217
|
+
# @param length [Integer, nil]
|
218
|
+
# @return [Object, Array]
|
219
|
+
def [](index, length = nil)
|
220
|
+
slice_with_enum(::Array, index, length)
|
221
|
+
end
|
222
|
+
|
223
|
+
# Get the elements at the specified index. Head of the list is `0`.
|
224
|
+
#
|
225
|
+
# This list in not indexed so the entire list will have to
|
226
|
+
# be traversed in the worst case.
|
227
|
+
# Time complexity: *O(n)*
|
228
|
+
#
|
229
|
+
# @param index [Integer]
|
230
|
+
# @param length [Integer, nil]
|
231
|
+
# @return [Object, self]
|
232
|
+
def slice(index, length = nil)
|
233
|
+
slice_with_enum(self.class, index, length)
|
234
|
+
end
|
235
|
+
|
236
|
+
# Calls the given block once for each element in linked list, passing
|
237
|
+
# the element as a parameter. Returns an enumerator if no block is
|
238
|
+
# given.
|
239
|
+
#
|
240
|
+
# Time complexity: *O(n)*
|
241
|
+
#
|
242
|
+
# @yieldparam [Object] An element of the list.
|
243
|
+
# @return [self, Enumerator]
|
244
|
+
def each
|
245
|
+
return enum_for(__method__) unless block_given?
|
246
|
+
|
247
|
+
each_node { |node| yield node.value }
|
248
|
+
end
|
249
|
+
|
250
|
+
alias each_value each
|
251
|
+
|
252
|
+
# Calls the given block once for each node in the linked list, passing
|
253
|
+
# the node as a parameter. Returns an enumerator if no block is
|
254
|
+
# given.
|
255
|
+
#
|
256
|
+
# Time complexity: *O(n)*
|
257
|
+
#
|
258
|
+
# @yieldparam [Node] A node of the list.
|
259
|
+
# @return [self, Enumerator]
|
260
|
+
def each_node
|
261
|
+
return enum_for(__method__) unless block_given?
|
262
|
+
return unless @head
|
263
|
+
|
264
|
+
element = @head
|
265
|
+
loop do
|
266
|
+
yield element
|
267
|
+
break if (element = element.next).nil?
|
268
|
+
end
|
269
|
+
|
270
|
+
self
|
271
|
+
end
|
272
|
+
|
273
|
+
# Returns a new `LinkedList` with the elements of `self` in reverse order.
|
274
|
+
# Time complexity: *O(2n)*
|
275
|
+
#
|
276
|
+
# @return [self]
|
277
|
+
def reverse
|
278
|
+
result = self.class.new
|
279
|
+
reverse_each do |obj|
|
280
|
+
result << obj
|
281
|
+
end
|
282
|
+
|
283
|
+
result
|
284
|
+
end
|
285
|
+
|
286
|
+
# Returns a new `LinkedList` which consists of the values returned by the block.
|
287
|
+
# Returns an enumerator if no block is given.
|
288
|
+
#
|
289
|
+
# Time complexity: *O(n)*
|
290
|
+
#
|
291
|
+
# @yieldparam [Object] An element of the list.
|
292
|
+
# @return [self, Enumerator]
|
293
|
+
def map
|
294
|
+
return enum_for(__method__) unless block_given?
|
295
|
+
|
296
|
+
result = self.class.new
|
297
|
+
each_node do |node|
|
298
|
+
result << yield(node.value)
|
299
|
+
end
|
300
|
+
|
301
|
+
result
|
302
|
+
end
|
303
|
+
alias collect map
|
304
|
+
|
305
|
+
# Returns a list containing truthy elements returned by the block.
|
306
|
+
#
|
307
|
+
# With a block given, calls the block with successive elements;
|
308
|
+
# returns a list containing each truthy value returned by the block.
|
309
|
+
#
|
310
|
+
# Time complexity: *O(n)*
|
311
|
+
#
|
312
|
+
# @yieldparam [Object] An element of the list.
|
313
|
+
# @return [self, Enumerator]
|
314
|
+
def filter_map
|
315
|
+
return enum_for(__method__) unless block_given?
|
316
|
+
|
317
|
+
result = self.class.new
|
318
|
+
each_node do |node|
|
319
|
+
next unless (block_result = yield(node.value))
|
320
|
+
|
321
|
+
result << block_result
|
322
|
+
end
|
323
|
+
|
324
|
+
result
|
325
|
+
end
|
326
|
+
|
327
|
+
# Replaces the elements with ones returned by the block.
|
328
|
+
# Returns an enumerator if no block is given.
|
329
|
+
#
|
330
|
+
# Time complexity: *O(n)*
|
331
|
+
#
|
332
|
+
# @yieldparam [Object] An element of the list.
|
333
|
+
# @return [self, Enumerator]
|
334
|
+
def map!
|
335
|
+
return enum_for(__method__) unless block_given?
|
336
|
+
|
337
|
+
each_node do |node|
|
338
|
+
node.value = yield(node.value)
|
339
|
+
end
|
340
|
+
|
341
|
+
self
|
342
|
+
end
|
343
|
+
alias collect! map!
|
344
|
+
|
345
|
+
# Returns a new `LinkedList` object whose entries are those for which the block returns a falsey value.
|
346
|
+
# Or a new `Enumerator` if no block given.
|
347
|
+
#
|
348
|
+
# Time complexity: *O(n)*
|
349
|
+
#
|
350
|
+
# @yieldparam [Object] An element of the list.
|
351
|
+
# @return [self, Enumerator]
|
352
|
+
def reject
|
353
|
+
return enum_for(__method__) unless block_given?
|
354
|
+
|
355
|
+
select { |o| !yield(o) }
|
356
|
+
end
|
357
|
+
|
358
|
+
# Returns a new `LinkedList` object whose entries are those for which the block returns a truthy value.
|
359
|
+
# Or a new Enumerator if no block given.
|
360
|
+
#
|
361
|
+
# Time complexity: *O(n)*
|
362
|
+
#
|
363
|
+
# @yieldparam [Object] An element of the list.
|
364
|
+
# @return [self, Enumerator]
|
365
|
+
def select
|
366
|
+
return enum_for(__method__) unless block_given?
|
367
|
+
|
368
|
+
result = self.class.new
|
369
|
+
each do |value|
|
370
|
+
result << value if yield(value)
|
371
|
+
end
|
372
|
+
|
373
|
+
result
|
374
|
+
end
|
375
|
+
alias filter select
|
376
|
+
|
377
|
+
# Returns self whose entries are those for which the block returns a truthy value.
|
378
|
+
# Or a new `Enumerator` if no block given.
|
379
|
+
#
|
380
|
+
# Time complexity: *O(n)*
|
381
|
+
#
|
382
|
+
# @yieldparam [Object] An element of the list.
|
383
|
+
# @return [self, Enumerator, nil]
|
384
|
+
def delete_if(&block)
|
385
|
+
reject!(&block) || self
|
386
|
+
end
|
387
|
+
|
388
|
+
# Deletes the first item from `self` that is equal to `obj`.
|
389
|
+
# Returns the deleted item, or `nil` if no matching item is found.
|
390
|
+
#
|
391
|
+
# Time complexity: *O(n)*
|
392
|
+
#
|
393
|
+
# @param obj [Object] object to be deleted
|
394
|
+
# @return [Object]
|
395
|
+
def delete(obj)
|
396
|
+
removed = nil
|
397
|
+
prev_node = nil
|
398
|
+
each_node do |n|
|
399
|
+
next (prev_node = n) unless n.value == obj
|
400
|
+
|
401
|
+
delete_node_with_prev(prev_node, n.next)
|
402
|
+
return n.value
|
403
|
+
end
|
404
|
+
|
405
|
+
removed
|
406
|
+
end
|
407
|
+
|
408
|
+
# Deletes all items from `self` that are equal to `obj`.
|
409
|
+
# Returns the last deleted item, or `nil` if no matching item is found.
|
410
|
+
#
|
411
|
+
# Time complexity: *O(n)*
|
412
|
+
#
|
413
|
+
# @param obj [Object] object to be deleted
|
414
|
+
# @return [Object]
|
415
|
+
def delete_all(obj)
|
416
|
+
removed = nil
|
417
|
+
delete_if do |element|
|
418
|
+
removed = element if element == obj
|
419
|
+
end
|
420
|
+
|
421
|
+
removed
|
422
|
+
end
|
423
|
+
|
424
|
+
# Deletes a node from `self` that is the same object as the given `node`.
|
425
|
+
# Returns the deleted node, or `nil` if no matching item is found.
|
426
|
+
#
|
427
|
+
# Time complexity: *O(n)*
|
428
|
+
#
|
429
|
+
# @param node [Node] node to be deleted
|
430
|
+
# @return [Node, nil]
|
431
|
+
def delete_node(node)
|
432
|
+
raise ::ArgumentError, 'value should be a node' unless node.is_a?(Node)
|
433
|
+
|
434
|
+
removed = nil
|
435
|
+
prev_node = nil
|
436
|
+
each_node do |n|
|
437
|
+
next (prev_node = n) unless n == node
|
438
|
+
|
439
|
+
delete_node_with_prev(prev_node, n.next)
|
440
|
+
return n
|
441
|
+
end
|
442
|
+
|
443
|
+
removed
|
444
|
+
end
|
445
|
+
|
446
|
+
# Deletes the element at the specified index
|
447
|
+
# returning that element, or `nil` if the `index` is out of range.
|
448
|
+
#
|
449
|
+
# This list in not indexed so the entire list will have to
|
450
|
+
# be traversed in the worst case.
|
451
|
+
# Time complexity: *O(n)*
|
452
|
+
#
|
453
|
+
# @param index [Integer]
|
454
|
+
# @return [Object, nil]
|
455
|
+
def delete_at(index)
|
456
|
+
prev_node = nil
|
457
|
+
each_node.with_index do |node, i|
|
458
|
+
return node.value if i == index && delete_node_with_prev(prev_node, node.next)
|
459
|
+
|
460
|
+
prev_node = node
|
461
|
+
end
|
462
|
+
|
463
|
+
nil
|
464
|
+
end
|
465
|
+
|
466
|
+
# Removes and returns leading elements.
|
467
|
+
# When no argument is given, removes and returns the first element.
|
468
|
+
# When positive Integer argument `length` is given, removes the first `length` elements
|
469
|
+
# and returns those elements in a new `Array`.
|
470
|
+
#
|
471
|
+
# Time complexity is *O(1)* when no `length` is given.
|
472
|
+
# Otherwise it's *O(min(m, n))*, where *m* is the given `length` of elements to be shifted
|
473
|
+
# and *n* is the length of `self`.
|
474
|
+
#
|
475
|
+
# @param length [Integer, nil]
|
476
|
+
# @return [Object, Array]
|
477
|
+
def shift(length = nil)
|
478
|
+
raise ::TypeError, "no implicit conversion of #{length.class} into Integer" unless length.nil? || length.respond_to?(:to_int)
|
479
|
+
raise ::ArgumentError, 'negative linked list size' if length&.negative?
|
480
|
+
return if empty?
|
481
|
+
|
482
|
+
unless length
|
483
|
+
prev_head = @head
|
484
|
+
@head = @head.next
|
485
|
+
return prev_head.value
|
486
|
+
end
|
487
|
+
|
488
|
+
length = length.to_int
|
489
|
+
removed = []
|
490
|
+
each_node.with_index do |node, i|
|
491
|
+
break if i == length
|
492
|
+
|
493
|
+
removed << @head.value
|
494
|
+
@head = node.next
|
495
|
+
end
|
496
|
+
|
497
|
+
removed
|
498
|
+
end
|
499
|
+
|
500
|
+
# Removes and returns trailing elements.
|
501
|
+
#
|
502
|
+
# When no argument is given and self is not empty, removes and returns the last element
|
503
|
+
#
|
504
|
+
# Keep in mind that the entire list has to be traversed
|
505
|
+
# in the worst case to pop an item.
|
506
|
+
#
|
507
|
+
# Time complexity: *O(n)*.
|
508
|
+
#
|
509
|
+
# @param length [Integer, nil]
|
510
|
+
# @return [Object, Array]
|
511
|
+
def pop(length = nil)
|
512
|
+
raise ::TypeError, "no implicit conversion of #{length.class} into Integer" unless length.nil? || length.respond_to?(:to_int)
|
513
|
+
return [] if length&.zero?
|
514
|
+
raise ::ArgumentError, 'negative linked list size' if length&.negative?
|
515
|
+
|
516
|
+
index = length ? -length : -1
|
517
|
+
ary = each_node.to_a
|
518
|
+
node = ary[index] || @head
|
519
|
+
prev_node = ary[index - 1]
|
520
|
+
|
521
|
+
if prev_node.nil?
|
522
|
+
@head = nil
|
523
|
+
else
|
524
|
+
prev_node.next = nil
|
525
|
+
end
|
526
|
+
|
527
|
+
return node&.value unless length
|
528
|
+
|
529
|
+
node&.to_list.to_a
|
530
|
+
end
|
531
|
+
|
532
|
+
# Returns self whose entries are those for which the block returns a falsey value.
|
533
|
+
# A new `Enumerator` if no block given.
|
534
|
+
# Or `nil` if no entries were removed.
|
535
|
+
#
|
536
|
+
# Time complexity: *O(n)*
|
537
|
+
#
|
538
|
+
# @yieldparam [Object] An element of the list.
|
539
|
+
# @return [self, Enumerator, nil]
|
540
|
+
def reject!
|
541
|
+
return enum_for(__method__) unless block_given?
|
542
|
+
|
543
|
+
select! { |o| !yield(o) }
|
544
|
+
end
|
545
|
+
|
546
|
+
# Returns self whose entries are those for which the block returns a truthy value.
|
547
|
+
# Or a new `Enumerator` if no block given.
|
548
|
+
#
|
549
|
+
# Time complexity: *O(n)*
|
550
|
+
#
|
551
|
+
# @yieldparam [Object] An element of the list.
|
552
|
+
# @return [self, Enumerator, nil]
|
553
|
+
def keep_if(&block)
|
554
|
+
select!(&block) || self
|
555
|
+
end
|
556
|
+
|
557
|
+
# Returns self whose entries are those for which the block returns a truthy value.
|
558
|
+
# A new `Enumerator` if no block given.
|
559
|
+
# Or `nil` if no entries were removed.
|
560
|
+
#
|
561
|
+
# Time complexity: *O(n)*
|
562
|
+
#
|
563
|
+
# @yieldparam [Object] An element of the list.
|
564
|
+
# @return [self, Enumerator, nil]
|
565
|
+
def select!
|
566
|
+
return enum_for(__method__) unless block_given?
|
567
|
+
return if empty?
|
568
|
+
|
569
|
+
removed = false
|
570
|
+
prev_node = nil
|
571
|
+
node = @head
|
572
|
+
next_node = node.next
|
573
|
+
loop do
|
574
|
+
keep = yield(node.value)
|
575
|
+
if keep
|
576
|
+
prev_node = node
|
577
|
+
node = prev_node.next
|
578
|
+
next_node = node&.next
|
579
|
+
else
|
580
|
+
removed = true
|
581
|
+
prev_node, node, next_node = delete_node_with_prev(prev_node, next_node)
|
582
|
+
end
|
583
|
+
|
584
|
+
break if node.nil?
|
585
|
+
end
|
586
|
+
|
587
|
+
return unless removed
|
588
|
+
|
589
|
+
self
|
590
|
+
end
|
591
|
+
alias filter! select!
|
592
|
+
|
593
|
+
# Time complexity: *O(n)*
|
594
|
+
#
|
595
|
+
# @param separator [String, nil]
|
596
|
+
# @yieldparam [Object]
|
597
|
+
# @return [String]
|
598
|
+
def join(separator = nil)
|
599
|
+
result = ::String.new
|
600
|
+
each_node do |node|
|
601
|
+
string_value = block_given? ? yield(node.value) : node.value
|
602
|
+
result << string_value.to_s
|
603
|
+
result << separator if separator && node.next
|
604
|
+
end
|
605
|
+
|
606
|
+
result
|
607
|
+
end
|
608
|
+
|
609
|
+
# Appends the given `objects` to `self`.
|
610
|
+
#
|
611
|
+
# Time complexity: *O(n)*.
|
612
|
+
#
|
613
|
+
# @param objects [Object]
|
614
|
+
# @return [self]
|
615
|
+
def push(*objects)
|
616
|
+
return self if objects.empty?
|
617
|
+
|
618
|
+
@head = Node.new objects.shift if empty?
|
619
|
+
tail.insert_after(*objects)
|
620
|
+
|
621
|
+
self
|
622
|
+
end
|
623
|
+
alias << push
|
624
|
+
alias add push
|
625
|
+
alias append push
|
626
|
+
|
627
|
+
# Prepends the given `objects` to `self`.
|
628
|
+
#
|
629
|
+
# Time complexity is *O(1)* if one item is given.
|
630
|
+
# Otherwise it's *O(m)*, where *m* is the length of given `objects`.
|
631
|
+
#
|
632
|
+
# @param objects [Array]
|
633
|
+
# @return [self]
|
634
|
+
def unshift(*objects)
|
635
|
+
objects.reverse_each do |obj|
|
636
|
+
new_node = Node.new obj
|
637
|
+
new_node.next = @head
|
638
|
+
@head = new_node
|
639
|
+
end
|
640
|
+
|
641
|
+
self
|
642
|
+
end
|
643
|
+
alias >> unshift
|
644
|
+
alias prepend unshift
|
645
|
+
|
646
|
+
# Inserts given objects before or after the element at `Integer` index offset; returns `self`.
|
647
|
+
#
|
648
|
+
# Inserts all given objects before the element at offset index:
|
649
|
+
#
|
650
|
+
# a = LinkedList[:foo, 'bar', 2]
|
651
|
+
# a.insert(1, :bat, :bam) # => LinkedList[:foo, :bat, :bam, "bar", 2]
|
652
|
+
#
|
653
|
+
# Extends the list if `index` is beyond the list (`index` >= `self.size`):
|
654
|
+
#
|
655
|
+
# a = LinkedList[:foo, 'bar', 2]
|
656
|
+
# a.insert(5, :bat, :bam)
|
657
|
+
# a # => LinkedList[:foo, "bar", 2, nil, nil, :bat, :bam]
|
658
|
+
#
|
659
|
+
# Does nothing if no objects given:
|
660
|
+
#
|
661
|
+
# a = LinkedList[:foo, 'bar', 2]
|
662
|
+
# a.insert(1)
|
663
|
+
# a.insert(50)
|
664
|
+
# a.insert(-50)
|
665
|
+
# a # => LinkedList[:foo, "bar", 2]
|
666
|
+
#
|
667
|
+
# @param index [Integer]
|
668
|
+
# @param objects [Array]
|
669
|
+
# @return [self]
|
670
|
+
def insert(index, *objects)
|
671
|
+
index = index.to_int
|
672
|
+
|
673
|
+
raise ::ArgumentError, 'negative list index' if index.negative?
|
674
|
+
return unshift(*objects) if index.zero?
|
675
|
+
return self if objects.empty?
|
676
|
+
|
677
|
+
last_node = nil
|
678
|
+
prev_node = nil
|
679
|
+
found_index = false
|
680
|
+
last_index = 0
|
681
|
+
each_node.with_index do |node, i|
|
682
|
+
last_index = i
|
683
|
+
last_node = node
|
684
|
+
next (prev_node = node) unless i >= index
|
685
|
+
|
686
|
+
found_index = true
|
687
|
+
prev_node.insert_after(*objects)
|
688
|
+
break
|
689
|
+
end
|
690
|
+
|
691
|
+
return self if found_index
|
692
|
+
|
693
|
+
@head = last_node = Node.new if empty?
|
694
|
+
|
695
|
+
loop do
|
696
|
+
last_index += 1
|
697
|
+
break if last_index >= index
|
698
|
+
|
699
|
+
new_node = Node.new
|
700
|
+
last_node.next = new_node
|
701
|
+
last_node = new_node
|
702
|
+
end
|
703
|
+
last_node.insert_after(*objects)
|
704
|
+
|
705
|
+
self
|
706
|
+
end
|
707
|
+
|
708
|
+
# Concatenates this linked list with another linked list or `Enumerable`.
|
709
|
+
#
|
710
|
+
# Time complexity is *O(m)*, where *m* is the length of given `enum`.
|
711
|
+
#
|
712
|
+
# @param enum [Object]
|
713
|
+
# @return [self]
|
714
|
+
def concat(enum)
|
715
|
+
do_with_enum(enum) { |o| self << o }
|
716
|
+
|
717
|
+
self
|
718
|
+
end
|
719
|
+
|
720
|
+
# Concatenates this linked list with another linked list.
|
721
|
+
#
|
722
|
+
# This version is faster for two linked lists but more unsafe
|
723
|
+
# because concatenating them happens in place
|
724
|
+
# by just linking the tail of the first list to the head of the second one.
|
725
|
+
# This means that modifying the second list after concatenating it
|
726
|
+
# will change the concatenated list as well!
|
727
|
+
#
|
728
|
+
# Time complexity is *O(n)*, where *n* is the length of `self`.
|
729
|
+
#
|
730
|
+
# @param list [self]
|
731
|
+
# @return [self]
|
732
|
+
def concat!(list)
|
733
|
+
raise ::ArgumentError, 'value must be a linked list' unless list.instance_of?(self.class)
|
734
|
+
|
735
|
+
tail.next = list.head
|
736
|
+
|
737
|
+
self
|
738
|
+
end
|
739
|
+
|
740
|
+
# Returns a new `LinkedList` containing all non-nil elements from `self`
|
741
|
+
#
|
742
|
+
# Time complexity: *O(n)*
|
743
|
+
#
|
744
|
+
# @return [self]
|
745
|
+
def compact
|
746
|
+
result = self.class.new
|
747
|
+
|
748
|
+
each do |value|
|
749
|
+
next if value.nil?
|
750
|
+
|
751
|
+
result << value
|
752
|
+
end
|
753
|
+
|
754
|
+
result
|
755
|
+
end
|
756
|
+
|
757
|
+
# Removes all `nil` elements from `self`.
|
758
|
+
#
|
759
|
+
# Returns `self` if any elements removed, otherwise `nil`.
|
760
|
+
#
|
761
|
+
# Time complexity: *O(n)*
|
762
|
+
#
|
763
|
+
# @return [self, nil]
|
764
|
+
def compact!
|
765
|
+
removed = nil
|
766
|
+
prev_node = nil
|
767
|
+
each_node do |node|
|
768
|
+
if node.value.nil?
|
769
|
+
removed = true
|
770
|
+
prev_node, = delete_node_with_prev(prev_node, node.next)
|
771
|
+
next
|
772
|
+
end
|
773
|
+
|
774
|
+
prev_node = node
|
775
|
+
end
|
776
|
+
return self if removed
|
777
|
+
|
778
|
+
nil
|
779
|
+
end
|
780
|
+
|
781
|
+
# Checks whether `self` is a superlist of the provided list `other`
|
782
|
+
# (if the `other` list is a sublist of `self`).
|
783
|
+
# Time complexity is *O(n)*, where *n* is the length of `self`.
|
784
|
+
#
|
785
|
+
# @param other [self]
|
786
|
+
# @return [Boolean]
|
787
|
+
def superlist?(other)
|
788
|
+
raise ::ArgumentError, 'value must be a linked list' unless other.is_a?(self.class)
|
789
|
+
|
790
|
+
other.sublist?(self)
|
791
|
+
end
|
792
|
+
|
793
|
+
# Checks whether `self` is a sublist of the provided list `other`.
|
794
|
+
# Time complexity is *O(m)*, where *m* is the length of `other`.
|
795
|
+
#
|
796
|
+
# @param other [self]
|
797
|
+
# @return [Boolean]
|
798
|
+
def sublist?(other)
|
799
|
+
return true if equal?(other)
|
800
|
+
raise ::ArgumentError, 'value must be a linked list' unless other.is_a?(self.class)
|
801
|
+
return true if (empty? && !other.empty?) || (empty? && other.empty?)
|
802
|
+
return false if !empty? && other.empty?
|
803
|
+
|
804
|
+
self_node = @head
|
805
|
+
other_node = other.head
|
806
|
+
|
807
|
+
at_least_one_equal = false
|
808
|
+
loop do
|
809
|
+
return true if self_node.equal?(other_node)
|
810
|
+
return true if self_node.nil?
|
811
|
+
return false if other_node.nil?
|
812
|
+
|
813
|
+
if self_node.value == other_node.value
|
814
|
+
at_least_one_equal = true
|
815
|
+
self_node = self_node.next
|
816
|
+
other_node = other_node.next
|
817
|
+
next
|
818
|
+
end
|
819
|
+
|
820
|
+
return false if at_least_one_equal
|
821
|
+
|
822
|
+
other_node = other_node.next
|
823
|
+
end
|
824
|
+
|
825
|
+
true
|
826
|
+
end
|
827
|
+
|
828
|
+
# Returns a new LinkedList which is the result of
|
829
|
+
# concatenating this linked list with another linked list or `Enumerable`.
|
830
|
+
#
|
831
|
+
# Time complexity is *O(n + m)*, where *n* is the length of `self` and *m* is the length of `other`.
|
832
|
+
#
|
833
|
+
# @param enum [Object]
|
834
|
+
# @return [self]
|
835
|
+
def +(other)
|
836
|
+
dup.concat(other)
|
837
|
+
end
|
838
|
+
|
839
|
+
# Returns true if two linked lists are equal. The equality of each couple
|
840
|
+
# of elements is defined according to `#==`.
|
841
|
+
#
|
842
|
+
# Time complexity is *O(min(n, m))*, where *n* is the length of `self`
|
843
|
+
# and *m* is the length of `other`.
|
844
|
+
#
|
845
|
+
# LinkedList[1, 2] == LinkedList[1, 2] #=> true
|
846
|
+
# LinkedList[1, 2] == LinkedList[1, 2.0] #=> true
|
847
|
+
# LinkedList[1, 3, 5] == LinkedList[1, 5] #=> false
|
848
|
+
# LinkedList[1, 3, 5] == LinkedList[1, 3] #=> false
|
849
|
+
# LinkedList['a', 'b', 'c'] == LinkedList['a', 'c', 'b'] #=> true
|
850
|
+
# LinkedList['a', 'b', 'c'] == ['a', 'c', 'b'] #=> false
|
851
|
+
#
|
852
|
+
# @return [Boolean]
|
853
|
+
def eql?(other)
|
854
|
+
return true if equal?(other)
|
855
|
+
return false unless other.is_a?(self.class)
|
856
|
+
|
857
|
+
self_node = @head
|
858
|
+
other_node = other.head
|
859
|
+
loop do
|
860
|
+
break if self_node.nil? && other_node.nil?
|
861
|
+
return false if self_node.nil? || other_node.nil?
|
862
|
+
return false if self_node.value != other_node.value
|
863
|
+
|
864
|
+
self_node = self_node.next
|
865
|
+
other_node = other_node.next
|
866
|
+
end
|
867
|
+
|
868
|
+
true
|
869
|
+
end
|
870
|
+
alias == eql?
|
871
|
+
|
872
|
+
# Returns `true` if the given object is a member of the list,
|
873
|
+
# and `false` otherwise.
|
874
|
+
#
|
875
|
+
# Keep in mind that checking for inclusion will
|
876
|
+
# will require the list to be traversed in its entirety
|
877
|
+
# in the worst case.
|
878
|
+
# Time complexity: *O(n)*.
|
879
|
+
#
|
880
|
+
# Used in case statements:
|
881
|
+
#
|
882
|
+
# case :apple
|
883
|
+
# when LinkedList[:potato, :carrot]
|
884
|
+
# "vegetable"
|
885
|
+
# when LinkedList[:apple, :banana]
|
886
|
+
# "fruit"
|
887
|
+
# end
|
888
|
+
# # => "fruit"
|
889
|
+
#
|
890
|
+
# Or by itself:
|
891
|
+
#
|
892
|
+
# LinkedList[1, 2, 3] === 2 #=> true
|
893
|
+
# LinkedList[1, 2, 3] === 4 #=> false
|
894
|
+
#
|
895
|
+
alias === include?
|
896
|
+
|
897
|
+
# @return [Set]
|
898
|
+
def to_set
|
899
|
+
set = ::Set.new
|
900
|
+
each do |value|
|
901
|
+
set << value
|
902
|
+
end
|
903
|
+
|
904
|
+
set
|
905
|
+
end
|
906
|
+
|
907
|
+
# @return [String]
|
908
|
+
def inspect
|
909
|
+
"#<#{self.class}: {#{join(', ', &:inspect)}}>"
|
910
|
+
end
|
911
|
+
|
912
|
+
private
|
913
|
+
|
914
|
+
def slice_with_enum(klass, index, length = nil)
|
915
|
+
return klass.new if length&.zero?
|
916
|
+
return at(index) if length.nil? && index.is_a?(::Numeric)
|
917
|
+
return if length&.negative?
|
918
|
+
|
919
|
+
range = if index.is_a?(::Range)
|
920
|
+
index
|
921
|
+
elsif length
|
922
|
+
index..(index + length - 1)
|
923
|
+
else
|
924
|
+
index..index
|
925
|
+
end
|
926
|
+
|
927
|
+
if range.begin&.negative? || range.end&.negative?
|
928
|
+
result = to_a[range]
|
929
|
+
return result unless result.is_a?(::Array)
|
930
|
+
|
931
|
+
return klass[*result]
|
932
|
+
end
|
933
|
+
|
934
|
+
result = klass.new
|
935
|
+
added = nil
|
936
|
+
each_with_index do |val, i|
|
937
|
+
includes = range.include? i
|
938
|
+
break if added && !includes
|
939
|
+
next unless includes
|
940
|
+
|
941
|
+
added ||= true
|
942
|
+
result << val
|
943
|
+
end
|
944
|
+
return result unless result.empty?
|
945
|
+
|
946
|
+
nil
|
947
|
+
end
|
948
|
+
|
949
|
+
def delete_node_with_prev(prev_node, next_node)
|
950
|
+
if prev_node.nil?
|
951
|
+
node = @head = next_node
|
952
|
+
next_node = node&.next
|
953
|
+
|
954
|
+
return [prev_node, node, next_node]
|
955
|
+
end
|
956
|
+
|
957
|
+
prev_node.next = next_node
|
958
|
+
node = next_node
|
959
|
+
next_node = node&.next
|
960
|
+
|
961
|
+
[prev_node, node, next_node]
|
962
|
+
end
|
963
|
+
|
964
|
+
def initialize_dup(orig)
|
965
|
+
super
|
966
|
+
@head = nil
|
967
|
+
orig.each { |o| self << o }
|
968
|
+
end
|
969
|
+
|
970
|
+
def initialize_clone(orig)
|
971
|
+
super
|
972
|
+
@head = nil
|
973
|
+
orig.each { |o| self << o }
|
974
|
+
end
|
975
|
+
|
976
|
+
# @param enum [Object]
|
977
|
+
# @return [void]
|
978
|
+
def do_with_enum(enum, &block)
|
979
|
+
return unless block
|
980
|
+
return enum.each_entry(&block) if enum.respond_to?(:each_entry)
|
981
|
+
return enum.each(&block) if enum.respond_to?(:each)
|
982
|
+
|
983
|
+
raise ::ArgumentError, 'value must be enumerable'
|
984
|
+
end
|
985
|
+
end
|