@kofon
Я человек

Java. Как работает Random и remove в Queue?

Что, собственно говоря, стряслось...
Происходит какая-то нелепость.

Создаю очередь (PriorityQueue) и добавляю в неё значения.
1. Добавляю случайные числа (Random)
2. Добавляю константное выражение

и удаляю первый элемент в очереди (remove(0)).

В первом случае удаление происходит за 40-60 микросекунд, во втором в почти миллисекунда, что в 500 раз больше

Пожалуйста, не поленитесь глянуть на код (или хотя бы скопировать к себе).
private static final int COUNT = 1000000;

	public static void main(String[] args) {
		
		Random rand = new Random();
		
		Queue<Integer> arr = new PriorityQueue<Integer>();

		for (int i = 0; i < COUNT; i++)
			arr.add(rand.nextInt(100));               // заносим значения

		long before = System.nanoTime();			            // до
		arr.remove(0);	                              // удаляем первый элемент
		long total = System.nanoTime() - before;	    // после
		
		System.out.println("Microsecond: " + total / 1000);
	}
Клик сюда!!! (фото)

Теперь, при добавлении меняем рандом на константные числа
// ...
        arr.add(100);
// ...
И сюда

Почему так происходит???
  • Вопрос задан
  • 3059 просмотров
Пригласить эксперта
Ответы на вопрос 3
Для работы PriorityQueue используется binary heap - это двоичное дерево, которое хранится определенном образом в линейном массиве. Корень дерева храниться в нулевом элементе, его дети - в следующих двух (1ом и 2ом), их дети - в следующих четырех.

После заполнения PriorityQueue в первом варианте, случайными числами, массив будет выглядить так
35ecb9d38da74a628579e45d5a83f891.png
Элементы со значением "0" с вероятностью 99% будут встречаться в первых 100 элементах массива.

Если заполнить PriorityQueue одним и тем же числом - то массив двоичной кучи будет таким

8b81d98250c840eaa6513b02bb10a5ae.png


Теперь посмотрим исходники метода remove

public boolean remove(Object o) {
       int i = indexOf(o);
       if (i == -1)
           return false;
        else {
            removeAt(i);
           return true;
       }
}

 private int indexOf(Object o) {
        if (o != null) {
            for (int i = 0; i < size; i++)
                if (o.equals(queue[i]))
                    return i;
        }
        return -1;
    }


Сначала ищется индекс элемента в массиве. Для этого используется проход по массиву.

В случае со случайными элементами придется просматривать в среднем 50 элементов пока не найдем элемента со значением "0", а при добавлении константы - все 1 000 000.
Ответ написан
@kofon Автор вопроса
Я человек
Кто-нибудь, протестите у себя, может быть у меня Java моросит...
Ответ написан
Комментировать
@Power
Ваша ошибка в том, что метод remove на самом деле принимает не индекс, а объект, т.е. вы удаляете не первый элемент, а пытаетесь удалить элемент, в котором записано значение 0. Почему операции занимают такое разное время, я думаю, вы уже сами догадаетесь.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы