How do I write a merge sort? - ruby

I am trying to implement a merge sort and am getting stack level too deep (SystemStackError) error when I run my code. I am not sure what the issue may be.
def merge_sort(lists)
lists if lists.count == 1
middle = lists[0..(lists.count / 2) - 1 ]
left = lists[0..middle.count - 1]
right = lists[middle.count..lists.count]
x = merge_sort(left)
y = merge_sort(right)
end
merge_sort [1,2,3,4,5,6,7,8]
Any help would be great!

From wikipedia:
def mergesort(list)
return list if list.size <= 1
mid = list.size / 2
left = list[0...mid]
right = list[mid...list.size]
merge(mergesort(left), mergesort(right))
end
def merge(left, right)
sorted = []
until left.empty? || right.empty?
if left.first <= right.first
sorted << left.shift
else
sorted << right.shift
end
end
sorted.concat(left).concat(right)
end

write this
return lists if lists.count == 1
instead of
lists if lists.count == 1
In Ruby, from a method last statement is always returned by default. But if you want to return from the middle of any lines except the last line conditionally, you must need to use return keyword explicitly.

A simplified version with comments
def merge_sort(arr)
# 0. Base case
return arr if arr.length <= 1
# 1. Divide
mid = arr.length / 2
arr0 = merge_sort(arr[0, mid])
arr1 = merge_sort(arr[mid, arr.length])
# 2. Conquer
output = merge(arr0, arr1)
end
def merge(l, r)
output = []
until l.empty? || r.empty?
output << if l.first <= r.first
l.shift
else
r.shift
end
end
# The order of `concat(l)` or `concat(r)` does not matters
output.concat(l).concat(r)
end
https://www.khanacademy.org/computing/computer-science/algorithms/merge-sort/a/divide-and-conquer-algorithms

This is a good way to do it. Tis a bit tricky at first, but stay at it.
def merge_sort list
if list.length <= 1
list
else
mid = (list.length / 2).floor
left = merge_sort(list[0..mid - 1])
right = merge_sort(list[mid..list.length])
merge(left, right)
end
end
def merge(left, right)
if left.empty?
right
elsif right.empty?
left
elsif left.first < right.first
[left.first] + merge(left[1..left.length], right)
else
[right.first] + merge(left, right[1..right.length])
end
end

Related

Quick sort created by Lua does not work correctly

