dsa_visualizer 0.1.1 ā 0.1.2
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 +4 -4
- data/lib/dsa_visualizer/algorithms/graph_algorithms.rb +322 -6
- data/lib/dsa_visualizer/algorithms/sorting.rb +106 -2
- data/lib/dsa_visualizer/data_structures/bst.rb +303 -2
- data/lib/dsa_visualizer/data_structures/deque.rb +208 -2
- data/lib/dsa_visualizer/data_structures/doubly_linked_list.rb +255 -2
- data/lib/dsa_visualizer/data_structures/graph.rb +191 -2
- data/lib/dsa_visualizer/data_structures/heap.rb +327 -4
- data/lib/dsa_visualizer/data_structures/priority_queue.rb +214 -2
- data/lib/dsa_visualizer/data_structures/trie.rb +261 -2
- data/lib/dsa_visualizer/data_structures/union_find.rb +207 -2
- metadata +5 -5
|
@@ -1,10 +1,263 @@
|
|
|
1
1
|
module DSAVisualizer
|
|
2
2
|
module DataStructures
|
|
3
3
|
class DoublyLinkedList
|
|
4
|
+
class Node
|
|
5
|
+
attr_accessor :data, :prev, :next
|
|
6
|
+
|
|
7
|
+
def initialize(data)
|
|
8
|
+
@data = data
|
|
9
|
+
@prev = nil
|
|
10
|
+
@next = nil
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
4
14
|
def self.learn
|
|
5
15
|
Visualizer.print_header("DOUBLY LINKED LIST - Bidirectional Navigation")
|
|
6
|
-
|
|
7
|
-
puts "
|
|
16
|
+
|
|
17
|
+
puts "\nš CONCEPT:"
|
|
18
|
+
puts "A Doubly Linked List has nodes with two pointers:"
|
|
19
|
+
puts "⢠next: Points to the next node"
|
|
20
|
+
puts "⢠prev: Points to the previous node"
|
|
21
|
+
puts "⢠Allows bidirectional traversal"
|
|
22
|
+
puts "⢠More memory overhead but more flexible than singly linked list"
|
|
23
|
+
|
|
24
|
+
puts "\nā±ļø TIME COMPLEXITY:"
|
|
25
|
+
puts "⢠Access: O(n)"
|
|
26
|
+
puts "⢠Search: O(n)"
|
|
27
|
+
puts "⢠Insert at head/tail: O(1)"
|
|
28
|
+
puts "⢠Delete at head/tail: O(1)"
|
|
29
|
+
puts "⢠Insert/Delete at position: O(n)"
|
|
30
|
+
|
|
31
|
+
puts "\nš¾ SPACE COMPLEXITY: O(n) - extra pointer per node"
|
|
32
|
+
|
|
33
|
+
demonstrate_dll
|
|
34
|
+
demonstrate_operations
|
|
35
|
+
show_ruby_vs_cpp
|
|
36
|
+
show_practice_problems
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.demonstrate_dll
|
|
40
|
+
puts "\n" + "="*60
|
|
41
|
+
puts "DEMONSTRATION: Building a Doubly Linked List"
|
|
42
|
+
puts "="*60
|
|
43
|
+
|
|
44
|
+
dll = DLLImplementation.new
|
|
45
|
+
|
|
46
|
+
puts "\nInserting at tail: 10, 20, 30"
|
|
47
|
+
dll.insert_tail(10)
|
|
48
|
+
dll.insert_tail(20)
|
|
49
|
+
dll.insert_tail(30)
|
|
50
|
+
dll.display
|
|
51
|
+
|
|
52
|
+
puts "\nInserting at head: 5"
|
|
53
|
+
dll.insert_head(5)
|
|
54
|
+
dll.display
|
|
55
|
+
|
|
56
|
+
puts "\nš Structure:"
|
|
57
|
+
puts "nil ā [5] ā [10] ā [20] ā [30] ā nil"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.demonstrate_operations
|
|
61
|
+
puts "\n" + "="*60
|
|
62
|
+
puts "DOUBLY LINKED LIST OPERATIONS"
|
|
63
|
+
puts "="*60
|
|
64
|
+
|
|
65
|
+
dll = DLLImplementation.new
|
|
66
|
+
[10, 20, 30, 40].each { |v| dll.insert_tail(v) }
|
|
67
|
+
|
|
68
|
+
puts "\n1ļøā£ FORWARD TRAVERSAL:"
|
|
69
|
+
dll.display
|
|
70
|
+
|
|
71
|
+
puts "\n2ļøā£ BACKWARD TRAVERSAL:"
|
|
72
|
+
dll.display_reverse
|
|
73
|
+
|
|
74
|
+
puts "\n3ļøā£ DELETE FROM HEAD:"
|
|
75
|
+
dll.delete_head
|
|
76
|
+
dll.display
|
|
77
|
+
|
|
78
|
+
puts "\n4ļøā£ DELETE FROM TAIL:"
|
|
79
|
+
dll.delete_tail
|
|
80
|
+
dll.display
|
|
81
|
+
|
|
82
|
+
puts "\n5ļøā£ SEARCH:"
|
|
83
|
+
puts "Search 30: #{dll.search(30) ? 'ā Found' : 'ā Not found'}"
|
|
84
|
+
puts "Search 99: #{dll.search(99) ? 'ā Found' : 'ā Not found'}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.show_ruby_vs_cpp
|
|
88
|
+
puts "\n" + "="*60
|
|
89
|
+
puts "RUBY vs C++ IMPLEMENTATION"
|
|
90
|
+
puts "="*60
|
|
91
|
+
|
|
92
|
+
puts "\nš“ RUBY:"
|
|
93
|
+
puts <<~RUBY
|
|
94
|
+
class Node
|
|
95
|
+
attr_accessor :data, :prev, :next
|
|
96
|
+
def initialize(data)
|
|
97
|
+
@data = data
|
|
98
|
+
@prev = @next = nil
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class DoublyLinkedList
|
|
103
|
+
def insert_tail(data)
|
|
104
|
+
new_node = Node.new(data)
|
|
105
|
+
if @head.nil?
|
|
106
|
+
@head = @tail = new_node
|
|
107
|
+
else
|
|
108
|
+
@tail.next = new_node
|
|
109
|
+
new_node.prev = @tail
|
|
110
|
+
@tail = new_node
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def delete_head
|
|
115
|
+
return if @head.nil?
|
|
116
|
+
@head = @head.next
|
|
117
|
+
@head.prev = nil if @head
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
RUBY
|
|
121
|
+
|
|
122
|
+
puts "\nšµ C++:"
|
|
123
|
+
puts <<~CPP
|
|
124
|
+
struct Node {
|
|
125
|
+
int data;
|
|
126
|
+
Node* prev;
|
|
127
|
+
Node* next;
|
|
128
|
+
Node(int val) : data(val), prev(nullptr), next(nullptr) {}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
class DoublyLinkedList {
|
|
132
|
+
Node* head;
|
|
133
|
+
Node* tail;
|
|
134
|
+
public:
|
|
135
|
+
void insertTail(int data) {
|
|
136
|
+
Node* newNode = new Node(data);
|
|
137
|
+
if (head == nullptr) {
|
|
138
|
+
head = tail = newNode;
|
|
139
|
+
} else {
|
|
140
|
+
tail->next = newNode;
|
|
141
|
+
newNode->prev = tail;
|
|
142
|
+
tail = newNode;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
void deleteHead() {
|
|
147
|
+
if (head == nullptr) return;
|
|
148
|
+
head = head->next;
|
|
149
|
+
if (head) head->prev = nullptr;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
CPP
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def self.show_practice_problems
|
|
156
|
+
puts "\n" + "="*60
|
|
157
|
+
puts "PRACTICE PROBLEMS"
|
|
158
|
+
puts "="*60
|
|
159
|
+
|
|
160
|
+
problems = [
|
|
161
|
+
"1. Reverse a doubly linked list",
|
|
162
|
+
"2. Find pairs with given sum in sorted DLL",
|
|
163
|
+
"3. Remove duplicates from sorted DLL",
|
|
164
|
+
"4. Convert binary tree to DLL (in-order)",
|
|
165
|
+
"5. Clone a DLL with random pointers",
|
|
166
|
+
"6. Find triplets with given sum",
|
|
167
|
+
"7. Rotate DLL by N nodes",
|
|
168
|
+
"8. Implement LRU cache using DLL"
|
|
169
|
+
]
|
|
170
|
+
|
|
171
|
+
problems.each { |p| puts p }
|
|
172
|
+
|
|
173
|
+
puts "\nš” TIP: DLL allows O(1) deletion when node reference is given!"
|
|
174
|
+
puts "š” TIP: Perfect for implementing LRU cache and browser history"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
class DLLImplementation
|
|
178
|
+
attr_reader :head, :tail
|
|
179
|
+
|
|
180
|
+
def initialize
|
|
181
|
+
@head = nil
|
|
182
|
+
@tail = nil
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def insert_head(data)
|
|
186
|
+
new_node = Node.new(data)
|
|
187
|
+
if @head.nil?
|
|
188
|
+
@head = @tail = new_node
|
|
189
|
+
else
|
|
190
|
+
new_node.next = @head
|
|
191
|
+
@head.prev = new_node
|
|
192
|
+
@head = new_node
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def insert_tail(data)
|
|
197
|
+
new_node = Node.new(data)
|
|
198
|
+
if @head.nil?
|
|
199
|
+
@head = @tail = new_node
|
|
200
|
+
else
|
|
201
|
+
@tail.next = new_node
|
|
202
|
+
new_node.prev = @tail
|
|
203
|
+
@tail = new_node
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def delete_head
|
|
208
|
+
return if @head.nil?
|
|
209
|
+
|
|
210
|
+
if @head == @tail
|
|
211
|
+
@head = @tail = nil
|
|
212
|
+
else
|
|
213
|
+
@head = @head.next
|
|
214
|
+
@head.prev = nil
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def delete_tail
|
|
219
|
+
return if @tail.nil?
|
|
220
|
+
|
|
221
|
+
if @head == @tail
|
|
222
|
+
@head = @tail = nil
|
|
223
|
+
else
|
|
224
|
+
@tail = @tail.prev
|
|
225
|
+
@tail.next = nil
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def search(data)
|
|
230
|
+
current = @head
|
|
231
|
+
while current
|
|
232
|
+
return true if current.data == data
|
|
233
|
+
current = current.next
|
|
234
|
+
end
|
|
235
|
+
false
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def display
|
|
239
|
+
return puts "List is empty" if @head.nil?
|
|
240
|
+
|
|
241
|
+
current = @head
|
|
242
|
+
result = []
|
|
243
|
+
while current
|
|
244
|
+
result << current.data
|
|
245
|
+
current = current.next
|
|
246
|
+
end
|
|
247
|
+
puts "Forward: #{result.join(' ā ')}"
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def display_reverse
|
|
251
|
+
return puts "List is empty" if @tail.nil?
|
|
252
|
+
|
|
253
|
+
current = @tail
|
|
254
|
+
result = []
|
|
255
|
+
while current
|
|
256
|
+
result << current.data
|
|
257
|
+
current = current.prev
|
|
258
|
+
end
|
|
259
|
+
puts "Backward: #{result.join(' ā ')}"
|
|
260
|
+
end
|
|
8
261
|
end
|
|
9
262
|
end
|
|
10
263
|
end
|
|
@@ -3,8 +3,197 @@ module DSAVisualizer
|
|
|
3
3
|
class Graph
|
|
4
4
|
def self.learn
|
|
5
5
|
Visualizer.print_header("GRAPH - Vertices and Edges")
|
|
6
|
-
|
|
7
|
-
puts "
|
|
6
|
+
|
|
7
|
+
puts "\nš CONCEPT:"
|
|
8
|
+
puts "A Graph is a collection of vertices (nodes) connected by edges:"
|
|
9
|
+
puts "⢠Directed: Edges have direction (A ā B)"
|
|
10
|
+
puts "⢠Undirected: Edges are bidirectional (A ā B)"
|
|
11
|
+
puts "⢠Weighted: Edges have associated costs"
|
|
12
|
+
puts "⢠Unweighted: All edges have equal weight"
|
|
13
|
+
|
|
14
|
+
puts "\nā±ļø TIME COMPLEXITY (Adjacency List):"
|
|
15
|
+
puts "⢠Add vertex: O(1)"
|
|
16
|
+
puts "⢠Add edge: O(1)"
|
|
17
|
+
puts "⢠Remove vertex: O(V + E)"
|
|
18
|
+
puts "⢠Remove edge: O(E)"
|
|
19
|
+
puts "⢠Check if edge exists: O(V)"
|
|
20
|
+
|
|
21
|
+
puts "\nš¾ SPACE COMPLEXITY:"
|
|
22
|
+
puts "⢠Adjacency List: O(V + E)"
|
|
23
|
+
puts "⢠Adjacency Matrix: O(V²)"
|
|
24
|
+
|
|
25
|
+
demonstrate_graph
|
|
26
|
+
demonstrate_representations
|
|
27
|
+
show_ruby_vs_cpp
|
|
28
|
+
show_practice_problems
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.demonstrate_graph
|
|
32
|
+
puts "\n" + "="*60
|
|
33
|
+
puts "DEMONSTRATION: Building a Graph"
|
|
34
|
+
puts "="*60
|
|
35
|
+
|
|
36
|
+
graph = GraphImplementation.new
|
|
37
|
+
|
|
38
|
+
puts "\nAdding vertices: A, B, C, D, E"
|
|
39
|
+
['A', 'B', 'C', 'D', 'E'].each { |v| graph.add_vertex(v) }
|
|
40
|
+
|
|
41
|
+
puts "\nAdding edges:"
|
|
42
|
+
edges = [['A', 'B'], ['A', 'C'], ['B', 'D'], ['C', 'D'], ['D', 'E']]
|
|
43
|
+
edges.each do |from, to|
|
|
44
|
+
graph.add_edge(from, to)
|
|
45
|
+
puts "#{from} ā #{to}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
puts "\nš Graph Structure:"
|
|
49
|
+
puts " A"
|
|
50
|
+
puts " / \\"
|
|
51
|
+
puts " B C"
|
|
52
|
+
puts " \\ /"
|
|
53
|
+
puts " D"
|
|
54
|
+
puts " |"
|
|
55
|
+
puts " E"
|
|
56
|
+
|
|
57
|
+
graph.display
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.demonstrate_representations
|
|
61
|
+
puts "\n" + "="*60
|
|
62
|
+
puts "GRAPH REPRESENTATIONS"
|
|
63
|
+
puts "="*60
|
|
64
|
+
|
|
65
|
+
puts "\n1ļøā£ ADJACENCY LIST:"
|
|
66
|
+
puts "Space efficient for sparse graphs"
|
|
67
|
+
puts "A: [B, C]"
|
|
68
|
+
puts "B: [D]"
|
|
69
|
+
puts "C: [D]"
|
|
70
|
+
puts "D: [E]"
|
|
71
|
+
puts "E: []"
|
|
72
|
+
|
|
73
|
+
puts "\n2ļøā£ ADJACENCY MATRIX:"
|
|
74
|
+
puts "Fast edge lookup, more space"
|
|
75
|
+
puts " A B C D E"
|
|
76
|
+
puts "A [[0,1,1,0,0],"
|
|
77
|
+
puts "B [0,0,0,1,0],"
|
|
78
|
+
puts "C [0,0,0,1,0],"
|
|
79
|
+
puts "D [0,0,0,0,1],"
|
|
80
|
+
puts "E [0,0,0,0,0]]"
|
|
81
|
+
|
|
82
|
+
puts "\n3ļøā£ EDGE LIST:"
|
|
83
|
+
puts "Simple but less efficient"
|
|
84
|
+
puts "[(A,B), (A,C), (B,D), (C,D), (D,E)]"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.show_ruby_vs_cpp
|
|
88
|
+
puts "\n" + "="*60
|
|
89
|
+
puts "RUBY vs C++ IMPLEMENTATION"
|
|
90
|
+
puts "="*60
|
|
91
|
+
|
|
92
|
+
puts "\nš“ RUBY (Adjacency List):"
|
|
93
|
+
puts <<~RUBY
|
|
94
|
+
class Graph
|
|
95
|
+
def initialize
|
|
96
|
+
@adj_list = Hash.new { |h, k| h[k] = [] }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def add_vertex(vertex)
|
|
100
|
+
@adj_list[vertex] ||= []
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def add_edge(from, to, directed = true)
|
|
104
|
+
@adj_list[from] << to
|
|
105
|
+
@adj_list[to] << from unless directed
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def neighbors(vertex)
|
|
109
|
+
@adj_list[vertex]
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
RUBY
|
|
113
|
+
|
|
114
|
+
puts "\nšµ C++ (Adjacency List):"
|
|
115
|
+
puts <<~CPP
|
|
116
|
+
class Graph {
|
|
117
|
+
unordered_map<int, vector<int>> adjList;
|
|
118
|
+
public:
|
|
119
|
+
void addVertex(int vertex) {
|
|
120
|
+
if (adjList.find(vertex) == adjList.end())
|
|
121
|
+
adjList[vertex] = vector<int>();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
void addEdge(int from, int to, bool directed = true) {
|
|
125
|
+
adjList[from].push_back(to);
|
|
126
|
+
if (!directed)
|
|
127
|
+
adjList[to].push_back(from);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
vector<int> neighbors(int vertex) {
|
|
131
|
+
return adjList[vertex];
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
CPP
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def self.show_practice_problems
|
|
138
|
+
puts "\n" + "="*60
|
|
139
|
+
puts "PRACTICE PROBLEMS"
|
|
140
|
+
puts "="*60
|
|
141
|
+
|
|
142
|
+
problems = [
|
|
143
|
+
"1. Clone a graph",
|
|
144
|
+
"2. Number of islands",
|
|
145
|
+
"3. Course schedule (cycle detection)",
|
|
146
|
+
"4. Word ladder",
|
|
147
|
+
"5. Network delay time",
|
|
148
|
+
"6. Minimum spanning tree",
|
|
149
|
+
"7. Shortest path in binary matrix",
|
|
150
|
+
"8. Critical connections in network"
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
problems.each { |p| puts p }
|
|
154
|
+
|
|
155
|
+
puts "\nš” TIP: Use adjacency list for sparse graphs!"
|
|
156
|
+
puts "š” TIP: Use adjacency matrix when you need O(1) edge lookup"
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
class GraphImplementation
|
|
160
|
+
def initialize(directed = true)
|
|
161
|
+
@adj_list = Hash.new { |h, k| h[k] = [] }
|
|
162
|
+
@directed = directed
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def add_vertex(vertex)
|
|
166
|
+
@adj_list[vertex] ||= []
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def add_edge(from, to)
|
|
170
|
+
@adj_list[from] << to
|
|
171
|
+
@adj_list[to] << from unless @directed
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def remove_edge(from, to)
|
|
175
|
+
@adj_list[from].delete(to)
|
|
176
|
+
@adj_list[to].delete(from) unless @directed
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def neighbors(vertex)
|
|
180
|
+
@adj_list[vertex]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def has_edge?(from, to)
|
|
184
|
+
@adj_list[from].include?(to)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def vertices
|
|
188
|
+
@adj_list.keys
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def display
|
|
192
|
+
puts "\nAdjacency List:"
|
|
193
|
+
@adj_list.each do |vertex, neighbors|
|
|
194
|
+
puts "#{vertex}: #{neighbors.join(', ')}"
|
|
195
|
+
end
|
|
196
|
+
end
|
|
8
197
|
end
|
|
9
198
|
end
|
|
10
199
|
end
|