ds 0.0.4 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|