feat(sorting): add selectable sorting algorithms

- add bubble and merge sort algorithm selection
- add SortStrategySelectionWindow
- apply selected strategy to normal and parity sorting
- use dedicated comparators for student fields
- remove obsolete EvenOnlyMergeSortStrategy
- update collection menu labels and TODO placeholders
This commit is contained in:
2026-08-31 19:11:10 +04:00
parent a143a535ba
commit db66ebbc07
5 changed files with 137 additions and 99 deletions
@@ -1,84 +0,0 @@
package ru.project.sorting;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.ToIntFunction;
import ru.project.collection.MyList;
public class EvenOnlyMergeSortStrategy<T> implements SortStrategy<T> {
private final ToIntFunction<T> valueExtractor;
public EvenOnlyMergeSortStrategy(ToIntFunction<T> valueExtractor) {
this.valueExtractor = valueExtractor;
}
@Override
public void sort(MyList<T> list, Comparator<T> comparator) {
if (list == null || list.size() <= 1) {
return;
}
List<Integer> evenIndices = new ArrayList<>();
List<T> evenElements = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
T element = list.get(i);
int value = valueExtractor.applyAsInt(element);
if (value % 2 == 0) {
evenIndices.add(i);
evenElements.add(element);
}
}
if (evenElements.size() <= 1) {
return;
}
List<T> sortedEven = mergeSort(evenElements, comparator);
for (int j = 0; j < evenIndices.size(); j++) {
list.set(evenIndices.get(j), sortedEven.get(j));
}
}
private List<T> mergeSort(List<T> list, Comparator<T> comparator) {
if (list.size() <= 1) {
return list;
}
int mid = list.size() / 2;
List<T> left = mergeSort(list.subList(0, mid), comparator);
List<T> right = mergeSort(list.subList(mid, list.size()), comparator);
return merge(left, right, comparator);
}
private List<T> merge(List<T> left, List<T> right, Comparator<T> comparator) {
List<T> result = new ArrayList<>();
int i = 0, j = 0;
while (i < left.size() && j < right.size()) {
if (comparator.compare(left.get(i), right.get(j)) <= 0) {
result.add(left.get(i));
i++;
} else {
result.add(right.get(j));
j++;
}
}
while (i < left.size()) {
result.add(left.get(i));
i++;
}
while (j < right.size()) {
result.add(right.get(j));
j++;
}
return result;
}
}
@@ -7,7 +7,6 @@ import ru.project.ui.base.BaseModalWindow;
import ru.project.ui.collection.sorting.SortCollectionMenu;
import ru.project.ui.common.CollectionDisplayWindow;
import ru.project.ui.common.CollectionFileSaveWindow;
import ru.project.ui.common.MessageWindow;
public class CurrentCollectionMenu extends BaseModalWindow {
@@ -15,6 +14,9 @@ public class CurrentCollectionMenu extends BaseModalWindow {
private final SortCollectionMenu sortCollectionMenu;
// private final SearchCollectionMenu searchCollectionMenu;
// private final CountOccurrencesMenu countOccurrencesMenu;
public CurrentCollectionMenu(WindowBasedTextGUI gui, AppState state) {
super("Меню текущей коллекции", gui);
@@ -23,6 +25,9 @@ public class CurrentCollectionMenu extends BaseModalWindow {
this.sortCollectionMenu = new SortCollectionMenu(gui, state);
// this.searchCollectionMenu = new SearchCollectionMenu(gui, state);
// this.countCollectionMenu = new CountOccurrencesMenu(gui, state);
ActionListBox menu = new ActionListBox();
menu.addItem("Показать коллекцию...", this::showCurrentCollection);
@@ -53,12 +58,14 @@ public class CurrentCollectionMenu extends BaseModalWindow {
}
private void searchCollection() {
// TODO
MessageWindow.showModal(gui, "Не реализовано.");
// SearchCollectionMenu searchCollectionMenu = new SearchCollectionMenu(gui, state);
//
// searchCollectionMenu.showModal();
}
private void countOccurrences() {
// TODO
MessageWindow.showModal(gui, "Не реализовано.");
// CountOccurrencesMenu countOccurrencesMenu = new CountOccurrencesMenu(gui, state);
//
// countOccurrencesMenu.showModal();
}
}
@@ -0,0 +1,6 @@
package ru.project.ui.collection.sorting;
public enum SortAlgorithm {
BUBBLE,
MERGE
}
@@ -5,7 +5,16 @@ import com.googlecode.lanterna.gui2.Label;
import com.googlecode.lanterna.gui2.LinearLayout;
import com.googlecode.lanterna.gui2.Panel;
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
import java.util.Comparator;
import ru.project.model.AppState;
import ru.project.sorting.BubbleSortStrategy;
import ru.project.sorting.EvenOnlySortStrategy;
import ru.project.sorting.MergeSortStrategy;
import ru.project.sorting.SortStrategy;
import ru.project.sorting.StudentAverageGradeComparator;
import ru.project.sorting.StudentGroupComparator;
import ru.project.sorting.StudentRecordBookComparator;
import ru.project.student.Student;
import ru.project.ui.base.BaseModalWindow;
import ru.project.ui.common.MessageWindow;
@@ -13,29 +22,37 @@ public class SortCollectionMenu extends BaseModalWindow {
private final AppState state;
private final Label sortMethodLabel;
private final Label sortAlgorithmLabel;
private final Label sortFieldLabel;
private final Label sortMethodLabel;
private final SortMethodSelectionWindow sortMethodSelectionWindow;
private final NormalSortSettingsWindow normalSortSettingsWindow;
private final ParitySortSettingsWindow paritySortSettingsWindow;
private final SortMethodSelectionWindow sortMethodSelectionWindow;
private final SortStrategySelectionWindow sortStrategySelectionWindow;
private SortMethod selectedSortMethod;
private SortAlgorithm selectedSortAlgorithm;
private SortField selectedSortField;
private SortMethod selectedSortMethod;
public SortCollectionMenu(WindowBasedTextGUI gui, AppState state) {
super("Меню сортировки текущей коллекции", gui);
this.state = state;
this.selectedSortMethod = SortMethod.NORMAL;
this.selectedSortAlgorithm = SortAlgorithm.BUBBLE;
this.selectedSortField = SortField.GROUP_NUMBER;
this.selectedSortMethod = SortMethod.NORMAL;
Panel panel = new Panel();
panel.setLayoutManager(new LinearLayout());
this.sortMethodLabel = new Label("Способ сортировки: " + getSortMethodName(selectedSortMethod));
this.sortAlgorithmLabel =
new Label("Алгоритм сортировки: " + getSortAlgorithmName(selectedSortAlgorithm));
this.sortFieldLabel =
new Label("Сортировать по: " + getSortFieldName(selectedSortMethod, selectedSortField));
@@ -52,6 +69,16 @@ public class SortCollectionMenu extends BaseModalWindow {
"Сортировать по: " + getSortFieldName(selectedSortMethod, selectedSortField));
});
this.sortStrategySelectionWindow =
new SortStrategySelectionWindow(
gui,
sortAlgorithm -> {
selectedSortAlgorithm = sortAlgorithm;
sortAlgorithmLabel.setText(
"Алгоритм сортировки: " + getSortAlgorithmName(selectedSortAlgorithm));
});
this.normalSortSettingsWindow =
new NormalSortSettingsWindow(
gui,
@@ -66,11 +93,14 @@ public class SortCollectionMenu extends BaseModalWindow {
panel.addComponent(sortMethodLabel);
panel.addComponent(sortFieldLabel);
panel.addComponent(sortAlgorithmLabel);
panel.addComponent(new Button("Выбрать способ сортировки", this::selectSortMethod));
panel.addComponent(new Button("Выбрать способ сортировки...", this::selectSortMethod));
panel.addComponent(new Button("Выбрать алгоритм сортировки...", this::selectSortAlgorithm));
panel.addComponent(
new Button("Настроить текущий способ сортировки", this::setupCurrentSortMethod));
new Button("Настроить текущий способ сортировки...", this::setupCurrentSortMethod));
panel.addComponent(new Button("Сортировать текущую коллекцию", this::sortCurrentCollection));
@@ -91,6 +121,10 @@ public class SortCollectionMenu extends BaseModalWindow {
sortMethodSelectionWindow.showModal();
}
private void selectSortAlgorithm() {
sortStrategySelectionWindow.showModal();
}
private void sortCurrentCollection() {
if (state.getMainCollection() == null || state.getMainCollection().isEmpty()) {
@@ -107,25 +141,64 @@ public class SortCollectionMenu extends BaseModalWindow {
}
private void sortNormally() {
// TODO
MessageWindow.showModal(gui, "Обычная сортировка не реализована.");
SortStrategy<Student> sortStrategy = getSortStrategy();
Comparator<Student> comparator = getSortComparator();
sortStrategy.sort(state.getMainCollection(), comparator);
MessageWindow.showModal(gui, "Обычная сортировка успешно выполнена.");
}
private void sortByParity() {
// TODO
MessageWindow.showModal(gui, "Сортировка по чётности не реализована.");
SortStrategy<Student> sortStrategy =
new EvenOnlySortStrategy<>(getSortStrategy(), Student::getRecordBookNumber);
Comparator<Student> comparator = new StudentRecordBookComparator();
sortStrategy.sort(state.getMainCollection(), comparator);
MessageWindow.showModal(gui, "Сортировка по чётности успешно выполнена.");
}
private SortStrategy<Student> getSortStrategy() {
return switch (selectedSortAlgorithm) {
case BUBBLE -> new BubbleSortStrategy<>();
case MERGE -> new MergeSortStrategy<>();
};
}
private Comparator<Student> getSortComparator() {
return switch (selectedSortField) {
case GROUP_NUMBER -> new StudentGroupComparator();
case AVERAGE_GRADE -> new StudentAverageGradeComparator();
case RECORD_BOOK_NUMBER -> new StudentRecordBookComparator();
};
}
private String getSortMethodName(SortMethod sortMethod) {
return switch (sortMethod) {
case NORMAL -> "Обычная сортировка";
case PARITY -> "Сортировка по чётности";
};
}
private String getSortAlgorithmName(SortAlgorithm sortAlgorithm) {
return switch (sortAlgorithm) {
case BUBBLE -> "Сортировка пузырьком";
case MERGE -> "Сортировка слиянием";
};
}
private String getSortFieldName(SortMethod sortMethod, SortField sortField) {
return switch (sortMethod) {
case NORMAL -> getNormalSortFieldName(sortField);
case PARITY -> "номеру зачётной книжки";
};
}
@@ -133,7 +206,9 @@ public class SortCollectionMenu extends BaseModalWindow {
private String getNormalSortFieldName(SortField sortField) {
return switch (sortField) {
case GROUP_NUMBER -> "номеру группы";
case AVERAGE_GRADE -> "среднему баллу";
case RECORD_BOOK_NUMBER -> "номеру зачётной книжки";
};
}
@@ -0,0 +1,34 @@
package ru.project.ui.collection.sorting;
import com.googlecode.lanterna.gui2.ActionListBox;
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
import java.util.function.Consumer;
import ru.project.ui.base.BaseModalWindow;
public class SortStrategySelectionWindow extends BaseModalWindow {
private final Consumer<SortAlgorithm> onSortAlgorithmSelected;
public SortStrategySelectionWindow(
WindowBasedTextGUI gui, Consumer<SortAlgorithm> onSortAlgorithmSelected) {
super("Выбор алгоритма сортировки", gui);
this.onSortAlgorithmSelected = onSortAlgorithmSelected;
ActionListBox menu = new ActionListBox();
menu.addItem("Сортировка пузырьком", () -> selectSortAlgorithm(SortAlgorithm.BUBBLE));
menu.addItem("Сортировка слиянием", () -> selectSortAlgorithm(SortAlgorithm.MERGE));
menu.addItem("Выйти", this::close);
setComponent(menu);
}
private void selectSortAlgorithm(SortAlgorithm sortAlgorithm) {
onSortAlgorithmSelected.accept(sortAlgorithm);
close();
}
}