Merge remote-tracking branches 'origin/feature/sorting' and 'origin/feature/even-only-sort-strategy' into feature/ui

This commit is contained in:
2026-08-30 12:51:10 +04:00
12 changed files with 909 additions and 146 deletions
@@ -0,0 +1,24 @@
package ru.project.sorting;
import ru.project.list.MyList;
import java.util.Comparator;
public class BubbleSortStrategy<T> implements SortStrategy<T> {
@Override
public void sort(MyList<T> list, Comparator<T> comparator) {
if (list == null || list.size() <= 1) {
return;
}
int n = list.size();
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (comparator.compare(list.get(j), list.get(j + 1)) > 0) {
T temp = list.get(j);
list.set(j, list.get(j + 1));
list.set(j + 1, temp);
}
}
}
}
}
@@ -0,0 +1,84 @@
package ru.project.sorting;
import ru.project.list.MyList;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.ToIntFunction;
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;
}
}
@@ -0,0 +1,94 @@
package ru.project.sorting;
import ru.project.collection.MyLinkedList;
import ru.project.collection.MyList;
import java.util.Comparator;
import java.util.function.ToIntFunction;
public class EvenOnlySortStrategy<T> implements SortStrategy<T> {
private SortStrategy<T> sortStrategy;
private ToIntFunction<T> valueExtractor;
public EvenOnlySortStrategy() {
}
public EvenOnlySortStrategy(SortStrategy<T> sortStrategy) {
setSortStrategy(sortStrategy);
}
public EvenOnlySortStrategy(
SortStrategy<T> sortStrategy,
ToIntFunction<T> valueExtractor
) {
setSortStrategy(sortStrategy);
setValueExtractor(valueExtractor);
}
public void setSortStrategy(SortStrategy<T> sortStrategy) {
if (sortStrategy == null) {
throw new IllegalArgumentException("Sort strategy must not be null");
}
this.sortStrategy = sortStrategy;
}
public void setValueExtractor(ToIntFunction<T> valueExtractor) {
if (valueExtractor == null) {
throw new IllegalArgumentException("Value extractor must not be null");
}
this.valueExtractor = valueExtractor;
}
@Override
public void sort(MyList<T> list, Comparator<T> comparator) {
if (sortStrategy == null) {
throw new IllegalStateException("Sort strategy is not set");
}
if (valueExtractor == null) {
throw new IllegalStateException("Value extractor is not set");
}
if (list == null || list.size() <= 1) {
return;
}
int evenCount = 0;
for (int i = 0; i < list.size(); i++) {
T element = list.get(i);
if (valueExtractor.applyAsInt(element) % 2 == 0) {
evenCount++;
}
}
if (evenCount <= 1) {
return;
}
MyList<T> evenElements = new MyLinkedList<>();
int[] evenIndexes = new int[evenCount];
int evenIndex = 0;
for (int i = 0; i < list.size(); i++) {
T element = list.get(i);
if (valueExtractor.applyAsInt(element) % 2 == 0) {
evenElements.add(element);
evenIndexes[evenIndex] = i;
evenIndex++;
}
}
sortStrategy.sort(evenElements, comparator);
for (int i = 0; i < evenIndexes.length; i++) {
list.set(evenIndexes[i], evenElements.get(i));
}
}
}
@@ -0,0 +1,67 @@
package ru.project.sorting;
import ru.project.collection.MyList;
import java.util.Comparator;
public class MergeSortStrategy<T> implements SortStrategy<T> {
@Override
public void sort(MyList<T> list, Comparator<T> comparator) {
if (list == null || list.size() <= 1) {
return;
}
mergeSort(list, 0, list.size() - 1, comparator);
}
private void mergeSort(MyList<T> list, int left, int right, Comparator<T> comparator) {
if (left >= right) {
return;
}
int mid = (left + right) / 2;
mergeSort(list, left, mid, comparator);
mergeSort(list, mid + 1, right, comparator);
merge(list, left, mid, right, comparator);
}
private void merge(MyList<T> list, int left, int mid, int right, Comparator<T> comparator) {
int leftSize = mid - left + 1;
int rightSize = right - mid;
@SuppressWarnings("unchecked")
T[] leftArray = (T[]) new Object[leftSize];
@SuppressWarnings("unchecked")
T[] rightArray = (T[]) new Object[rightSize];
for (int i = 0; i < leftSize; i++) {
leftArray[i] = list.get(left + i);
}
for (int j = 0; j < rightSize; j++) {
rightArray[j] = list.get(mid + 1 + j);
}
int i = 0, j = 0, k = left;
while (i < leftSize && j < rightSize) {
if (comparator.compare(leftArray[i], rightArray[j]) <= 0) {
list.set(k, leftArray[i]);
i++;
} else {
list.set(k, rightArray[j]);
j++;
}
k++;
}
while (i < leftSize) {
list.set(k, leftArray[i]);
i++;
k++;
}
while (j < rightSize) {
list.set(k, rightArray[j]);
j++;
k++;
}
}
}
@@ -0,0 +1,9 @@
package ru.project.sorting;
import ru.project.collection.MyList;
import java.util.Comparator;
public interface SortStrategy<T> {
void sort(MyList<T> list, Comparator<T> comparator);
}
@@ -0,0 +1,12 @@
package ru.project.sorting;
import ru.project.student.Student;
import java.util.Comparator;
public class StudentAverageGradeComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
return Double.compare(s1.getAverageGrade(), s2.getAverageGrade());
}
}
@@ -0,0 +1,12 @@
package ru.project.sorting;
import ru.project.student.Student;
import java.util.Comparator;
public class StudentGroupComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
return s1.getGroupNumber().compareTo(s2.getGroupNumber());
}
}
@@ -0,0 +1,12 @@
package ru.project.sorting;
import ru.project.student.Student;
import java.util.Comparator;
public class StudentRecordBookComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
return Integer.compare(s1.getRecordBookNumber(), s2.getRecordBookNumber());
}
}
@@ -3,21 +3,32 @@ package ru.project.student;
import java.util.Objects;
public class Student {
public static final double MIN_AVERAGE_GRADE = 0.0;
public static final double MAX_AVERAGE_GRADE = 5.0;
public static final int MIN_RECORD_BOOK_NUMBER = 1;
public static final String GROUP_NUMBER_PATTERN = "^[A-Z][0-9]{2}$";
private final String groupNumber;
private final double averageGrade;
private final int recordBookNumber;
public Student(String groupNumber, double averageGrade, int recordBookNumber) {
if (groupNumber == null || !groupNumber.matches("^[A-Z][0-9]{2}$")) {
if (groupNumber == null || !groupNumber.matches(GROUP_NUMBER_PATTERN)) {
throw new IllegalArgumentException(
"Group number must match format: one uppercase letter + two digits (e.g. A12)");
"Group number must match pattern: " + GROUP_NUMBER_PATTERN);
}
if (averageGrade < 0.0 || averageGrade > 5.0) {
throw new IllegalArgumentException("Average grade must be between 0.0 and 5.0");
if (averageGrade < MIN_AVERAGE_GRADE || averageGrade > MAX_AVERAGE_GRADE) {
throw new IllegalArgumentException(
"Average grade must be between " + MIN_AVERAGE_GRADE + " and " + MAX_AVERAGE_GRADE);
}
if (recordBookNumber <= 0) {
throw new IllegalArgumentException("Record book number must be positive");
}
if (recordBookNumber < MIN_RECORD_BOOK_NUMBER) {
throw new IllegalArgumentException(
"Record book number must be at least " + MIN_RECORD_BOOK_NUMBER);
}
this.groupNumber = groupNumber;
this.averageGrade = averageGrade;
this.recordBookNumber = recordBookNumber;
@@ -27,6 +38,10 @@ public class Student {
return groupNumber;
}
public double getAverageGrade() {
return averageGrade;
}
public int getRecordBookNumber() {
return recordBookNumber;
}
@@ -39,11 +54,22 @@ public class Student {
return new Student(this.groupNumber, averageGrade, this.recordBookNumber);
}
public Student withRecordBookNumber(int recordBookNumber) {
return new Student(this.groupNumber, this.averageGrade, recordBookNumber);
public static double getMinAverageGrade() {
return MIN_AVERAGE_GRADE;
}
public static double getMaxAverageGrade() {
return MAX_AVERAGE_GRADE;
}
public static int getMinRecordBookNumber() {
return MIN_RECORD_BOOK_NUMBER;
}
public static String getGroupNumberPattern() {
return GROUP_NUMBER_PATTERN;
}
@Override
public String toString() {
return "Student{"
+ "groupNumber='"
@@ -56,16 +82,19 @@ public class Student {
+ '}';
}
@Override
public int hashCode() {
return Objects.hash(groupNumber, averageGrade, recordBookNumber);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
if (this.hashCode() != obj.hashCode()) {
return false;
}
@@ -75,25 +104,4 @@ public class Student {
&& recordBookNumber == student.recordBookNumber
&& Objects.equals(groupNumber, student.groupNumber);
}
@Override
public int hashCode() {
return Objects.hash(groupNumber, averageGrade, recordBookNumber);
}
public static double getMinAverageGrade() {
return 0.0;
}
public static double getMaxAverageGrade() {
return 5.0;
}
public static int getMinRecordBookNumber() {
return 1;
}
public static String getGroupNumberPattern() {
return "^[A-Z][0-9]{2}$";
}
}