Oczekiwano, że czas działania Array#shift
i Array#unshift
będzie równy Θ(n)
. Powodem jest to, że maszyna musi przechodzić przez każdy element tablicy i przypisywać go do klucza w lewo lub w prawo do niego.Czas pracy Array # unshift vs Array # shift
W przypadku Array#unshift
, zakładając, że tylko jedna wartość jest przekazywana jako argument i jest wiele elementów tablicy, założyłem, że przypisanie wartości dla array[0]
nie ma znaczącego wpływu na czas działania. Innymi słowy, gdy liczba elementów macierzy jest wysoka, a liczba zmiennych przekazywanych do Array#unshift
jest niska, oczekiwałem, że Array#shift
i Array#unshift
będą miały taki sam czas działania.
Podczas wykonywania testów porównawczych w Ruby 2.1.2 te założenia nie są prawdziwe. Czemu?
Kod:
require 'benchmark'
GC.disable
number_of_elements = 25_600_000
a1 =[]
a2 = []
a3 = []
a4 = []
q1 = Queue.new
q2 = Queue.new
puts number_of_elements
number_of_elements.times do
q1.enq(true)
q2.enq(true)
a1 << true
a2 << true
a3 << true
a4 << true
end
number_of_operations = 1
Benchmark.bm do |bm|
puts "Queue#enq('test')"
bm.report do
number_of_operations.times { q1.enq('test') }
end
puts "Queue#deq"
bm.report do
number_of_operations.times { q2.deq }
end
puts "Array#shift"
bm.report do
number_of_operations.times { a1.shift }
end
puts "Array#unshift"
bm.report do
number_of_operations.times { a2.unshift('test') }
end
puts "Array#pop"
bm.report do
number_of_operations.times { a3.pop }
end
puts "Array#<<"
bm.report do
number_of_operations.times { a4 << 'test' }
end
end
Wynik:
25600000
user system total real
Queue#enq('test')
0.000000 0.000000 0.000000 ( 0.000006)
Queue#deq
0.010000 0.020000 0.030000 ( 0.029928)
Array#shift
0.010000 0.020000 0.030000 ( 0.032203)
Array#unshift
0.080000 0.060000 0.140000 ( 0.143272)
Array#pop
0.000000 0.000000 0.000000 ( 0.000004)
Array#<<
0.000000 0.000000 0.000000 ( 0.000007)
Co stanie się, jeśli zwiększysz liczbę operacji? – Ajedi32
#[email protected]: 0.016307, #[email protected]: 0.059878, # shift @ 64m: 0.098583, # shift @ 128m: 0.344900. #[email protected]: 0.059736, #[email protected]: 0.126382, # unshift @ 64m: 0.285351, # unshift @ 128m: 0.993967. Porównując tylko te proporcje, wydaje się, że #shift działa przy Θ (3,4n) i #unshift lekko wykładniczo. – migu
Czy zapoznałeś się z kodem źródłowym Ruby, aby zrozumieć, w jaki sposób implementowane są tablice i jak działa 'shift' /' unshift'? Istnieje wiele rzeczy, które mogą zaistnieć za kulisami, które spowodują zmętnienie twoich wyników. Dodanie elementu do początku tablicy niekoniecznie przydzieli pojedynczą nową pozycję dla tablicy, może przydzielić wiele lub po prostu przesunie wskaźnik tablicy startów; podobnie, 'shift'ing element może po prostu zaktualizować wskaźnik, aby wskazywał na nowy adres indeksu-0. –