dsa_visualizer 0.1.0
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/LICENSE.txt +21 -0
- data/README.md +323 -0
- data/USAGE.md +359 -0
- data/bin/dsa_visualizer +5 -0
- data/lib/dsa_visualizer/algorithms/dynamic_programming.rb +23 -0
- data/lib/dsa_visualizer/algorithms/graph_algorithms.rb +23 -0
- data/lib/dsa_visualizer/algorithms/greedy.rb +11 -0
- data/lib/dsa_visualizer/algorithms/searching.rb +78 -0
- data/lib/dsa_visualizer/algorithms/sorting.rb +77 -0
- data/lib/dsa_visualizer/algorithms/string_algorithms.rb +11 -0
- data/lib/dsa_visualizer/cli.rb +281 -0
- data/lib/dsa_visualizer/comparator.rb +57 -0
- data/lib/dsa_visualizer/data_structures/array.rb +109 -0
- data/lib/dsa_visualizer/data_structures/binary_tree.rb +104 -0
- data/lib/dsa_visualizer/data_structures/bst.rb +11 -0
- data/lib/dsa_visualizer/data_structures/deque.rb +11 -0
- data/lib/dsa_visualizer/data_structures/doubly_linked_list.rb +11 -0
- data/lib/dsa_visualizer/data_structures/graph.rb +11 -0
- data/lib/dsa_visualizer/data_structures/hash_table.rb +61 -0
- data/lib/dsa_visualizer/data_structures/heap.rb +17 -0
- data/lib/dsa_visualizer/data_structures/linked_list.rb +197 -0
- data/lib/dsa_visualizer/data_structures/priority_queue.rb +11 -0
- data/lib/dsa_visualizer/data_structures/queue.rb +110 -0
- data/lib/dsa_visualizer/data_structures/stack.rb +207 -0
- data/lib/dsa_visualizer/data_structures/string.rb +11 -0
- data/lib/dsa_visualizer/data_structures/trie.rb +11 -0
- data/lib/dsa_visualizer/data_structures/union_find.rb +11 -0
- data/lib/dsa_visualizer/fundamentals/complexity.rb +264 -0
- data/lib/dsa_visualizer/fundamentals/memory.rb +285 -0
- data/lib/dsa_visualizer/fundamentals/pointers.rb +311 -0
- data/lib/dsa_visualizer/fundamentals/recursion.rb +63 -0
- data/lib/dsa_visualizer/memory_tracker.rb +49 -0
- data/lib/dsa_visualizer/notes_manager.rb +85 -0
- data/lib/dsa_visualizer/version.rb +3 -0
- data/lib/dsa_visualizer/visualizer.rb +58 -0
- data/lib/dsa_visualizer.rb +114 -0
- metadata +157 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module DSAVisualizer
|
|
2
|
+
module Algorithms
|
|
3
|
+
class DynamicProgramming
|
|
4
|
+
def self.learn_intro
|
|
5
|
+
Visualizer.print_header("DYNAMIC PROGRAMMING - Optimization Technique")
|
|
6
|
+
puts "\nš Coming soon: Memoization and tabulation"
|
|
7
|
+
puts "Topics: Overlapping subproblems, optimal substructure"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.learn_fibonacci
|
|
11
|
+
Visualizer.print_header("FIBONACCI - DP Example")
|
|
12
|
+
puts "\nš Coming soon: From recursion to DP"
|
|
13
|
+
puts "Topics: Top-down vs bottom-up, space optimization"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.learn_knapsack
|
|
17
|
+
Visualizer.print_header("0/1 KNAPSACK PROBLEM")
|
|
18
|
+
puts "\nš Coming soon: Classic DP problem"
|
|
19
|
+
puts "Topics: 2D DP table, backtracking solution"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module DSAVisualizer
|
|
2
|
+
module Algorithms
|
|
3
|
+
class GraphAlgorithms
|
|
4
|
+
def self.learn_bfs
|
|
5
|
+
Visualizer.print_header("BREADTH-FIRST SEARCH (BFS)")
|
|
6
|
+
puts "\nš Coming soon: Level-order graph traversal"
|
|
7
|
+
puts "Topics: Queue-based, shortest path in unweighted graph"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.learn_dfs
|
|
11
|
+
Visualizer.print_header("DEPTH-FIRST SEARCH (DFS)")
|
|
12
|
+
puts "\nš Coming soon: Deep exploration"
|
|
13
|
+
puts "Topics: Stack/recursion-based, cycle detection, topological sort"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.learn_dijkstra
|
|
17
|
+
Visualizer.print_header("DIJKSTRA'S ALGORITHM")
|
|
18
|
+
puts "\nš Coming soon: Shortest path in weighted graph"
|
|
19
|
+
puts "Topics: Priority queue, greedy approach, non-negative weights"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module DSAVisualizer
|
|
2
|
+
module Algorithms
|
|
3
|
+
class Greedy
|
|
4
|
+
def self.learn_intro
|
|
5
|
+
Visualizer.print_header("GREEDY ALGORITHMS")
|
|
6
|
+
puts "\nš Coming soon: Making locally optimal choices"
|
|
7
|
+
puts "Topics: Activity selection, Huffman coding, coin change"
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module DSAVisualizer
|
|
2
|
+
module Algorithms
|
|
3
|
+
class Searching
|
|
4
|
+
def self.learn_linear
|
|
5
|
+
demo
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.learn_binary
|
|
9
|
+
demo
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.demo
|
|
13
|
+
Visualizer.print_header("SEARCHING ALGORITHMS - Core Level Visualization")
|
|
14
|
+
|
|
15
|
+
Visualizer.print_section("1. Linear Search")
|
|
16
|
+
|
|
17
|
+
ruby_code = <<~RUBY
|
|
18
|
+
def linear_search(arr, target)
|
|
19
|
+
arr.each_with_index do |val, idx|
|
|
20
|
+
return idx if val == target
|
|
21
|
+
end
|
|
22
|
+
-1
|
|
23
|
+
end
|
|
24
|
+
RUBY
|
|
25
|
+
|
|
26
|
+
cpp_code = <<~CPP
|
|
27
|
+
int linearSearch(int arr[], int n, int target) {
|
|
28
|
+
for(int i = 0; i < n; i++) {
|
|
29
|
+
if(arr[i] == target)
|
|
30
|
+
return i;
|
|
31
|
+
}
|
|
32
|
+
return -1;
|
|
33
|
+
}
|
|
34
|
+
CPP
|
|
35
|
+
|
|
36
|
+
explanation = "Sequential scan through array. Time: O(n), Space: O(1). Works on unsorted arrays."
|
|
37
|
+
|
|
38
|
+
Visualizer.print_comparison(ruby_code, cpp_code, explanation)
|
|
39
|
+
|
|
40
|
+
Visualizer.print_section("2. Binary Search")
|
|
41
|
+
|
|
42
|
+
ruby_code2 = <<~RUBY
|
|
43
|
+
def binary_search(arr, target)
|
|
44
|
+
left, right = 0, arr.length - 1
|
|
45
|
+
while left <= right
|
|
46
|
+
mid = (left + right) / 2
|
|
47
|
+
return mid if arr[mid] == target
|
|
48
|
+
arr[mid] < target ? left = mid + 1 : right = mid - 1
|
|
49
|
+
end
|
|
50
|
+
-1
|
|
51
|
+
end
|
|
52
|
+
RUBY
|
|
53
|
+
|
|
54
|
+
cpp_code2 = <<~CPP
|
|
55
|
+
int binarySearch(int arr[], int n, int target) {
|
|
56
|
+
int left = 0, right = n - 1;
|
|
57
|
+
while(left <= right) {
|
|
58
|
+
int mid = left + (right - left) / 2;
|
|
59
|
+
if(arr[mid] == target) return mid;
|
|
60
|
+
if(arr[mid] < target) left = mid + 1;
|
|
61
|
+
else right = mid - 1;
|
|
62
|
+
}
|
|
63
|
+
return -1;
|
|
64
|
+
}
|
|
65
|
+
CPP
|
|
66
|
+
|
|
67
|
+
explanation2 = "Divide and conquer on sorted array. Time: O(log n), Space: O(1). Requires sorted input."
|
|
68
|
+
|
|
69
|
+
Visualizer.print_comparison(ruby_code2, cpp_code2, explanation2)
|
|
70
|
+
|
|
71
|
+
puts "\n\nšÆ Key Takeaways:".colorize(:green).bold
|
|
72
|
+
puts " 1. Linear: O(n) - works on any array"
|
|
73
|
+
puts " 2. Binary: O(log n) - requires sorted array"
|
|
74
|
+
puts " 3. Binary search eliminates half the search space each iteration"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module DSAVisualizer
|
|
2
|
+
module Algorithms
|
|
3
|
+
class Sorting
|
|
4
|
+
def self.learn_bubble
|
|
5
|
+
demo
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.learn_merge
|
|
9
|
+
puts "\nš Coming soon: Merge Sort - Divide and Conquer"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.learn_quick
|
|
13
|
+
puts "\nš Coming soon: Quick Sort - Partition-based"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.demo
|
|
17
|
+
Visualizer.print_header("SORTING ALGORITHMS - Core Level Visualization")
|
|
18
|
+
|
|
19
|
+
Visualizer.print_section("1. Bubble Sort")
|
|
20
|
+
|
|
21
|
+
ruby_code = <<~RUBY
|
|
22
|
+
def bubble_sort(arr)
|
|
23
|
+
n = arr.length
|
|
24
|
+
(n-1).times do |i|
|
|
25
|
+
(n-i-1).times do |j|
|
|
26
|
+
if arr[j] > arr[j+1]
|
|
27
|
+
arr[j], arr[j+1] = arr[j+1], arr[j]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
arr
|
|
32
|
+
end
|
|
33
|
+
RUBY
|
|
34
|
+
|
|
35
|
+
cpp_code = <<~CPP
|
|
36
|
+
void bubbleSort(int arr[], int n) {
|
|
37
|
+
for(int i = 0; i < n-1; i++) {
|
|
38
|
+
for(int j = 0; j < n-i-1; j++) {
|
|
39
|
+
if(arr[j] > arr[j+1]) {
|
|
40
|
+
std::swap(arr[j], arr[j+1]);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
CPP
|
|
46
|
+
|
|
47
|
+
explanation = "Both implementations identical in logic. Ruby's swap is cleaner syntax. Time: O(n²), Space: O(1). Stable sort."
|
|
48
|
+
|
|
49
|
+
Visualizer.print_comparison(ruby_code, cpp_code, explanation)
|
|
50
|
+
|
|
51
|
+
arr = [64, 34, 25, 12, 22]
|
|
52
|
+
puts "\nOriginal: #{arr.inspect}"
|
|
53
|
+
|
|
54
|
+
# Simulate one pass
|
|
55
|
+
puts "\nAfter first pass:"
|
|
56
|
+
n = arr.length
|
|
57
|
+
(n-1).times do |j|
|
|
58
|
+
if arr[j] > arr[j+1]
|
|
59
|
+
arr[j], arr[j+1] = arr[j+1], arr[j]
|
|
60
|
+
puts " Swapped #{arr[j+1]} and #{arr[j]}: #{arr.inspect}"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
Visualizer.print_section("2. Quick Sort")
|
|
65
|
+
puts "\nDivide and conquer algorithm"
|
|
66
|
+
puts "Average: O(n log n), Worst: O(n²)"
|
|
67
|
+
puts "In-place, not stable"
|
|
68
|
+
|
|
69
|
+
puts "\n\nšÆ Sorting Comparison:".colorize(:green).bold
|
|
70
|
+
puts " Bubble Sort: O(n²) - simple, slow"
|
|
71
|
+
puts " Quick Sort: O(n log n) - fast, in-place"
|
|
72
|
+
puts " Merge Sort: O(n log n) - stable, needs extra space"
|
|
73
|
+
puts " Heap Sort: O(n log n) - in-place, not stable"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module DSAVisualizer
|
|
2
|
+
module Algorithms
|
|
3
|
+
class StringAlgorithms
|
|
4
|
+
def self.learn_kmp
|
|
5
|
+
Visualizer.print_header("KMP PATTERN MATCHING")
|
|
6
|
+
puts "\nš Coming soon: Efficient string search"
|
|
7
|
+
puts "Topics: LPS array, O(n+m) complexity"
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
require 'io/console'
|
|
2
|
+
|
|
3
|
+
module DSAVisualizer
|
|
4
|
+
class CLI
|
|
5
|
+
CURRICULUM = {
|
|
6
|
+
"1" => {
|
|
7
|
+
title: "Fundamentals",
|
|
8
|
+
topics: {
|
|
9
|
+
"1.1" => { name: "Time & Space Complexity", key: :complexity_basics },
|
|
10
|
+
"1.2" => { name: "Memory Management", key: :memory_basics },
|
|
11
|
+
"1.3" => { name: "Pointers & References", key: :pointers_basics },
|
|
12
|
+
"1.4" => { name: "Recursion Basics", key: :recursion_basics }
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"2" => {
|
|
16
|
+
title: "Basic Data Structures",
|
|
17
|
+
topics: {
|
|
18
|
+
"2.1" => { name: "Arrays", key: :array },
|
|
19
|
+
"2.2" => { name: "Strings", key: :string },
|
|
20
|
+
"2.3" => { name: "Linked Lists", key: :linked_list },
|
|
21
|
+
"2.4" => { name: "Doubly Linked Lists", key: :doubly_linked_list },
|
|
22
|
+
"2.5" => { name: "Circular Linked Lists", key: :circular_linked_list }
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"3" => {
|
|
26
|
+
title: "Stack & Queue",
|
|
27
|
+
topics: {
|
|
28
|
+
"3.1" => { name: "Stack (Array-based)", key: :stack },
|
|
29
|
+
"3.2" => { name: "Stack (Linked List-based)", key: :stack_linked },
|
|
30
|
+
"3.3" => { name: "Queue (Array-based)", key: :queue },
|
|
31
|
+
"3.4" => { name: "Queue (Linked List-based)", key: :queue_linked },
|
|
32
|
+
"3.5" => { name: "Circular Queue", key: :circular_queue },
|
|
33
|
+
"3.6" => { name: "Deque", key: :deque },
|
|
34
|
+
"3.7" => { name: "Priority Queue", key: :priority_queue }
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"4" => {
|
|
38
|
+
title: "Hashing",
|
|
39
|
+
topics: {
|
|
40
|
+
"4.1" => { name: "Hash Functions", key: :hash_functions },
|
|
41
|
+
"4.2" => { name: "Hash Tables", key: :hash_table },
|
|
42
|
+
"4.3" => { name: "Collision Handling", key: :collision_handling },
|
|
43
|
+
"4.4" => { name: "Hash Maps & Sets", key: :hash_map_set }
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"5" => {
|
|
47
|
+
title: "Trees",
|
|
48
|
+
topics: {
|
|
49
|
+
"5.1" => { name: "Binary Trees", key: :binary_tree },
|
|
50
|
+
"5.2" => { name: "Binary Search Trees", key: :bst },
|
|
51
|
+
"5.3" => { name: "Tree Traversals", key: :tree_traversals },
|
|
52
|
+
"5.4" => { name: "AVL Trees", key: :avl_tree },
|
|
53
|
+
"5.5" => { name: "Red-Black Trees", key: :red_black_tree },
|
|
54
|
+
"5.6" => { name: "B-Trees", key: :b_tree },
|
|
55
|
+
"5.7" => { name: "Segment Trees", key: :segment_tree },
|
|
56
|
+
"5.8" => { name: "Fenwick Trees", key: :fenwick_tree },
|
|
57
|
+
"5.9" => { name: "Trie", key: :trie }
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"6" => {
|
|
61
|
+
title: "Heaps",
|
|
62
|
+
topics: {
|
|
63
|
+
"6.1" => { name: "Min Heap", key: :min_heap },
|
|
64
|
+
"6.2" => { name: "Max Heap", key: :max_heap },
|
|
65
|
+
"6.3" => { name: "Heap Operations", key: :heap_operations },
|
|
66
|
+
"6.4" => { name: "Heap Sort", key: :heap_sort }
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"7" => {
|
|
70
|
+
title: "Graphs",
|
|
71
|
+
topics: {
|
|
72
|
+
"7.1" => { name: "Graph Representations", key: :graph_representation },
|
|
73
|
+
"7.2" => { name: "BFS (Breadth-First Search)", key: :bfs },
|
|
74
|
+
"7.3" => { name: "DFS (Depth-First Search)", key: :dfs },
|
|
75
|
+
"7.4" => { name: "Topological Sort", key: :topological_sort },
|
|
76
|
+
"7.5" => { name: "Shortest Path (Dijkstra)", key: :dijkstra },
|
|
77
|
+
"7.6" => { name: "Shortest Path (Bellman-Ford)", key: :bellman_ford },
|
|
78
|
+
"7.7" => { name: "Minimum Spanning Tree (Kruskal)", key: :kruskal },
|
|
79
|
+
"7.8" => { name: "Minimum Spanning Tree (Prim)", key: :prim },
|
|
80
|
+
"7.9" => { name: "Floyd-Warshall", key: :floyd_warshall }
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"8" => {
|
|
84
|
+
title: "Sorting Algorithms",
|
|
85
|
+
topics: {
|
|
86
|
+
"8.1" => { name: "Bubble Sort", key: :bubble_sort },
|
|
87
|
+
"8.2" => { name: "Selection Sort", key: :selection_sort },
|
|
88
|
+
"8.3" => { name: "Insertion Sort", key: :insertion_sort },
|
|
89
|
+
"8.4" => { name: "Merge Sort", key: :merge_sort },
|
|
90
|
+
"8.5" => { name: "Quick Sort", key: :quick_sort },
|
|
91
|
+
"8.6" => { name: "Heap Sort", key: :heap_sort },
|
|
92
|
+
"8.7" => { name: "Counting Sort", key: :counting_sort },
|
|
93
|
+
"8.8" => { name: "Radix Sort", key: :radix_sort },
|
|
94
|
+
"8.9" => { name: "Bucket Sort", key: :bucket_sort }
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"9" => {
|
|
98
|
+
title: "Searching Algorithms",
|
|
99
|
+
topics: {
|
|
100
|
+
"9.1" => { name: "Linear Search", key: :linear_search },
|
|
101
|
+
"9.2" => { name: "Binary Search", key: :binary_search },
|
|
102
|
+
"9.3" => { name: "Ternary Search", key: :ternary_search },
|
|
103
|
+
"9.4" => { name: "Jump Search", key: :jump_search },
|
|
104
|
+
"9.5" => { name: "Interpolation Search", key: :interpolation_search }
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"10" => {
|
|
108
|
+
title: "Advanced Algorithms",
|
|
109
|
+
topics: {
|
|
110
|
+
"10.1" => { name: "Dynamic Programming Intro", key: :dp_intro },
|
|
111
|
+
"10.2" => { name: "Fibonacci (DP)", key: :dp_fibonacci },
|
|
112
|
+
"10.3" => { name: "Knapsack Problem", key: :knapsack },
|
|
113
|
+
"10.4" => { name: "Longest Common Subsequence", key: :lcs },
|
|
114
|
+
"10.5" => { name: "Matrix Chain Multiplication", key: :matrix_chain },
|
|
115
|
+
"10.6" => { name: "Greedy Algorithms", key: :greedy_intro },
|
|
116
|
+
"10.7" => { name: "Backtracking", key: :backtracking },
|
|
117
|
+
"10.8" => { name: "Divide and Conquer", key: :divide_conquer }
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"11" => {
|
|
121
|
+
title: "String Algorithms",
|
|
122
|
+
topics: {
|
|
123
|
+
"11.1" => { name: "Pattern Matching (Naive)", key: :pattern_naive },
|
|
124
|
+
"11.2" => { name: "KMP Algorithm", key: :kmp },
|
|
125
|
+
"11.3" => { name: "Rabin-Karp", key: :rabin_karp },
|
|
126
|
+
"11.4" => { name: "Z Algorithm", key: :z_algorithm }
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"12" => {
|
|
130
|
+
title: "Advanced Data Structures",
|
|
131
|
+
topics: {
|
|
132
|
+
"12.1" => { name: "Disjoint Set (Union-Find)", key: :union_find },
|
|
133
|
+
"12.2" => { name: "Suffix Array", key: :suffix_array },
|
|
134
|
+
"12.3" => { name: "Suffix Tree", key: :suffix_tree },
|
|
135
|
+
"12.4" => { name: "Skip List", key: :skip_list }
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
def self.start
|
|
141
|
+
new.run
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def run
|
|
145
|
+
loop do
|
|
146
|
+
clear_screen
|
|
147
|
+
print_header
|
|
148
|
+
print_menu
|
|
149
|
+
choice = get_input
|
|
150
|
+
|
|
151
|
+
break if choice == "0"
|
|
152
|
+
handle_choice(choice)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
puts "\nš Happy Learning! Keep practicing DSA!".colorize(:green)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
private
|
|
159
|
+
|
|
160
|
+
def clear_screen
|
|
161
|
+
system('cls') || system('clear')
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def print_header
|
|
165
|
+
puts "ā" + "ā" * 78 + "ā"
|
|
166
|
+
puts "ā" + " DSA VISUALIZER - Zero to Hero ".center(78).colorize(:cyan).bold + "ā"
|
|
167
|
+
puts "ā" + " Ruby vs C++ Implementation Comparison ".center(78).colorize(:yellow) + "ā"
|
|
168
|
+
puts "ā" + "ā" * 78 + "ā"
|
|
169
|
+
puts ""
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def print_menu
|
|
173
|
+
puts "š CURRICULUM".colorize(:green).bold
|
|
174
|
+
puts "ā" * 80
|
|
175
|
+
|
|
176
|
+
CURRICULUM.each do |section_num, section|
|
|
177
|
+
puts "\n#{section_num}. #{section[:title]}".colorize(:yellow).bold
|
|
178
|
+
section[:topics].each do |topic_num, topic|
|
|
179
|
+
puts " #{topic_num}. #{topic[:name]}"
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
puts "\n" + "ā" * 80
|
|
184
|
+
puts "Commands:".colorize(:cyan)
|
|
185
|
+
puts " ⢠Enter topic number (e.g., 2.1 for Arrays)"
|
|
186
|
+
puts " ⢠Type 'progress' to see your learning progress"
|
|
187
|
+
puts " ⢠Type 'notes' to view saved notes"
|
|
188
|
+
puts " ⢠Type '0' to exit"
|
|
189
|
+
puts "ā" * 80
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def get_input
|
|
193
|
+
print "\n⤠Enter your choice: ".colorize(:green)
|
|
194
|
+
gets.chomp.strip
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def handle_choice(choice)
|
|
198
|
+
case choice.downcase
|
|
199
|
+
when 'progress'
|
|
200
|
+
show_progress
|
|
201
|
+
when 'notes'
|
|
202
|
+
show_notes
|
|
203
|
+
else
|
|
204
|
+
run_topic(choice)
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def run_topic(topic_code)
|
|
209
|
+
section_num = topic_code.split('.').first
|
|
210
|
+
section = CURRICULUM[section_num]
|
|
211
|
+
|
|
212
|
+
unless section
|
|
213
|
+
puts "\nā Invalid section number!".colorize(:red)
|
|
214
|
+
wait_for_key
|
|
215
|
+
return
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
topic = section[:topics][topic_code]
|
|
219
|
+
|
|
220
|
+
unless topic
|
|
221
|
+
puts "\nā Invalid topic number!".colorize(:red)
|
|
222
|
+
wait_for_key
|
|
223
|
+
return
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
clear_screen
|
|
227
|
+
DSAVisualizer.learn(topic[:key])
|
|
228
|
+
mark_completed(topic_code)
|
|
229
|
+
wait_for_key
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def show_progress
|
|
233
|
+
clear_screen
|
|
234
|
+
puts "\nš YOUR LEARNING PROGRESS".colorize(:cyan).bold
|
|
235
|
+
puts "ā" * 80
|
|
236
|
+
|
|
237
|
+
completed = load_progress
|
|
238
|
+
total = CURRICULUM.values.sum { |s| s[:topics].size }
|
|
239
|
+
|
|
240
|
+
puts "\nCompleted: #{completed.size}/#{total} topics"
|
|
241
|
+
puts "Progress: #{'ā' * (completed.size * 50 / total)}#{'ā' * (50 - completed.size * 50 / total)} #{(completed.size * 100 / total)}%"
|
|
242
|
+
|
|
243
|
+
if completed.any?
|
|
244
|
+
puts "\nā
Completed Topics:"
|
|
245
|
+
completed.each { |topic| puts " ⢠#{topic}" }
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
wait_for_key
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def show_notes
|
|
252
|
+
clear_screen
|
|
253
|
+
puts "\nš YOUR NOTES".colorize(:cyan).bold
|
|
254
|
+
puts "ā" * 80
|
|
255
|
+
puts "\nFeature coming soon! Notes will be saved automatically as you learn."
|
|
256
|
+
wait_for_key
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def mark_completed(topic_code)
|
|
260
|
+
completed = load_progress
|
|
261
|
+
completed << topic_code unless completed.include?(topic_code)
|
|
262
|
+
save_progress(completed)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def load_progress
|
|
266
|
+
file = File.join(Dir.home, '.dsa_visualizer_progress')
|
|
267
|
+
return [] unless File.exist?(file)
|
|
268
|
+
File.read(file).split("\n")
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def save_progress(completed)
|
|
272
|
+
file = File.join(Dir.home, '.dsa_visualizer_progress')
|
|
273
|
+
File.write(file, completed.join("\n"))
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def wait_for_key
|
|
277
|
+
puts "\n\nPress any key to continue...".colorize(:light_black)
|
|
278
|
+
STDIN.getch
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module DSAVisualizer
|
|
2
|
+
class Comparator
|
|
3
|
+
def self.compare_memory_model(concept)
|
|
4
|
+
case concept
|
|
5
|
+
when :array
|
|
6
|
+
ruby_model = <<~RUBY
|
|
7
|
+
# Ruby Array (Dynamic)
|
|
8
|
+
arr = [1, 2, 3]
|
|
9
|
+
# Internally: Array of object references
|
|
10
|
+
# Each element is a pointer to Ruby object
|
|
11
|
+
# Heap allocated, garbage collected
|
|
12
|
+
RUBY
|
|
13
|
+
|
|
14
|
+
cpp_model = <<~CPP
|
|
15
|
+
// C++ Array (Static)
|
|
16
|
+
int arr[3] = {1, 2, 3};
|
|
17
|
+
// Contiguous memory block
|
|
18
|
+
// Direct values, no indirection
|
|
19
|
+
// Stack or heap allocated
|
|
20
|
+
CPP
|
|
21
|
+
|
|
22
|
+
explanation = "Ruby arrays store references to objects (indirection), while C++ arrays store actual values in contiguous memory. Ruby provides dynamic sizing with overhead, C++ offers fixed size with better cache locality."
|
|
23
|
+
|
|
24
|
+
Visualizer.print_comparison(ruby_model, cpp_model, explanation)
|
|
25
|
+
|
|
26
|
+
when :pointer
|
|
27
|
+
ruby_model = <<~RUBY
|
|
28
|
+
# Ruby (No explicit pointers)
|
|
29
|
+
obj = Object.new
|
|
30
|
+
ref = obj # Reference copy
|
|
31
|
+
# Both point to same object
|
|
32
|
+
# Managed by GC
|
|
33
|
+
RUBY
|
|
34
|
+
|
|
35
|
+
cpp_model = <<~CPP
|
|
36
|
+
// C++ (Explicit pointers)
|
|
37
|
+
int* ptr = new int(42);
|
|
38
|
+
int* ref = ptr; // Pointer copy
|
|
39
|
+
// Manual memory management
|
|
40
|
+
delete ptr; // Must free
|
|
41
|
+
CPP
|
|
42
|
+
|
|
43
|
+
explanation = "Ruby abstracts pointers as object references with automatic memory management. C++ exposes raw pointers requiring manual allocation/deallocation, offering more control but more responsibility."
|
|
44
|
+
|
|
45
|
+
Visualizer.print_comparison(ruby_model, cpp_model, explanation)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.compare_complexity(operation, ruby_complexity, cpp_complexity, explanation)
|
|
50
|
+
puts "\nā±ļø Time Complexity Comparison:".colorize(:yellow).bold
|
|
51
|
+
puts " Operation: #{operation}"
|
|
52
|
+
puts " Ruby: #{ruby_complexity}".colorize(:red)
|
|
53
|
+
puts " C++: #{cpp_complexity}".colorize(:green)
|
|
54
|
+
puts " Why: #{explanation}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
module DSAVisualizer
|
|
2
|
+
module DataStructures
|
|
3
|
+
class Array
|
|
4
|
+
def self.learn
|
|
5
|
+
demo
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.demo
|
|
9
|
+
Visualizer.print_header("ARRAY - Core Level Visualization")
|
|
10
|
+
|
|
11
|
+
# Memory Model Comparison
|
|
12
|
+
Visualizer.print_section("1. Memory Model")
|
|
13
|
+
Comparator.compare_memory_model(:array)
|
|
14
|
+
|
|
15
|
+
# Creation and Memory Allocation
|
|
16
|
+
Visualizer.print_section("2. Array Creation")
|
|
17
|
+
tracker = MemoryTracker.new
|
|
18
|
+
|
|
19
|
+
Visualizer.print_step(1, "Creating array in Ruby")
|
|
20
|
+
arr = [10, 20, 30, 40, 50]
|
|
21
|
+
tracker.track_allocation("Array", arr.size, arr)
|
|
22
|
+
|
|
23
|
+
puts "\nRuby internals:"
|
|
24
|
+
puts " - Array object created on heap"
|
|
25
|
+
puts " - Stores references to Integer objects"
|
|
26
|
+
puts " - Dynamic resizing capability"
|
|
27
|
+
Visualizer.visualize_memory_layout("Ruby Array", arr)
|
|
28
|
+
|
|
29
|
+
puts "\nC++ equivalent:"
|
|
30
|
+
puts " int arr[5] = {10, 20, 30, 40, 50};"
|
|
31
|
+
puts " - Contiguous memory block"
|
|
32
|
+
puts " - Each int: 4 bytes"
|
|
33
|
+
puts " - Total: 20 bytes (5 Ć 4)"
|
|
34
|
+
puts " - Stack allocated (if local)"
|
|
35
|
+
|
|
36
|
+
# Access Operation
|
|
37
|
+
Visualizer.print_section("3. Element Access")
|
|
38
|
+
Visualizer.print_step(2, "Accessing element at index 2")
|
|
39
|
+
|
|
40
|
+
element = arr[2]
|
|
41
|
+
tracker.track_operation("Access", "arr[2] = #{element}")
|
|
42
|
+
Visualizer.visualize_array(arr, 2)
|
|
43
|
+
|
|
44
|
+
puts "\nš Ruby Process:"
|
|
45
|
+
puts " 1. Check bounds (raises error if out of range)"
|
|
46
|
+
puts " 2. Calculate: base_address + (index Ć pointer_size)"
|
|
47
|
+
puts " 3. Dereference pointer to get object"
|
|
48
|
+
puts " 4. Return object reference"
|
|
49
|
+
|
|
50
|
+
puts "\nš C++ Process:"
|
|
51
|
+
puts " 1. Calculate: base_address + (index Ć sizeof(int))"
|
|
52
|
+
puts " 2. Direct memory access"
|
|
53
|
+
puts " 3. Return value (no indirection)"
|
|
54
|
+
|
|
55
|
+
Comparator.compare_complexity(
|
|
56
|
+
"Array Access",
|
|
57
|
+
"O(1) - with bounds checking overhead",
|
|
58
|
+
"O(1) - direct memory access",
|
|
59
|
+
"Both are constant time, but C++ is faster due to no bounds checking and direct value access"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Insertion
|
|
63
|
+
Visualizer.print_section("4. Insertion")
|
|
64
|
+
Visualizer.print_step(3, "Inserting 25 at index 2")
|
|
65
|
+
|
|
66
|
+
puts "\nBefore:"
|
|
67
|
+
Visualizer.visualize_array(arr)
|
|
68
|
+
|
|
69
|
+
arr.insert(2, 25)
|
|
70
|
+
tracker.track_operation("Insert", "Inserted 25 at index 2")
|
|
71
|
+
|
|
72
|
+
puts "\nAfter:"
|
|
73
|
+
Visualizer.visualize_array(arr, 2)
|
|
74
|
+
|
|
75
|
+
puts "\nš Ruby Process:"
|
|
76
|
+
puts " 1. Check if resize needed (capacity vs size)"
|
|
77
|
+
puts " 2. If needed: allocate new array (2Ć capacity)"
|
|
78
|
+
puts " 3. Shift elements right from index 2"
|
|
79
|
+
puts " 4. Insert new element"
|
|
80
|
+
puts " 5. Update size"
|
|
81
|
+
|
|
82
|
+
puts "\nš C++ Process (std::vector):"
|
|
83
|
+
puts " 1. Check capacity"
|
|
84
|
+
puts " 2. If needed: allocate new memory"
|
|
85
|
+
puts " 3. Copy elements to new location"
|
|
86
|
+
puts " 4. Shift elements using memmove"
|
|
87
|
+
puts " 5. Insert element"
|
|
88
|
+
|
|
89
|
+
Comparator.compare_complexity(
|
|
90
|
+
"Array Insertion (middle)",
|
|
91
|
+
"O(n) - must shift elements",
|
|
92
|
+
"O(n) - must shift elements",
|
|
93
|
+
"Both require shifting elements. Ruby has additional overhead from object reference management."
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Memory Summary
|
|
97
|
+
tracker.print_summary
|
|
98
|
+
|
|
99
|
+
# Key Takeaways
|
|
100
|
+
puts "\n\nšÆ Key Takeaways:".colorize(:green).bold
|
|
101
|
+
puts " 1. Ruby arrays are dynamic and store object references"
|
|
102
|
+
puts " 2. C++ arrays can be static (fixed) or dynamic (std::vector)"
|
|
103
|
+
puts " 3. Ruby provides safety (bounds checking) at cost of performance"
|
|
104
|
+
puts " 4. C++ provides speed at cost of safety (manual management)"
|
|
105
|
+
puts " 5. Both use contiguous memory, but Ruby adds indirection layer"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|