ds 0.0.4 → 0.0.6
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 +11 -0
- data/.rubocop_todo.yml +452 -0
- data/.travis.yml +12 -0
- data/Gemfile +1 -1
- data/README.rdoc +185 -214
- data/Rakefile +8 -3
- data/ds.gemspec +16 -13
- data/lib/ds.rb +20 -30
- data/lib/ds/{matrixes → arrays}/array_2d.rb +9 -10
- data/lib/ds/arrays/expandable_array.rb +34 -0
- data/lib/ds/arrays/heap_store.rb +32 -0
- data/lib/ds/arrays/tri_matrix.rb +33 -0
- data/lib/ds/lists/list.rb +310 -186
- data/lib/ds/lists/list_element.rb +14 -11
- data/lib/ds/pair.rb +4 -4
- data/lib/ds/queues/priority_queue.rb +33 -20
- data/lib/ds/queues/simple_queue.rb +55 -0
- data/lib/ds/sets/indexed_set.rb +37 -0
- data/lib/ds/stacks/stack.rb +25 -17
- data/lib/ds/trees/binary_heap.rb +71 -66
- data/lib/ds/trees/binary_tree.rb +40 -44
- data/lib/ds/trees/red_black_tree.rb +123 -0
- data/lib/ds/trees/red_black_tree/node.rb +21 -0
- data/lib/ds/trees/tree.rb +50 -48
- data/lib/ds/trees/tree_walker.rb +73 -144
- data/lib/ds/trees/trie.rb +67 -37
- data/lib/ds/trees/trie/node.rb +48 -0
- data/lib/ds/version.rb +2 -1
- data/test/help.rb +3 -6
- data/test/performance/binary_heap_performance_test.rb +20 -0
- data/test/performance/list_performance_test.rb +36 -0
- data/test/performance/priority_queue_performance.rb +32 -0
- data/test/performance/rbt_performance_test.rb +17 -0
- data/test/performance/simple_queue_performance_test.rb +37 -0
- data/test/performance/stack_test.rb +45 -0
- data/test/test_array2d.rb +29 -31
- data/test/test_binary_heap.rb +29 -23
- data/test/test_binary_tree.rb +30 -20
- data/test/test_expandable_array.rb +6 -10
- data/test/test_heap_store.rb +34 -0
- data/test/test_indexed_set.rb +26 -0
- data/test/test_list.rb +226 -109
- data/test/test_list_element.rb +34 -16
- data/test/test_pair.rb +5 -8
- data/test/test_priority_queue.rb +43 -64
- data/test/test_queue.rb +12 -61
- data/test/test_red_black_tree.rb +46 -0
- data/test/test_stack.rb +35 -39
- data/test/test_tree.rb +42 -29
- data/test/test_tree_walker.rb +27 -52
- data/test/test_tri_matrix.rb +6 -11
- data/test/test_trie.rb +59 -17
- metadata +80 -35
- data/lib/ds/ext/array_x.rb +0 -35
- data/lib/ds/graphs/digraph.rb +0 -20
- data/lib/ds/graphs/edge.rb +0 -15
- data/lib/ds/graphs/graph.rb +0 -111
- data/lib/ds/graphs/graph_as_matrix.rb +0 -113
- data/lib/ds/graphs/graph_as_tri_matrix.rb +0 -24
- data/lib/ds/lists/cyclic_list.rb +0 -21
- data/lib/ds/lists/ring.rb +0 -42
- data/lib/ds/matrixes/expandable_array.rb +0 -37
- data/lib/ds/matrixes/tri_matrix.rb +0 -30
- data/lib/ds/queues/queue.rb +0 -53
- data/lib/ds/sets/ordered_set.rb +0 -32
- data/lib/ds/trees/binary_search_tree.rb +0 -34
- data/lib/ds/trees/complete_binary_tree.rb +0 -60
- data/test/test_array_x.rb +0 -51
- data/test/test_binary_search_tree.rb +0 -39
- data/test/test_complete_binary_tree.rb +0 -58
- data/test/test_digraph.rb +0 -134
- data/test/test_graph.rb +0 -80
- data/test/test_ordered_set.rb +0 -28
- data/test/test_ring.rb +0 -28
data/Rakefile
CHANGED
@@ -4,10 +4,15 @@ require 'rake/testtask'
|
|
4
4
|
Rake::TestTask.new do |t|
|
5
5
|
t.libs << 'test'
|
6
6
|
t.test_files = FileList['test/test*.rb']
|
7
|
-
#t.pattern = "test/test_*.rb"
|
8
7
|
t.verbose = true
|
9
8
|
end
|
10
9
|
|
11
|
-
|
12
|
-
|
10
|
+
Rake::TestTask.new do |t|
|
11
|
+
t.name = 'test:performance'
|
12
|
+
t.libs << 'test'
|
13
|
+
t.test_files = FileList['test/performance/*test.rb']
|
14
|
+
t.verbose = true
|
15
|
+
end
|
13
16
|
|
17
|
+
desc 'Run tests'
|
18
|
+
task default: :test
|
data/ds.gemspec
CHANGED
@@ -1,20 +1,23 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path(
|
3
|
-
require
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'ds/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
|
-
s.name =
|
6
|
+
s.name = 'ds'
|
7
7
|
s.version = DS::VERSION
|
8
|
-
s.authors = [
|
9
|
-
s.email = [
|
10
|
-
s.homepage =
|
11
|
-
s.summary =
|
12
|
-
s.description =
|
13
|
-
|
14
|
-
s.rubyforge_project = "ds"
|
8
|
+
s.authors = ['knife']
|
9
|
+
s.email = ['satre@o2.pl']
|
10
|
+
s.homepage = ''
|
11
|
+
s.summary = 'Some common data structures.'
|
12
|
+
s.description = 'Data structures (lists, stacks, trees, heaps, graphs..) in pure Ruby.'
|
13
|
+
s.rubyforge_project = 'ds'
|
15
14
|
|
16
15
|
s.files = `git ls-files`.split("\n")
|
17
|
-
s.test_files = `git ls-files --
|
18
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
-
s.require_paths = [
|
16
|
+
s.test_files = `git ls-files -- test/**/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
18
|
+
s.require_paths = ['lib']
|
19
|
+
|
20
|
+
s.add_development_dependency 'bundler'
|
21
|
+
s.add_development_dependency 'rake'
|
22
|
+
s.add_development_dependency 'minitest'
|
20
23
|
end
|
data/lib/ds.rb
CHANGED
@@ -1,36 +1,26 @@
|
|
1
|
-
require
|
1
|
+
require 'ds/version'
|
2
2
|
|
3
|
-
require
|
4
|
-
require "ds/pair"
|
3
|
+
require 'ds/pair'
|
5
4
|
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
5
|
+
require 'ds/arrays/expandable_array'
|
6
|
+
require 'ds/arrays/array_2d'
|
7
|
+
require 'ds/arrays/tri_matrix'
|
8
|
+
require 'ds/arrays/heap_store'
|
9
9
|
|
10
|
-
require
|
11
|
-
|
12
|
-
require "ds/lists/list_element"
|
13
|
-
require "ds/lists/list"
|
14
|
-
require "ds/lists/cyclic_list"
|
15
|
-
require "ds/lists/ring"
|
16
|
-
|
17
|
-
require "ds/stacks/stack"
|
18
|
-
require "ds/queues/queue"
|
19
|
-
require "ds/queues/priority_queue"
|
20
|
-
|
21
|
-
require "ds/trees/tree"
|
22
|
-
require "ds/trees/tree_walker"
|
23
|
-
require "ds/trees/binary_tree"
|
24
|
-
require "ds/trees/binary_search_tree"
|
25
|
-
require "ds/trees/complete_binary_tree"
|
26
|
-
require "ds/trees/binary_heap"
|
27
|
-
require "ds/trees/trie"
|
28
|
-
|
29
|
-
require "ds/graphs/edge"
|
30
|
-
require "ds/graphs/graph_as_matrix"
|
31
|
-
require "ds/graphs/graph_as_tri_matrix"
|
32
|
-
require "ds/graphs/graph"
|
33
|
-
require "ds/graphs/digraph"
|
10
|
+
require 'ds/sets/indexed_set'
|
34
11
|
|
12
|
+
require 'ds/lists/list_element'
|
13
|
+
require 'ds/lists/list'
|
35
14
|
|
15
|
+
require 'ds/stacks/stack'
|
16
|
+
require 'ds/queues/simple_queue'
|
17
|
+
require 'ds/queues/priority_queue'
|
36
18
|
|
19
|
+
require 'ds/trees/tree'
|
20
|
+
require 'ds/trees/tree_walker'
|
21
|
+
require 'ds/trees/binary_tree'
|
22
|
+
require 'ds/trees/binary_heap'
|
23
|
+
require 'ds/trees/red_black_tree'
|
24
|
+
require 'ds/trees/red_black_tree/node'
|
25
|
+
require 'ds/trees/trie'
|
26
|
+
require 'ds/trees/trie/node'
|
@@ -1,17 +1,13 @@
|
|
1
1
|
module DS
|
2
|
-
|
3
|
-
#Implements two dimensional array.
|
2
|
+
# Implements two dimensional array.
|
4
3
|
class Array2D
|
5
|
-
|
6
|
-
|
7
|
-
#Creates new two dimensional array. Init is the default value of the array.
|
8
|
-
def initialize(size=1,init=0)
|
4
|
+
# Creates new two dimensional array. Init is the default value of the array.
|
5
|
+
def initialize(size = 1, init = 0)
|
9
6
|
@init = init
|
10
|
-
@store = Array.new(size){Array.new(size){init}}
|
7
|
+
@store = Array.new(size) { Array.new(size) { init } }
|
11
8
|
end
|
12
9
|
|
13
|
-
|
14
|
-
def [](x,y)
|
10
|
+
def [](x, y)
|
15
11
|
if @store[x].nil?
|
16
12
|
@store[x] = []
|
17
13
|
@init
|
@@ -22,7 +18,7 @@ module DS
|
|
22
18
|
end
|
23
19
|
end
|
24
20
|
|
25
|
-
def []=(x,y,v)
|
21
|
+
def []=(x, y, v)
|
26
22
|
@store[x] = [] if @store[x].nil?
|
27
23
|
@store[x][y] = v
|
28
24
|
end
|
@@ -35,5 +31,8 @@ module DS
|
|
35
31
|
@store.flatten
|
36
32
|
end
|
37
33
|
|
34
|
+
def size
|
35
|
+
@store.size
|
36
|
+
end
|
38
37
|
end
|
39
38
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module DS
|
2
|
+
# Class provides access to any element in array. If index i
|
3
|
+
# is greter than array size then elements from size to i are
|
4
|
+
# filled with extender.
|
5
|
+
class ExpandableArray < Array
|
6
|
+
def initialize(size = 0, extender = 0)
|
7
|
+
@extender = extender
|
8
|
+
super(size, extender)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Returns element at index. If index is greater than size of array then
|
12
|
+
# elements from size to index are filled with extender.
|
13
|
+
def [](x)
|
14
|
+
expand(size, x) if x >= size
|
15
|
+
super(x)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Sets the element at index. If index is greater than size of array then
|
19
|
+
# elements from size to index are filled with extender.
|
20
|
+
def []=(x, v)
|
21
|
+
old_size = size
|
22
|
+
super(x, v)
|
23
|
+
expand(old_size, size - 2) if size - old_size > 1
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def expand(from, to)
|
29
|
+
(from..to).each do |i|
|
30
|
+
self[i] = @extender
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module DS
|
4
|
+
# Simple Array-like data structure with indexing starting from one.
|
5
|
+
class HeapStore
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def_delegators :@store, :push, :pop, :[], :[]=
|
9
|
+
|
10
|
+
def initialize(*args)
|
11
|
+
@store = [nil] + args.to_a
|
12
|
+
end
|
13
|
+
|
14
|
+
def length
|
15
|
+
@store.size - 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def first
|
19
|
+
@store[1]
|
20
|
+
end
|
21
|
+
|
22
|
+
alias size length
|
23
|
+
|
24
|
+
def empty?
|
25
|
+
length <= 0
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_a
|
29
|
+
@store[1..-1]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DS
|
2
|
+
# Class implements Triangular Matrix (lower).
|
3
|
+
class TriMatrix
|
4
|
+
# Creates new triangular matrix.
|
5
|
+
def initialize(init = 0)
|
6
|
+
@store = ExpandableArray.new(0, init)
|
7
|
+
@max = 0
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns element at index x,y (or y,x).
|
11
|
+
def [](x, y)
|
12
|
+
x, y = y, x if y > x
|
13
|
+
index = (x * x + x) / 2 + y
|
14
|
+
@store[index]
|
15
|
+
end
|
16
|
+
|
17
|
+
# Sets the element at index x,y (or y,x).
|
18
|
+
def []=(x, y, v)
|
19
|
+
x, y = y, x if y > x
|
20
|
+
index = (x * x + x) / 2 + y
|
21
|
+
@max = x if x > @max
|
22
|
+
@store[index] = v
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_a
|
26
|
+
@store
|
27
|
+
end
|
28
|
+
|
29
|
+
def size
|
30
|
+
@max
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/ds/lists/list.rb
CHANGED
@@ -1,300 +1,424 @@
|
|
1
1
|
module DS
|
2
|
+
class ListError < StandardError; end
|
2
3
|
|
3
|
-
#Implements simple list data structure.
|
4
|
+
# Implements simple list data structure.
|
4
5
|
class List
|
5
|
-
|
6
6
|
include Enumerable
|
7
|
+
include Comparable
|
7
8
|
|
8
9
|
attr_accessor :head, :tail
|
9
10
|
|
10
|
-
#Creates new list.
|
11
|
-
def initialize(
|
12
|
-
@
|
13
|
-
@
|
11
|
+
# Creates new list.
|
12
|
+
def initialize(*arr)
|
13
|
+
@size = 0
|
14
|
+
@head = nil
|
15
|
+
@tail = nil
|
16
|
+
from_array(arr) if arr.any?
|
14
17
|
end
|
15
18
|
|
16
|
-
#
|
17
|
-
def
|
18
|
-
list = new
|
19
|
-
|
20
|
-
arr.each{ |e| tail = tail.append(e) }
|
21
|
-
list.tail = tail
|
19
|
+
# Clones list
|
20
|
+
def clone
|
21
|
+
list = self.class.new
|
22
|
+
each { |e| list.append(e.data) }
|
22
23
|
list
|
23
24
|
end
|
24
25
|
|
25
|
-
#
|
26
|
+
# Clears list by reseting head and tail to nil
|
27
|
+
def clear
|
28
|
+
@size = 0
|
29
|
+
@head = nil
|
30
|
+
@tail = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
# Appends new element to list. Returns list tail
|
26
34
|
def append(x)
|
27
|
-
last_elem = self.tail
|
28
35
|
if !empty?
|
29
|
-
@tail =
|
36
|
+
@tail = tail.append(x)
|
37
|
+
increment_size
|
30
38
|
else
|
31
|
-
|
32
|
-
@tail = @head
|
39
|
+
create_first(x)
|
33
40
|
end
|
41
|
+
@tail
|
34
42
|
end
|
35
43
|
|
36
|
-
alias
|
44
|
+
alias << append
|
45
|
+
alias push append
|
37
46
|
|
38
|
-
#Prepends new element to list.
|
39
|
-
def
|
47
|
+
# Prepends new element to list. Returns list head
|
48
|
+
def unshift(x)
|
40
49
|
el = ListElement.new(x)
|
41
50
|
el.next = @head
|
51
|
+
@head.prev = el if @head
|
52
|
+
|
53
|
+
increment_size
|
42
54
|
@head = el
|
43
55
|
end
|
44
56
|
|
45
|
-
#Removes
|
46
|
-
def
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
else
|
57
|
+
# Removes list head.
|
58
|
+
def shift
|
59
|
+
raise ListError, 'List already empty' if empty?
|
60
|
+
remove(head).data
|
61
|
+
end
|
51
62
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
63
|
+
# Return ListElement if it is on list otherwise returns nil
|
64
|
+
def get(x)
|
65
|
+
el = head
|
66
|
+
el = el.next while el && el != x
|
67
|
+
el
|
68
|
+
end
|
57
69
|
|
58
|
-
|
70
|
+
# Return ListElement if it is on list or raises error
|
71
|
+
def get!(x)
|
72
|
+
found = get(x)
|
73
|
+
raise ListError, 'Element not found' unless found
|
74
|
+
end
|
59
75
|
|
60
|
-
|
61
|
-
|
76
|
+
# Returns list element on given index.
|
77
|
+
def at(index)
|
78
|
+
found = nil
|
79
|
+
find_index = lambda do |element, i|
|
80
|
+
if i == index
|
81
|
+
found = element
|
82
|
+
break
|
83
|
+
end
|
62
84
|
end
|
63
|
-
|
85
|
+
if index >= 0
|
86
|
+
each_with_index(&find_index)
|
87
|
+
else
|
88
|
+
reverse_each(&find_index)
|
89
|
+
end
|
90
|
+
found
|
64
91
|
end
|
65
92
|
|
66
|
-
#
|
67
|
-
def
|
68
|
-
|
93
|
+
# Returns list element on given index.
|
94
|
+
def [](i, count = nil)
|
95
|
+
return [] if count && count < 0
|
96
|
+
i = (i...i + count) if count && count > 0
|
97
|
+
case i
|
98
|
+
when Integer
|
99
|
+
at(i)
|
100
|
+
when Range
|
101
|
+
elements_in_range(i)
|
102
|
+
end
|
69
103
|
end
|
70
104
|
|
71
|
-
#
|
72
|
-
def
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
105
|
+
# Sets list element on given index.
|
106
|
+
def []=(i, count = 1, val)
|
107
|
+
if i.is_a? Range
|
108
|
+
index = i.first
|
109
|
+
count = i.size
|
110
|
+
else
|
111
|
+
index = i
|
78
112
|
end
|
79
113
|
|
80
|
-
raise
|
114
|
+
raise ListError, 'Ivalid count parameter' unless valid_count?(count, index)
|
81
115
|
|
82
|
-
|
83
|
-
|
116
|
+
el = at(index)
|
117
|
+
raise ListError, 'Element not found' unless el
|
118
|
+
if val.is_a? Array
|
119
|
+
replace(el, List.new(*val), count)
|
120
|
+
else
|
121
|
+
el.data = val
|
122
|
+
end
|
123
|
+
end
|
84
124
|
|
85
|
-
|
86
|
-
|
125
|
+
# Replaces list elements with other list
|
126
|
+
def replace(el, list, count = 1)
|
127
|
+
if el.head?
|
128
|
+
replace_head(el, list, count)
|
129
|
+
elsif el.tail?
|
130
|
+
replace_tail(el, list, count)
|
131
|
+
else
|
132
|
+
replace_inside(el, list, count)
|
87
133
|
end
|
88
134
|
end
|
89
135
|
|
90
|
-
#
|
91
|
-
def
|
92
|
-
|
136
|
+
# Checks if two lists are equal
|
137
|
+
def <=>(other)
|
138
|
+
a = head
|
139
|
+
b = other.head
|
140
|
+
while a && b && a.data == b.data
|
141
|
+
a = a.next
|
142
|
+
b = b.next
|
143
|
+
end
|
144
|
+
compare_list_elements(a, b)
|
145
|
+
end
|
93
146
|
|
94
|
-
|
147
|
+
# Appends one list to other
|
148
|
+
def concat(other)
|
149
|
+
other.head.prev = tail
|
150
|
+
tail.next = other.head
|
151
|
+
self.tail = other.tail
|
152
|
+
@size += other.size
|
153
|
+
self
|
154
|
+
end
|
155
|
+
|
156
|
+
# Inserts element x after another element.
|
157
|
+
def insert_after(x, rel)
|
158
|
+
x = ListElement.new(x)
|
159
|
+
|
160
|
+
el = rel
|
161
|
+
nxt = el.next
|
162
|
+
x.next = nxt
|
163
|
+
nxt.prev = x if nxt
|
164
|
+
el.next = x
|
165
|
+
x.prev = el
|
166
|
+
self.tail = x if x.nil?
|
167
|
+
|
168
|
+
increment_size
|
169
|
+
|
170
|
+
self
|
171
|
+
end
|
172
|
+
|
173
|
+
# Inserts element x before another element.
|
174
|
+
def insert_before(x, rel)
|
95
175
|
if rel == head
|
96
|
-
x
|
97
|
-
|
176
|
+
unshift(x)
|
177
|
+
else
|
178
|
+
x = ListElement.new(x)
|
179
|
+
|
180
|
+
prev = rel.prev
|
181
|
+
prev.next = x
|
182
|
+
x.prev = prev
|
183
|
+
x.next = rel
|
184
|
+
rel.prev = x
|
185
|
+
end
|
186
|
+
increment_size
|
187
|
+
self
|
188
|
+
end
|
98
189
|
|
99
|
-
|
190
|
+
# Removes element x from list.
|
191
|
+
def remove(x)
|
192
|
+
if x == head
|
193
|
+
self.head = head.next
|
194
|
+
x.next = nil
|
195
|
+
head.prev = nil if head
|
100
196
|
else
|
101
|
-
|
102
|
-
prev =
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
197
|
+
nxt = x.next
|
198
|
+
prev = x.prev
|
199
|
+
prev.next = nxt
|
200
|
+
nxt.prev = prev if nxt
|
201
|
+
x.next = nil
|
202
|
+
x.prev = nil
|
107
203
|
|
108
|
-
if
|
109
|
-
raise ListError, "List element not found"
|
110
|
-
else
|
111
|
-
prev.next = x
|
112
|
-
x.next = el
|
113
|
-
end
|
204
|
+
self.tail = prev if nxt.nil?
|
114
205
|
end
|
206
|
+
decrement_size
|
207
|
+
x
|
115
208
|
end
|
116
209
|
|
210
|
+
# Removes last element from list.
|
211
|
+
def pop
|
212
|
+
remove(tail).data
|
213
|
+
end
|
117
214
|
|
118
|
-
#Checks if list is empty.
|
215
|
+
# Checks if list is empty.
|
119
216
|
def empty?
|
120
|
-
|
217
|
+
@size.zero?
|
121
218
|
end
|
122
219
|
|
123
|
-
#Returns last element of the list.
|
220
|
+
# Returns last element of the list.
|
124
221
|
def last
|
125
222
|
tail.data
|
126
223
|
end
|
127
224
|
|
225
|
+
# Returns first element of the list.
|
128
226
|
def first
|
129
227
|
head.data
|
130
228
|
end
|
131
229
|
|
132
|
-
#Returns length of the list.
|
230
|
+
# Returns length of the list.
|
133
231
|
def length
|
134
|
-
|
232
|
+
@size
|
135
233
|
end
|
136
234
|
|
137
|
-
|
235
|
+
alias size length
|
236
|
+
|
237
|
+
# Checks if list is linked at the end with other list.
|
138
238
|
def zip?(other)
|
139
|
-
tail.equal? other.tail
|
239
|
+
tail.equal? other.tail
|
140
240
|
end
|
141
241
|
|
142
|
-
#Returns joint element if exists, otherwise returns nil.
|
242
|
+
# Returns joint element if exists, otherwise returns nil.
|
143
243
|
def joint
|
144
244
|
elem = head
|
145
245
|
elem2 = elem.next
|
146
246
|
|
147
|
-
while elem
|
247
|
+
while elem && elem2
|
148
248
|
|
149
|
-
#traversing by 1
|
249
|
+
# traversing by 1
|
150
250
|
elem = elem.next
|
151
251
|
|
152
|
-
#traversing by 2
|
252
|
+
# traversing by 2
|
153
253
|
elem2 = elem2.next
|
154
254
|
elem2 = elem2.next if elem2
|
155
255
|
|
156
|
-
if elem2.equal? elem
|
157
|
-
return elem
|
158
|
-
end
|
256
|
+
return elem if elem2.equal? elem
|
159
257
|
end
|
160
|
-
|
161
258
|
nil
|
162
259
|
end
|
163
260
|
|
164
|
-
#Returns true if list has cycle.
|
261
|
+
# Returns true if list has cycle.
|
165
262
|
def looped?
|
166
|
-
|
263
|
+
!joint.nil?
|
167
264
|
end
|
168
265
|
|
266
|
+
# Returns cycle size or nil if list has no cycles
|
267
|
+
def cycle_size
|
268
|
+
return unless looped?
|
269
|
+
counter = 0
|
270
|
+
start = joint
|
271
|
+
if start
|
272
|
+
counter = 1
|
273
|
+
elem = start.next
|
274
|
+
while elem != start
|
275
|
+
elem = elem.next
|
276
|
+
counter += 1
|
277
|
+
end
|
278
|
+
end
|
279
|
+
counter
|
280
|
+
end
|
169
281
|
|
170
|
-
#
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
282
|
+
# Reverses list.
|
283
|
+
def reverse!
|
284
|
+
@tail = head
|
285
|
+
prev = head
|
286
|
+
elem = prev.next
|
287
|
+
prev.next = nil
|
288
|
+
while elem
|
289
|
+
nxt = elem.next
|
290
|
+
elem.next = prev
|
291
|
+
prev.prev = elem
|
292
|
+
prev = elem
|
293
|
+
elem = nxt
|
294
|
+
end
|
177
295
|
|
178
|
-
|
296
|
+
@head = prev
|
297
|
+
self
|
298
|
+
end
|
179
299
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
when 1
|
185
|
-
plus_tail = plus.append(el.data)
|
186
|
-
when -1
|
187
|
-
minus_tail = minus.append(el.data)
|
188
|
-
end
|
300
|
+
# Converts list to array.
|
301
|
+
def to_a
|
302
|
+
map(&:data)
|
303
|
+
end
|
189
304
|
|
190
|
-
|
305
|
+
# Default list iterator.
|
306
|
+
def each
|
307
|
+
elem = head
|
308
|
+
while elem
|
309
|
+
yield elem
|
310
|
+
elem = elem.next
|
191
311
|
end
|
192
|
-
|
193
|
-
minus_tail.next = zero.head
|
194
|
-
zero_tail.next = plus.head
|
195
|
-
return minus
|
196
312
|
end
|
197
313
|
|
314
|
+
# Reverse list iterator.
|
315
|
+
def reverse_each
|
316
|
+
elem = tail
|
317
|
+
i = 0
|
318
|
+
while elem
|
319
|
+
i -= 1
|
320
|
+
yield elem, i
|
321
|
+
elem = elem.prev
|
322
|
+
end
|
323
|
+
end
|
198
324
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
b = other.head
|
325
|
+
def to_s
|
326
|
+
to_a.join('=')
|
327
|
+
end
|
203
328
|
|
204
|
-
|
329
|
+
private
|
205
330
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
331
|
+
def from_array(arr)
|
332
|
+
create_first(arr.shift)
|
333
|
+
arr.each { |e| append(e) }
|
334
|
+
end
|
210
335
|
|
211
|
-
|
212
|
-
|
213
|
-
|
336
|
+
# Creates first element in list.
|
337
|
+
def create_first(x)
|
338
|
+
first = unshift(x)
|
339
|
+
self.head = first
|
340
|
+
self.tail = first
|
341
|
+
self
|
342
|
+
end
|
214
343
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
self.head = a
|
220
|
-
b = b.next
|
221
|
-
else
|
222
|
-
a = a.next
|
223
|
-
prev.next = a
|
224
|
-
b = b.next
|
225
|
-
end
|
344
|
+
def elements_in_range(range)
|
345
|
+
arr = []
|
346
|
+
each_with_index do |e, i|
|
347
|
+
arr << e if range.include?(i)
|
226
348
|
end
|
227
|
-
|
349
|
+
arr
|
228
350
|
end
|
229
351
|
|
230
|
-
|
231
|
-
|
352
|
+
def increment_size
|
353
|
+
@size += 1
|
354
|
+
end
|
232
355
|
|
233
|
-
|
234
|
-
|
356
|
+
def decrement_size
|
357
|
+
@size -= 1
|
358
|
+
end
|
235
359
|
|
236
|
-
|
237
|
-
|
238
|
-
|
360
|
+
def compare_list_elements(a, b)
|
361
|
+
if a.nil? && b.nil?
|
362
|
+
0
|
363
|
+
elsif a && b
|
364
|
+
a.data <=> b.data
|
365
|
+
elsif a.nil?
|
366
|
+
-1
|
239
367
|
else
|
240
|
-
|
241
|
-
b = b.next
|
368
|
+
1
|
242
369
|
end
|
370
|
+
end
|
243
371
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
a = a.next
|
248
|
-
else
|
249
|
-
result.append(b.data)
|
250
|
-
b = b.next
|
251
|
-
end
|
252
|
-
end
|
253
|
-
if !b
|
254
|
-
result.tail.next = a
|
255
|
-
result.tail = self.tail
|
256
|
-
elsif !a
|
257
|
-
result.tail.next = b
|
258
|
-
result.tail = other.tail
|
259
|
-
end
|
260
|
-
result
|
372
|
+
def valid_count?(count, index)
|
373
|
+
return true if count.nil?
|
374
|
+
!(count < 1 || count + index > size)
|
261
375
|
end
|
262
376
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
prev.next = nil
|
269
|
-
while elem
|
270
|
-
nxt = elem.next
|
271
|
-
elem.next = prev
|
272
|
-
prev = elem
|
273
|
-
elem = nxt
|
377
|
+
def replace_head(el, list, count)
|
378
|
+
count.times do
|
379
|
+
temp = el.next
|
380
|
+
remove(el)
|
381
|
+
el = temp
|
274
382
|
end
|
275
|
-
|
276
|
-
@
|
277
|
-
self
|
383
|
+
list.concat self
|
384
|
+
@size = list.size
|
385
|
+
self.head = list.head
|
278
386
|
end
|
279
387
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
388
|
+
def replace_tail(el, list, count)
|
389
|
+
count.times do
|
390
|
+
temp = el.next
|
391
|
+
remove(el)
|
392
|
+
el = temp
|
393
|
+
end
|
394
|
+
concat list
|
284
395
|
end
|
285
396
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
397
|
+
def replace_inside(el, list, count)
|
398
|
+
first = el
|
399
|
+
last = find_last_element(el, count)
|
400
|
+
if last.tail?
|
401
|
+
self.tail = list.tail
|
402
|
+
else
|
403
|
+
nxt = last.next
|
404
|
+
nxt.prev = list.tail
|
405
|
+
list.tail.next = nxt
|
406
|
+
last.next = nil
|
292
407
|
end
|
408
|
+
prev = first.prev
|
409
|
+
list.head.prev = prev
|
410
|
+
prev.next = list.head
|
411
|
+
first.prev = nil
|
412
|
+
@size = @size - count + list.size
|
293
413
|
end
|
294
414
|
|
415
|
+
def find_last_element(el, count)
|
416
|
+
last = el
|
417
|
+
(count - 1).times do
|
418
|
+
temp = last.next if last.next
|
419
|
+
last = temp
|
420
|
+
end
|
421
|
+
last
|
422
|
+
end
|
295
423
|
end
|
296
|
-
|
297
|
-
class ListError < StandardError
|
298
|
-
end
|
299
|
-
|
300
424
|
end
|