mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
array.c: replace sort! method implementation
- use heap sort (O(1)) instead of merge sort (O(n)) for better space complexity. - method implemented in C for better performance As a result, simple sorting now consumes far less memory and is faster. Since it's implemented in C, fiber context switching is not allowed from comparison, but we consider the risk is minimal (no one switches context in the comparison, right?)
This commit is contained in:
@@ -198,78 +198,6 @@ class Array
|
||||
ret
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# array.sort! -> self
|
||||
# array.sort! {|a, b| ... } -> self
|
||||
#
|
||||
# Sort all elements and replace +self+ with these
|
||||
# elements.
|
||||
def sort!(&block)
|
||||
stack = [ [ 0, self.size - 1 ] ]
|
||||
until stack.empty?
|
||||
left, mid, right = stack.pop
|
||||
if right == nil
|
||||
right = mid
|
||||
# sort self[left..right]
|
||||
if left < right
|
||||
if left + 1 == right
|
||||
lval = self[left]
|
||||
rval = self[right]
|
||||
cmp = if block then block.call(lval,rval) else lval <=> rval end
|
||||
if cmp.nil?
|
||||
raise ArgumentError, "comparison of #{lval.inspect} and #{rval.inspect} failed"
|
||||
end
|
||||
if cmp > 0
|
||||
self[left] = rval
|
||||
self[right] = lval
|
||||
end
|
||||
else
|
||||
mid = ((left + right + 1) / 2).floor
|
||||
stack.push [ left, mid, right ]
|
||||
stack.push [ mid, right ]
|
||||
stack.push [ left, (mid - 1) ] if left < mid - 1
|
||||
end
|
||||
end
|
||||
else
|
||||
lary = self[left, mid - left]
|
||||
lsize = lary.size
|
||||
|
||||
# The entity sharing between lary and self may cause a large memory
|
||||
# copy operation in the merge loop below. This harmless operation
|
||||
# cancels the sharing and provides a huge performance gain.
|
||||
lary[0] = lary[0]
|
||||
|
||||
# merge
|
||||
lidx = 0
|
||||
ridx = mid
|
||||
(left..right).each { |i|
|
||||
if lidx >= lsize
|
||||
break
|
||||
elsif ridx > right
|
||||
self[i, lsize - lidx] = lary[lidx, lsize - lidx]
|
||||
break
|
||||
else
|
||||
lval = lary[lidx]
|
||||
rval = self[ridx]
|
||||
cmp = if block then block.call(lval,rval) else lval <=> rval end
|
||||
if cmp.nil?
|
||||
raise ArgumentError, "comparison of #{lval.inspect} and #{rval.inspect} failed"
|
||||
end
|
||||
if cmp <= 0
|
||||
self[i] = lval
|
||||
lidx += 1
|
||||
else
|
||||
self[i] = rval
|
||||
ridx += 1
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# array.sort -> new_array
|
||||
|
||||
Reference in New Issue
Block a user