sorting_race/services/sorters/
merge.rs

1//! Merge Sort implementation
2
3use crate::models::traits::{Sorter, StepResult, Telemetry, Markers};
4use std::any::Any;
5
6#[derive(Debug, Clone)]
7struct MergeFrame {
8    left: usize,
9    mid: usize,
10    right: usize,
11    state: MergeState,
12    temp_left_idx: usize,
13    temp_right_idx: usize,
14    output_idx: usize,
15}
16
17#[derive(Debug, Clone, PartialEq)]
18enum MergeState {
19    Split,
20    Merge,
21}
22
23/// Merge Sort algorithm implementation
24#[derive(Debug)]
25pub struct MergeSort {
26    data: Vec<i32>,
27    temp_buffer: Vec<i32>,
28    stack: Vec<MergeFrame>,
29    comparisons: u64,
30    moves: u64,
31    complete: bool,
32    memory_usage: usize,
33}
34
35impl MergeSort {
36    /// Create a new MergeSort instance
37    pub fn new() -> Self {
38        Self {
39            data: Vec::new(),
40            temp_buffer: Vec::new(),
41            stack: Vec::new(),
42            comparisons: 0,
43            moves: 0,
44            complete: false,
45            memory_usage: 0,
46        }
47    }
48
49    fn merge(&mut self, frame: &mut MergeFrame, budget: &mut usize) -> bool {
50        let mid = frame.mid;
51        let right = frame.right;
52
53        // Copy data to temp buffer if not already done
54        if frame.temp_left_idx == frame.left {
55            for i in frame.left..=right {
56                self.temp_buffer[i] = self.data[i];
57            }
58        }
59
60        while *budget > 0 && frame.output_idx <= right {
61            if frame.temp_left_idx > mid {
62                // Left half exhausted, copy from right
63                self.data[frame.output_idx] = self.temp_buffer[frame.temp_right_idx];
64                self.moves += 1;
65                frame.temp_right_idx += 1;
66            } else if frame.temp_right_idx > right {
67                // Right half exhausted, copy from left
68                self.data[frame.output_idx] = self.temp_buffer[frame.temp_left_idx];
69                self.moves += 1;
70                frame.temp_left_idx += 1;
71            } else {
72                // Compare and merge
73                *budget -= 1;
74                self.comparisons += 1;
75
76                if self.temp_buffer[frame.temp_left_idx] <= self.temp_buffer[frame.temp_right_idx] {
77                    self.data[frame.output_idx] = self.temp_buffer[frame.temp_left_idx];
78                    frame.temp_left_idx += 1;
79                } else {
80                    self.data[frame.output_idx] = self.temp_buffer[frame.temp_right_idx];
81                    frame.temp_right_idx += 1;
82                }
83                self.moves += 1;
84            }
85
86            frame.output_idx += 1;
87        }
88
89        frame.output_idx > right // Return true if merge is complete
90    }
91}
92
93impl Default for MergeSort {
94    fn default() -> Self {
95        Self::new()
96    }
97}
98
99impl Sorter for MergeSort {
100    fn step(&mut self, budget: usize) -> StepResult {
101        if self.complete || self.data.len() <= 1 {
102            return StepResult {
103                comparisons_used: 0,
104                moves_made: 0,
105                continued: false,
106            };
107        }
108
109        let initial_comparisons = self.comparisons;
110        let initial_moves = self.moves;
111        let mut remaining_budget = budget;
112
113        while remaining_budget > 0 && !self.stack.is_empty() {
114            let mut frame = self.stack.pop().unwrap();
115
116            match frame.state {
117                MergeState::Split => {
118                    if frame.left < frame.right {
119                        let mid = (frame.left + frame.right) / 2;
120                        
121                        // Push merge operation for later
122                        self.stack.push(MergeFrame {
123                            left: frame.left,
124                            mid,
125                            right: frame.right,
126                            state: MergeState::Merge,
127                            temp_left_idx: frame.left,
128                            temp_right_idx: mid + 1,
129                            output_idx: frame.left,
130                        });
131
132                        // Push right half
133                        self.stack.push(MergeFrame {
134                            left: mid + 1,
135                            mid: mid + 1,
136                            right: frame.right,
137                            state: MergeState::Split,
138                            temp_left_idx: 0,
139                            temp_right_idx: 0,
140                            output_idx: 0,
141                        });
142
143                        // Push left half
144                        self.stack.push(MergeFrame {
145                            left: frame.left,
146                            mid: frame.left,
147                            right: mid,
148                            state: MergeState::Split,
149                            temp_left_idx: 0,
150                            temp_right_idx: 0,
151                            output_idx: 0,
152                        });
153                    }
154                }
155                MergeState::Merge => {
156                    let finished = self.merge(&mut frame, &mut remaining_budget);
157                    
158                    if !finished {
159                        // Merge not finished, push back to stack
160                        self.stack.push(frame);
161                        break;
162                    }
163                }
164            }
165        }
166
167        if self.stack.is_empty() {
168            self.complete = true;
169        }
170
171        StepResult {
172            comparisons_used: (self.comparisons - initial_comparisons) as usize,
173            moves_made: (self.moves - initial_moves) as usize,
174            continued: !self.complete,
175        }
176    }
177
178    fn is_complete(&self) -> bool {
179        self.complete
180    }
181
182    fn get_telemetry(&self) -> Telemetry {
183        let mut markers = Markers::default();
184        
185        if let Some(frame) = self.stack.last()
186            && frame.state == MergeState::Merge {
187                markers.merge_runs.push((frame.left, frame.right));
188                
189                // Show current merge positions
190                if frame.temp_left_idx <= frame.mid {
191                    markers.cursors.push(frame.temp_left_idx);
192                }
193                if frame.temp_right_idx <= frame.right {
194                    markers.cursors.push(frame.temp_right_idx);
195                }
196                if frame.output_idx <= frame.right {
197                    markers.cursors.push(frame.output_idx);
198                }
199            }
200
201        Telemetry {
202            total_comparisons: self.comparisons,
203            total_moves: self.moves,
204            memory_current: self.memory_usage,
205            memory_peak: self.memory_usage, // Simplified for stub
206            highlights: markers.cursors.clone(),
207            markers,
208            status_text: if self.complete {
209                "Completed".to_string()
210            } else if let Some(frame) = self.stack.last() {
211                match frame.state {
212                    MergeState::Split => format!("Splitting range [{}, {}]", frame.left, frame.right),
213                    MergeState::Merge => format!("Merging range [{}, {}]", frame.left, frame.right),
214                }
215            } else {
216                "Processing".to_string()
217            },
218            progress_hint: if self.data.len() <= 1 {
219                1.0
220            } else {
221                let progress = 1.0 - (self.stack.len() as f32 / (self.data.len() as f32).log2().max(1.0));
222                if progress.is_finite() { progress.min(1.0).max(0.0) } else { 0.0 }
223            },
224        }
225    }
226
227    fn reset(&mut self, data: Vec<i32>) {
228        self.data = data;
229        self.temp_buffer = vec![0; self.data.len()];
230        self.stack.clear();
231        self.comparisons = 0;
232        self.moves = 0;
233        self.complete = self.data.len() <= 1;
234        
235        // Calculate memory usage: temp buffer + stack
236        self.memory_usage = self.temp_buffer.len() * std::mem::size_of::<i32>();
237
238        if !self.complete {
239            self.stack.push(MergeFrame {
240                left: 0,
241                mid: 0,
242                right: self.data.len() - 1,
243                state: MergeState::Split,
244                temp_left_idx: 0,
245                temp_right_idx: 0,
246                output_idx: 0,
247            });
248            
249            self.memory_usage += self.stack.capacity() * std::mem::size_of::<MergeFrame>();
250        }
251    }
252
253    fn name(&self) -> &str {
254        "Merge Sort"
255    }
256
257    fn get_array(&self) -> &[i32] {
258        &self.data
259    }
260
261    fn get_memory_usage(&self) -> usize {
262        // Data array + temp buffer + stack
263        self.data.len() * std::mem::size_of::<i32>() + self.memory_usage
264    }
265
266    fn as_any(&self) -> &dyn Any {
267        self
268    }
269
270    fn as_any_mut(&mut self) -> &mut dyn Any {
271        self
272    }
273}