feat: add StudentOccurrenceIndexFinder for occurrence search and test
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
package ru.project.finder;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
public class StudentOccurrenceIndexFinder
|
||||
{
|
||||
public int[] findOccurrences(MyList<Student> students, Student target) {
|
||||
if (students == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (target == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (students.isEmpty()) {
|
||||
return new int[0];
|
||||
}
|
||||
int size = students.size();
|
||||
int threadCount = calculateThreadCount(size);
|
||||
int chunkSize = countChunkSize(size, threadCount);
|
||||
|
||||
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
|
||||
MyList<Future<MyList<Integer>>> futures = new MyLinkedList<>();
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
int fromIndex = i * chunkSize;
|
||||
int toIndex = Math.min(fromIndex + chunkSize, size);
|
||||
|
||||
if (fromIndex >= toIndex) {
|
||||
break;
|
||||
}
|
||||
|
||||
final int start = fromIndex;
|
||||
final int end = toIndex;
|
||||
|
||||
Future<MyList<Integer>> future = executor.submit(() -> {
|
||||
return findInRange(students, target, start, end);
|
||||
});
|
||||
futures.add(future);
|
||||
}
|
||||
MyList<Integer> allIndices = new MyLinkedList<>();
|
||||
try {
|
||||
for (int i = 0; i < futures.size(); i++) {
|
||||
Future<MyList<Integer>> future = futures.get(i);
|
||||
MyList<Integer> partialResult = future.get();
|
||||
|
||||
if (partialResult != null) {
|
||||
for (int j = 0; j < partialResult.size(); j++) {
|
||||
allIndices.add(partialResult.get(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Ошибка при поиске", e);
|
||||
} finally {
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
sortList(allIndices);
|
||||
|
||||
int[] resultArray = new int[allIndices.size()];
|
||||
for (int i = 0; i < allIndices.size(); i++) {
|
||||
resultArray[i] = allIndices.get(i);
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
private void sortList(MyList<Integer> list) {
|
||||
if (list.size() <= 1) return;
|
||||
|
||||
MyList<Integer> sorted = new MyLinkedList<>();
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
int value = list.get(i);
|
||||
int insertIndex = 0;
|
||||
while (insertIndex < sorted.size()) {
|
||||
if (sorted.get(insertIndex) > value) {
|
||||
break;
|
||||
}
|
||||
insertIndex++;
|
||||
}
|
||||
|
||||
MyList<Integer> temp = new MyLinkedList<>();
|
||||
for (int k = 0; k < insertIndex; k++) {
|
||||
temp.add(sorted.get(k));
|
||||
}
|
||||
temp.add(value);
|
||||
for (int k = insertIndex; k < sorted.size(); k++) {
|
||||
temp.add(sorted.get(k));
|
||||
}
|
||||
sorted = temp;
|
||||
}
|
||||
|
||||
while (!list.isEmpty()) {
|
||||
list.remove(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < sorted.size(); i++) {
|
||||
list.add(sorted.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
private int calculateThreadCount(int size) {
|
||||
int processors = Runtime.getRuntime().availableProcessors();
|
||||
return Math.min(processors, size);
|
||||
}
|
||||
|
||||
private int countChunkSize(int size, int threadCount) {
|
||||
if (threadCount == 0) return 0;
|
||||
return (size + threadCount - 1) / threadCount;
|
||||
}
|
||||
|
||||
private MyList<Integer> findInRange(MyList<Student> students, Student target, int fromIndex, int toIndex) {
|
||||
MyList<Integer> foundIndices = new MyLinkedList<>();
|
||||
|
||||
for (int i = fromIndex; i < toIndex; i++) {
|
||||
Student current = students.get(i);
|
||||
if (current != null && current.equals(target)) {
|
||||
foundIndices.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
return foundIndices;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package ru.project.finder;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class StudentOccurrenceIndexFinderTest
|
||||
{
|
||||
private StudentOccurrenceIndexFinder finder;
|
||||
private MyList<Student> students;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
finder = new StudentOccurrenceIndexFinder();
|
||||
students = new MyLinkedList<>();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTesfindOccurrences_emptyList_returnsEmptyArray() {
|
||||
int[] result = finder.findOccurrences(students, new Student("A12", 4.5, 1));
|
||||
assertEquals(0, result.length);
|
||||
}
|
||||
@Test
|
||||
void shouldTesfindOccurrences_noMatches_returnsEmptyArray() {
|
||||
students.add(new Student("A12", 4.0, 101));
|
||||
students.add(new Student("B23", 3.5, 102));
|
||||
Student target = new Student("C34", 4.8, 103); // такого нет
|
||||
|
||||
int[] result = finder.findOccurrences(students, target);
|
||||
assertEquals(0, result.length);
|
||||
}
|
||||
@Test
|
||||
void shouldTesfindOccurrences_singleMatch_returnsCorrectIndex() {
|
||||
students.add(new Student("A12", 4.0, 101));
|
||||
students.add(new Student("B23", 3.5, 102)); // target здесь
|
||||
students.add(new Student("C34", 4.8, 103));
|
||||
|
||||
Student target = new Student("B23", 3.5, 102);
|
||||
int[] result = finder.findOccurrences(students, target);
|
||||
|
||||
assertEquals(1, result.length);
|
||||
assertEquals(1, result[0]);
|
||||
}
|
||||
@Test
|
||||
void shouldTesfindOccurrences_multipleMatches_returnsAllIndicesSorted() {
|
||||
// индексы: 0, 2, 4 — должны вернуться в порядке возрастания
|
||||
students.add(new Student("A12", 4.5, 101)); // match
|
||||
students.add(new Student("B23", 3.8, 102));
|
||||
students.add(new Student("A12", 4.5, 101)); // match
|
||||
students.add(new Student("C34", 4.0, 103));
|
||||
students.add(new Student("A12", 4.5, 101)); // match
|
||||
|
||||
Student target = new Student("A12", 4.5, 101);
|
||||
int[] result = finder.findOccurrences(students, target);
|
||||
|
||||
assertEquals(3, result.length);
|
||||
assertArrayEquals(new int[]{0, 2, 4}, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTesfindOccurrences_allElementsMatch_returnsAllIndices() {
|
||||
Student s = new Student("X99", 5.0, 999);
|
||||
students.add(s);
|
||||
students.add(s);
|
||||
students.add(s);
|
||||
|
||||
int[] result = finder.findOccurrences(students, s);
|
||||
assertEquals(3, result.length);
|
||||
assertArrayEquals(new int[]{0, 1, 2}, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTesfindOccurrences_differentAverageGrade_noMatch() {
|
||||
students.add(new Student("A12", 4.50, 101));
|
||||
Student target = new Student("A12", 4.51, 101); // отличается балл
|
||||
|
||||
int[] result = finder.findOccurrences(students, target);
|
||||
assertEquals(0, result.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTesfindOccurrences_differentGroupNumber_noMatch() {
|
||||
students.add(new Student("A12", 4.5, 101));
|
||||
Student target = new Student("B12", 4.5, 101); // другая группа
|
||||
|
||||
int[] result = finder.findOccurrences(students, target);
|
||||
assertEquals(0, result.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTesfindOccurrences_differentRecordBookNumber_noMatch() {
|
||||
students.add(new Student("A12", 4.5, 101));
|
||||
Student target = new Student("A12", 4.5, 102); // другой номер зачетки
|
||||
|
||||
int[] result = finder.findOccurrences(students, target);
|
||||
assertEquals(0, result.length);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void shouldTesfindOccurrences_nullList_throwsException() {
|
||||
Student target = new Student("A12", 4.5, 101);
|
||||
assertThrows(IllegalArgumentException.class, () -> finder.findOccurrences(null, target));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void shouldTesfindOccurrences_nullTarget_throwsException() {
|
||||
assertThrows(IllegalArgumentException.class, () -> finder.findOccurrences(students, null));
|
||||
}
|
||||
@Test
|
||||
void shouldTesfindOccurrences_resultIsSorted() {
|
||||
String[] validGroups = {"A00", "A01", "B12", "C99", "X55"};
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
String group = validGroups[i % validGroups.length];
|
||||
double grade = (3.0 + (i % 3)) / 2.0;
|
||||
if (i % 3 == 0) {
|
||||
|
||||
students.add(new Student("A12", 4.5, 101));
|
||||
} else {
|
||||
students.add(new Student(group, grade, 200 + i));
|
||||
}
|
||||
}
|
||||
Student target = new Student("A12", 4.5, 101);
|
||||
int[] result = finder.findOccurrences(students, target);
|
||||
|
||||
|
||||
for (int i = 1; i < result.length; i++) {
|
||||
assertTrue(result[i] > result[i - 1], "Результат должен быть отсортирован");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user