I am a person who has been studying Lua recently. I am writing a QuickSort in Lua. I have translated the quick sort code that I wrote in Go language into Lua, and the code is below. Table.slice funcion defines the function used when making recursive calls in QuickSort.
function table.slice(tbl, first, last, step)
local sliced = {}
for i = first , last , step do
sliced[#sliced+1] = tbl[i]
end
return sliced
end
function quickSort(array)
if #array < 2 then
return array
end
local left = 1
local right = #array
local pivot = math.random( 1, #array )
array[pivot], array[right] = array[right], array[pivot]
for i = 1, #array do
if array[i] > array[right] then
array[left], array[i] = array[i], array[left]
left = left + 1
end
end
array[left], array[right] = array[right], array[left]
a = table.slice(array,1,left-1,1)
b = table.slice(array,left+1,#array,1)
quickSort(a)
quickSort(b)
return array
end
I initially thought that I made a mistake about Lua's table index starting at 1, but I could not tell where I was wrong. Could you tell me where I was wrong? Thank you.
I modified the code by modifying the given table directly by passing the range value as a parameter along with the comment, and posting the code for quick sort.
function quickSort(array, le, ri)
if ri-le < 1 then
return array
end
local left = le
local right = ri
local pivot = math.random( le, ri )
array[pivot], array[right] = array[right], array[pivot]
for i = le, ri do
if array[i] > array[right] then
array[left], array[i] = array[i], array[left]
left = left + 1
end
end
array[left], array[right] = array[right], array[left]
quickSort(array, 1, left-1)
quickSort(array, left +1, ri)
return array
end

How to create a bubble sort of a double-linked list for Ruby

I have been implementing a bubble sort for a doubly linked list:
def sort2(list) #bubble sort
for i in 0...list.length
for j in 0...list.length-1-i
if list.get(j+1)<list.get(j)
list.swap(j+1, j)
end
end
end
end
I don't have any idea how implement a bucket-sort. We can only use methods like:
get(i) - which return value of i element
swap(i, j) - which swaps two elements
length(list) - return length of list
This is the code for get, swap and length:
def swap(i,j)
if i > j
i, j = j, i
elsif j == i
return
end
tmp = nil
list = #ListE.next #first element
for it in 0...j
if i == it
tmp = list
end
list = list.next
end
tmp.v, list.v = list.v, tmp.v
end
def get(i)
a = #ListE
while i>0
a = a.next
i-=1
end
return a.next.v
end
def length()
list = #ListE.next
length_of_list = 0
while list.v != nil
length_of_list += 1
list = list.next
end
return length_of_list
end
This is my attempt at an insertion sort:
def sort3(list) #insertion sort
for i in 1...list.length
j = i
while j > 0 and list.get(j-1) > list.get(j)
list.swap(j-1, i)
j -= 1
end
end
end

How to use a block as method input

I am trying to create a method that uses bubble-sort to sort a small array into numerical order. This method accepts two arguments, an array and a method:
def bubble_sort_by(arr)
while(true)
counter = 0
for i in 0...(arr.size-1)
if yield (arr[i], arr[i+1]) > 0
saved = arr[i]
arr[i] = arr[i+1]
arr[i+1] = saved
counter += 1
end
end
if (counter == 0)
break
end
end
print arr
end
bubble_sort_by([4,3,78,2,0,2]) do |left,right|
return left - right
end
The sorted array should be
[0,2,2,3,4,78]
Currently I am using Ruby version 2.3.0p0.
I keep getting a syntax error when I try to run this code.
This is the fixed version:
def bubble_sort_by(arr)
while(true)
counter = 0
for i in 0...(arr.size-1)
if yield(arr[i], arr[i+1]) > 0
saved = arr[i]
arr[i] = arr[i+1]
arr[i+1] = saved
counter += 1
end
end
if (counter == 0)
break
end
end
print arr
end
bubble_sort_by([4,3,78,2,0,2]) do |left,right|
left - right
end
As you can see, it had two issues:
The space a yield - basically the space was extra because it wasn't passing the numbers in the parenthesis as arguments;
The return in the block - you do not want the block to explicitly return the value, you need it to be evaluated in bubble_sort_by and then its result used in the context there.

System Stack error doing the merge sort algorithm

Am doing the merge sort alg using recursion, which is probably the cause of the stack overflow. I have searched but can't seem to find out what part of the code is causing all of this.
Here's my code:
def merge(arr)
return arr if arr.length <= 1
mid = arr.length/2
x = arr[0..mid]
y = arr[mid..-1]
merge_sort(merge(x),merge(y))
end
def merge_sort(left, right)
sorted = []
while left.length > 0 && right.length > 0
if left.first > right.first
sorted << left.shift
else
sorted << right.shift
end
end
sorted.concat(left).concat(right)
end
nums = 15.times.map {rand(100) + 1}
puts merge(nums)
In the terminal I get: merge-sort.rb:2: Stack level too deep (SystemStackError)
In Ruby ... is endpoint exclusive, and .. is endpoint inclusive.
That means your x, and y both contains arr[mid] .
Change
x = arr[0..mid]
to
x = arr[0...mid]
and it should work.
See http://www.ruby-doc.org/core-2.1.5/Range.html

Using the Bubble sort method for an array in Ruby [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I'm trying to implement the Bubble sort method into an easy coding problem for Ruby, but I'm having some trouble. I understand the idea is to look at the value of the first element and compare it to the value of the second element and then swap them accordingly, but I can't seem to do it in an actual problem. Would anyone be willing to provide a brief example of how this might work in Ruby?
Correct implementation of the bubble sort with a while loop
def bubble_sort(list)
return list if list.size <= 1 # already sorted
swapped = true
while swapped do
swapped = false
0.upto(list.size-2) do |i|
if list[i] > list[i+1]
list[i], list[i+1] = list[i+1], list[i] # swap values
swapped = true
end
end
end
list
end
arr = [4,2,5,1]
loop until arr.each_cons(2).with_index.none?{|(x,y),i| arr[i],arr[i+1] = y,x if x > y}
p arr #=> [1, 2, 4, 5]
Source
def bubble_sort(list)
return list if list.size <= 1 # already sorted
loop do
swapped = false
0.upto(list.size-2) do |i|
if list[i] > list[i+1]
list[i], list[i+1] = list[i+1], list[i] # swap values
swapped = true
end
end
break unless swapped
end
list
end
Although I would certainly recommend something with a better run-time than bubblesort :)
Here's my version of the top answer. It calls size on the array only once instead of every loop. It doesn't compare elements once they have moved to the end of the array.
And the while loop quits one loop sooner. You're done once you've gone through the whole array and only did one swap, so no need to do another with 0 swaps.
def bubble_sort(list)
iterations = list.size - 2
return list unless iterations > 0 # already sorted
swaps = 2
while swaps > 1 do
swaps = 0
0.upto(iterations) do |i|
if list[i] > list[i + 1]
list[i], list[i + 1] = list[i + 1], list[i] # swap values
swaps += 1
end
end
iterations -= 1
end
list
end
Running this test takes 25% less time.
that_array = this_array = [22,66,4,44,5,7,392,22,8,77,33,118,99,6,1,62,29,14,139,2]
49.times {|variable| that_array = that_array + this_array}
bubble_sort that_array
Just re-writing #VanDarg's code to use a while loop
(note: code not tested... run at your own peril)
def bubble_sort(list)
return list if list.size <= 1 # already sorted
swapped = true
while swapped
swapped = false # maybe this time, we won't find a swap
0.upto(list.size-2) do |i|
if list[i] > list[i+1]
list[i], list[i+1] = list[i+1], list[i] # swap values
swapped = true # found a swap... keep going
end
end
end
list
end
Edit: updated swapped-values because bubble sort keeps sorting while there are still swaps being made - as soon as it finds no more swaps, it stops sorting. Note, this does not follow #Doug's code, but does conform with #cLuv's fix
def bubble_sort array
array.each do
swap_count = 0
array.each_with_index do |a, index|
break if index == (array.length - 1)
if a > array[index+1]
array[index],array[index+1] = array[index +1], array[index]
swap_count += 1
end
end
break if swap_count == 0 # this means it's ordered
end
array
end
The straight forward:
def bubble_sort(n)
return n if n.length <= 1
0.upto(n.length - 1) do |t|
0.upto(n.length - 2 - t) do |i|
if n[i] > n[i + 1]
n[i], n[i + 1] = n[i + 1], n[i]
end
end
end
n
end
If you don't want to use this funny swapping line (IMO):
arr[i], arr[j] = arr[j], arr[i]
here's my take:
def bubble_sort(arr)
temp = 0
arr.each do |i|
i = 0
j = 1
while (j < arr.length)
if arr[i] > arr[j]
temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
p arr
end
i+=1
j+=1
end
end
arr
end
Old school
def bubble_sort(random_numbers)
for i in 0..random_numbers.size
for j in i+1..random_numbers.size-1
random_numbers[i], random_numbers[j] = random_numbers[j], random_numbers[i] if(random_numbers[i] > random_numbers[j])
end
end
random_numbers
end
class Array
a = [6, 5, 4, 3, 2, 1]
n = a.length
for j in 0..n-1
for i in 0..n - 2 - j
if a[i]>a[i+1]
tmp = a[i]
a[i] = a[i+1]
a[i+1] = tmp
end
end
end
puts a.inspect
end
Here's my take using the operator XOR:
def bubble(arr)
n = arr.size - 1
k = 1
loop do
swapped = false
0.upto(n-k) do |i|
if arr[i] > arr[i+1]
xor = arr[i]^arr[i+1]
arr[i] = xor^arr[i]
arr[i+1] = xor^arr[i+1]
swapped = true
end
end
break unless swapped
k +=1
end
return arr
end
Another, slightly different naming.
def bubble_sort(list)
return list if list.size <= 1
not_sorted = true
while not_sorted
not_sorted = false
0.upto(list.size - 2) do |i|
if list[i] > list[i + 1]
list[i], list[i + 1] = list[i + 1], list[i]
not_sorted = true
end
end
end
list
end
def bubbleSort(list)
sorted = false
until sorted
sorted = true
for i in 0..(list.length - 2)
if list[i] > list[i + 1]
sorted = false
list[i], list[i + 1] = list[i + 1], list[i]
end
end
end
return list
end
Here is my code. I like using the (arr.length-1). For loops you can also use such iterations such as until, while, for, upto, loop do, etc. Fun to try different things to see how it functions.
def bubble_sort(arr) #10/17/13 took me 8mins to write it
return arr if arr.length <= 1
sorted = true
while sorted
sorted = false
(arr.length-1).times do |i|
if arr[i] > arr[i+1]
arr[i], arr[i+1] = arr[i+1], arr[i]
sorted = true
end
end
end
arr
end

Resources