-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlinked_list.rb
More file actions
159 lines (128 loc) · 3.12 KB
/
linked_list.rb
File metadata and controls
159 lines (128 loc) · 3.12 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
# frozen_string_literal: true
# Node
class Node
protected attr_accessor :next_node, :value
def initialize(value = nil, next_node = nil)
@value = value
@next_node = next_node
end
end
# Linked List
class LinkedList < Node
attr_reader :head, :tail, :size
private attr_writer :head, :tail, :size
def initialize
@head = nil
@tail = nil
@size = 0
end
# Adds a new node containing value to the end of the list
def append(value)
@size += 1
if @head.nil?
@head = Node.new(value)
@tail = @head
else
@tail.next_node = Node.new(value)
@tail = @tail.next_node
end
end
# Adds a new node containing value to the start of the list
def prepend(value)
@size += 1
if @head.nil?
@head = Node.new(value)
@tail = @head
else
@head = Node.new(value, @head)
end
end
# Iterates over the linked list nodes passing each node to the block
def each
return to_enum(:each) unless block_given?
node = @head
@size.times do
yield node
node = node.next_node
end
self
end
# Iterates over the linked list nodes passing the node
# and its position in the list to the block
def each_with_index
index = 0
each do |node|
yield node, index
index += 1
end
self
end
# Returns the node at the given index
def at(index)
index = @size + index if index.negative?
case index
when 0 then @head
when @size - 1 then @tail
when 1...@size
each_with_index { |node, i| return node if i == index }
end
end
# Removes the last node from the list
def pop
return if @size.zero?
if @size == 1
@head, @tail = nil
else
previous_node = at(-2)
previous_node.next_node = nil
@tail = previous_node
end
@size -= 1
end
# Returns true if the passed in value is in the list
# Otherwise returns false
def contains?(value)
each { |node| return true if node.value == value }
false
end
# Returns the index of the node containing the passed in value
# Otherwise returns nil
def find(value)
each_with_index { |node, index| return index if node.value == value }
nil
end
# Represents the linked list objects as string and prints it
def to_s
return if @size.zero?
each { |node| print "( #{node.value} ) -> " }
puts 'nil'
end
# Inserts a new node with the provided value at the given index
def insert_at(value, index)
index = @size + 1 + index if index.negative?
case index
when 0 then prepend(value)
when 1...@size
previous_node = at(index - 1)
@size += 1
previous_node.next_node = Node.new(value, previous_node.next_node)
else
append(value) # if index >= @size
end
end
# Removes the node at the given index
def remove_at(index)
return if @head.nil?
index = @size + index if index.negative?
case index
when 0
@head = @head.next_node
@size -= 1
when @size - 1 then pop
when 1...@size
previous_node = at(index - 1)
previous_node.next_node = previous_node.next_node.next_node
@size -= 1
end
end
end