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.
@@ -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
- puts "\nšŸ“š Coming soon: Two-way traversal, prev and next pointers"
7
- puts "Topics: Insertion, deletion, reverse traversal"
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
- puts "\nšŸ“š Coming soon: Graph representations"
7
- puts "Topics: Adjacency matrix, adjacency list, directed vs undirected"
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