Sobes.tech
Middle

Какво е по-добре да използвате: ArrayList или LinkedList, ако искам да изтрия елемент от средата на списъка?

sobes.tech AI

Отговор от AI

ArrayList.

При изтриване на елемент от средата на списъка:

  • ArrayList: Изисква преместване на всички последващи елементи, което в най-лошия случай (при изтриване на първия елемент) отнема време $O(n)$, където $n$ е броят на елементите. Средно обаче операцията остава $O(n)$, тъй като трябва да се премести само половината от елементите. Фактическата производителност често е по-добра поради по-добрата локализация на данните.
  • LinkedList: Изисква итерация през елементите до намиране на необходимия възел ($O(n)$ в най-лошия случай, ако започва от началото или края). След намиране на възела, изтриването отнема $O(1)$.

Въпреки че самото изтриване на възела в LinkedList е по-бързо, търсенето на възела преди изтриването прави цялостната операция средно по-бавна, отколкото в ArrayList.

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class ListRemovalComparison {

    public static void main(String[] args) {
        int size = 100000; // Размер на списъка
        int removeIndex = size / 2; // Индекс за изтриване (средата)

        // ArrayList
        List<Integer> arrayList = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            arrayList.add(i);
        }

        long startTimeArrayList = System.nanoTime();
        arrayList.remove(removeIndex); // Изтриване от средата
        long endTimeArrayList = System.nanoTime();
        long durationArrayList = (endTimeArrayList - startTimeArrayList);

        System.out.println("Време за изтриване от ArrayList: " + durationArrayList + " ns");

        // LinkedList
        List<Integer> linkedList = new LinkedList<>();
        for (int i = 0; i < size; i++) {
            linkedList.add(i);
        }

        long startTimeLinkedList = System.nanoTime();
        linkedList.remove(removeIndex); // Изтриване от средата
        long endTimeLinkedList = System.nanoTime();
        long durationLinkedList = (endTimeLinkedList - startTimeLinkedList);

        System.out.println("Време за изтриване от LinkedList: " + durationLinkedList + " ns");
    }
}

Резултатите показват, че при изтриване на елемент от средата, ArrayList обикновено е по-бърз, въпреки теоретичната сложност на преместването. Това се дължи на факта, че търсенето по индекс в LinkedList ($O(n)$) е по-бавно, отколкото преместването в ArrayList.

// ArrayList - достъп по индекс O(1), изтриване O(n) (преместване)
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("A");
arrayList.add("B");
arrayList.add("C");
arrayList.remove(1); // Изтриване на "B" - преместване на "C"

// LinkedList - достъп по индекс O(n), изтриване O(1) (след намиране на възела)
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("A");
linkedList.add("B");
linkedList.add("C");
linkedList.remove(1); // Изтриване на "B" - първо трябва да се намери възелът "B" (O(n)), след това да се изтрие (O(1))

В крайна сметка, за операцията изтриване от средата, ако знаете индекса, ArrayList често е по-подходящ избор поради по-бързата операция за достъп по индекс, което компенсира разходите за преместване.