From 415da099dd967606a16ca376c26408b84aeff3ab Mon Sep 17 00:00:00 2001 From: Arthur Date: Thu, 20 Feb 2020 14:21:57 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=B4=D0=B0=20=D1=8D=D1=84=D1=84=D0=B5=D0=BA=D1=82=D0=B8=D0=B2?= =?UTF-8?q?=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B0=D0=BB=D0=B3=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D1=82=D0=BC=D0=B0=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BD=D0=B5=D1=81=D0=BA=D0=BE=D0=BB=D1=8C=D0=BA=D0=B8?= =?UTF-8?q?=D1=85=20=D1=80=D1=8F=D0=B4=D0=BE=D0=BC=20=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=8F=D1=89=D0=B8=D1=85=20=D1=8D=D0=BB=D0=B5=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=20=D0=B8=D0=B7=20=D1=81=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=B4=D0=B8=D0=BD=D1=8B=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0?= =?UTF-8?q?,=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D1=83=D0=B5=D0=BC?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20ArrayList.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jcf.md | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/jcf.md b/jcf.md index 431eec8..db0fe2d 100644 --- a/jcf.md +++ b/jcf.md @@ -314,6 +314,114 @@ _O(N)_. Вставка элемента в конец списка осущес ## Предложите эффективный алгоритм удаления нескольких рядом стоящих элементов из середины списка, реализуемого `ArrayList`. Допустим нужно удалить `n` элементов с позиции `m` в списке. Вместо выполнения удаления одного элемента `n` раз (каждый раз смещая на 1 позицию элементы, стоящие «правее» в списке), нужно выполнить смещение всех элементов, стоящих «правее» `n + m` позиции на `n` элементов «левее» к началу списка. Таким образом, вместо выполнения `n` итераций перемещения элементов списка, все выполняется за 1 проход. +Пример: + +```java +package test1; + +import java.io.*; +import java.util.ArrayList; + +public class Main { + //позиция с которой удаляем + private static int m = 0; + //количество удаляемых элементов + private static int n = 0; + //количество элементов в списке + private static final int size = 1000000; + //основной список (для удаления вызовом remove() и его копия для удаления путём перезаписи) + private static ArrayList initList, copyList; + + public static void main(String[] args){ + + initList = new ArrayList<>(size); + for (int i = 0; i < size; i++) + initList.add(i); + System.out.println("Список из 1.000.000 элементов заполнен"); + + copyList = new ArrayList<>(initList); + System.out.println("Создана копия списка\n"); + + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + try{ + System.out.print("С какой позиции удаляем? > "); + m = Integer.parseInt(br.readLine()); + System.out.print("Сколько удаляем? > "); + n = Integer.parseInt(br.readLine()); + } catch(IOException e){ + System.err.println(e.toString()); + } + System.out.println("\nВыполняем удаление вызовом remove()..."); + long start = System.currentTimeMillis(); + + for (int i = m - 1; i < m + n - 1; i++) + initList.remove(i); + + long finish = System.currentTimeMillis() - start; + System.out.println("Время удаления с помощью вызова remove(): " + finish); + System.out.println("Размер исходного списка после удаления: " + initList.size()); + + System.out.println("\nВыполняем удаление путем перезаписи...\n"); + start = System.currentTimeMillis(); + + removeEfficiently(); + + finish = System.currentTimeMillis() - start; + System.out.println("Время удаления путём смещения: " + finish); + System.out.println("Размер копии списка:" + copyList.size()); + } + + private static void removeEfficiently(){ + /* если необходимо удалить все элементы, начиная с указанного, + * то удаляем элементы с конца до m + */ + if (m + n >= size){ + int i = size - 1; + while (i != m - 1){ + copyList.remove(i); + i--; + } + } else{ + //переменная k необходима для отсчёта сдвига начиная от места вставка m + for (int i = m + n, k = 0; i < size; i++, k++) + copyList.set(m + k, copyList.get(i)); + + /* удаляем ненужные элементы в конце списка + * удаляется всегда последний элемент, так как время этого действия + * фиксировано и не зависит от размера списка + */ + int i = size - 1; + while (i != size - n - 1){ + copyList.remove(i); + i--; + } + //сокращаем длину списка путём удаления пустых ячеек + copyList.trimToSize(); + } + } +} +``` + +Результат выполнения: +``` +run: +Список из 1.000.000 элементов заполнен +Создана копия списка + +С какой позиции удаляем? > 600000 +Сколько удаляем? > 20000 + +Выполняем удаление вызовом remove()... +Время удаления с помощью вызова remove(): 22359 +Размер исходного списка после удаления: 980000 + +Выполняем удаление путем перезаписи... + +Время удаления путём смещения: 62 +Размер копии списка:980000 +СБОРКА УСПЕШНО ЗАВЕРШЕНА (общее время: 33 секунды) +``` + [к оглавлению](#java-collections-framework) ## Сколько необходимо дополнительной памяти при вызове `ArrayList.add()`?