Skip to content

Commit 05cb2f0

Browse files
committed
task1 solution
1 parent 49c32ce commit 05cb2f0

File tree

1 file changed

+160
-13
lines changed

1 file changed

+160
-13
lines changed
Lines changed: 160 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
1-
# Design a data type that supports:
2-
3-
# - insert in logarithmic time
4-
# - find-the-median in constant time
5-
# - remove-the-median in logarithmic time
6-
7-
# If the number of keys in the data type is even, find/remove the lower median.
8-
9-
class MedianStruct
1+
class MedianStructBaseline
102
attr_reader :array
113

12-
def initialize(array)
13-
@array = array.sort
4+
def initialize
5+
@array = []
146
end
157

168
def insert(n)
@@ -19,10 +11,165 @@ def insert(n)
1911
end
2012

2113
def median
22-
array[array.size / 2]
14+
array[median_i]
2315
end
2416

2517
def remove_median
26-
array.delete_at(array.size / 2)
18+
array.delete_at(median_i)
19+
end
20+
21+
private def median_i
22+
(array.size - 1) / 2
2723
end
2824
end
25+
26+
class Heap
27+
attr_reader :arr, :type
28+
29+
def initialize(type)
30+
@arr = []
31+
@type = type
32+
end
33+
34+
def push(value)
35+
i = arr.size
36+
arr << value
37+
parent_i = (i - 1) / 2
38+
39+
while i > 0 && cmp(arr[i], arr[parent_i])
40+
swap(i, parent_i)
41+
i = parent_i
42+
parent_i = (i - 1) / 2
43+
end
44+
end
45+
46+
def top
47+
arr.first
48+
end
49+
50+
def pop
51+
value = arr[0]
52+
last = arr.pop
53+
unless arr.empty?
54+
arr[0] = last
55+
heapify!(0)
56+
end
57+
value
58+
end
59+
60+
def length
61+
arr.size
62+
end
63+
64+
private def heapify!(i)
65+
loop do
66+
left_child = 2 * i + 1
67+
right_child = 2 * i + 2
68+
top_child = i
69+
70+
top_child = left_child if left_child < arr.size && cmp(arr[left_child], arr[top_child])
71+
top_child = right_child if right_child < arr.size && cmp(arr[right_child], arr[top_child])
72+
73+
break if top_child == i
74+
75+
swap(i, top_child)
76+
i = top_child
77+
end
78+
end
79+
80+
private def cmp(a, b)
81+
type == :max ? a > b : a < b
82+
end
83+
84+
private def swap(i, j)
85+
arr[i], arr[j] = arr[j], arr[i]
86+
end
87+
end
88+
89+
class MedianStruct
90+
attr_reader :min_heap, :max_heap, :median
91+
92+
def initialize
93+
@min_heap = Heap.new(:min) # all elements are greater than median
94+
@max_heap = Heap.new(:max) # all elements are smaller than median
95+
@median = nil
96+
end
97+
98+
# insert in logarithmic time
99+
def insert(n)
100+
if median.nil?
101+
@median = n
102+
elsif n < median
103+
if max_heap.length < min_heap.length
104+
max_heap.push(n)
105+
elsif max_heap.top && n < max_heap.top
106+
min_heap.push(median)
107+
@median = max_heap.pop
108+
max_heap.push(n)
109+
else
110+
min_heap.push(median)
111+
@median = n
112+
end
113+
elsif n > median
114+
if min_heap.length <= max_heap.length
115+
min_heap.push(n)
116+
elsif n > min_heap.top
117+
max_heap.push(median)
118+
@median = min_heap.pop
119+
min_heap.push(n)
120+
else
121+
max_heap.push(median)
122+
@median = n
123+
end
124+
else # n == median
125+
if max_heap.length <= min_heap.length
126+
max_heap.push(n)
127+
else
128+
min_heap.push(n)
129+
end
130+
end
131+
end
132+
133+
# find-the-median in constant time
134+
attr_reader :median
135+
136+
# remove-the-median in logarithmic time
137+
def remove_median
138+
if max_heap.length >= min_heap.length
139+
@median = max_heap.pop
140+
else
141+
@median = min_heap.pop
142+
end
143+
end
144+
end
145+
146+
147+
base = MedianStructBaseline.new
148+
struct = MedianStruct.new
149+
150+
100.times do |x|
151+
n = rand(100)
152+
153+
base.insert(n)
154+
struct.insert(n)
155+
156+
unless base.median == struct.median
157+
puts "x#{x} | ERROR: base.median = #{base.median}, struct.median = #{struct.median}"
158+
159+
p [base.median, base.array]
160+
p [struct.median, struct.max_heap.arr, struct.min_heap.arr]
161+
exit
162+
end
163+
end
164+
165+
100.times do |y|
166+
base.remove_median
167+
struct.remove_median
168+
169+
unless base.median == struct.median
170+
puts "y#{y} | ERROR: base.median = #{base.median}, struct.median = #{struct.median}"
171+
exit
172+
end
173+
end
174+
175+
puts "OK"

0 commit comments

Comments
 (0)