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

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

Related

Where is the bug in my bubble sort code?

I see that there are better ruby bubble sort codes already posted in places such as here:
Using the Bubble sort method for an array in Ruby
But I am having trouble debugging my current code and would appreciate some help with figuring out why my code does not work. Thanks.
def bubble_sort(arr)
original = arr
x = 0
while x < arr.count - 1
if arr[x] < arr[x + 1]
y = arr[x + 1]
arr[x + 1] = arr[x]
arr[x] = y
end
x += 1
end
if original == arr
return arr
else
return bubble_sort(arr)
end
end
One of the problems is this:
original = arr
You expect original to a copy of arr in its current state, right? Well, no. They will point to the same array. That's why your function will never recurse here:
if original == arr
return arr
else
return bubble_sort[arr]
end
To copy the array, use dup
original = arr.dup
Four issues :
bubble_sort[arr] does not work - you should call bubble_sort(arr)
original == arr - will always be true, since you assigned it to arr before - you should have assigned it using dup - original = arr.dup
arr[x] < arr [x+1] will create an array sorted in reverse order...
you should change the local copy rather than the one you got as parameters - result = arr.dup rather than original = arr.dup
The code after the above fixes:
def bubble_sort(arr)
result = arr.dup
x = 0
while x < result.count - 1
if result[x] > result[x + 1]
y = result[x + 1]
result[x + 1] = result[x]
result[x] = y
end
x += 1
end
if arr == result
return result
else
return bubble_sort(result)
end
end
bubble_sort([1,3,5,2,4])
# => [1, 2, 3, 4, 5]

Heapsort implementation only nearly sorts array

I've been trying to implement heapsort in Ruby, but thus far, my algorithm only sorts like 90% of the array correctly and not the rest. Can anyone see what goes wrong?
This is my code
require 'pp'
def left(i)
(i+1)*2-1
end
def right(i)
(i+1)*2
end
def max_heapify(a, root)
left, right = left(root), right(root)
max = root
if left < a.length and a[left] > a[max]
max = left
end
if right < a.length and a[right] > a[max]
max = right
end
if max != root
a[root], a[max] = a[max], a[root]
max_heapify(a, max)
else
a
end
end
def build_max_heap(a)
((a.size-1)/2).downto(0) do |i|
max_heapify(a, i)
end
a
end
def heap_sort(a)
len = a.size
build_max_heap(a)
(len-1).downto(0) do |i|
a[0], a[i] = a[i], a[0]
a.delete_at(len)
max_heapify(a, 0)
end
a
end
a = (1..10).to_a.shuffle
pp heap_sort(a)
result: [10, 9, 7, 8, 6, 2, 4, 5, 1, 3]
During the sort, when you move the max element to the end, don't touch it anymore, it is
sorted and the array to sort (and the heap) should end just before it.
You need one more parameter to max_heapify, to tell where the heap ends, it's not the
end of the array.
require 'pp'
def left(i)
i*2+1
end
def right(i)
i*2+2
end
def max_heapify(a, root, len)
left, right = left(root), right(root)
max = root
if left < len and a[left] > a[max]
max = left
end
if right < len and a[right] > a[max]
max = right
end
if max != root
a[root], a[max] = a[max], a[root]
max_heapify(a, max, len)
else
a
end
end
def build_max_heap(a)
((a.size-1)/2).downto(0) do |i|
max_heapify(a, i, a.length)
end
a
end
def heap_sort(a)
len = a.size
build_max_heap(a)
(len-1).downto(0) do |i|
a[0], a[i] = a[i], a[0]
max_heapify(a, 0, i)
end
a
end
a = (1..10).to_a.shuffle
pp heap_sort(a)
PP. Not sure what delete_at does (don't know Ruby), but I strongly suspect it's not
needed, during a sort you don't "delete" anything from the array, you just rearrange elements.

Need to make this more Ruby-like

I'm new to Ruby and I seem to be comfortable using while loops. But I would like to simplify my code by possibly using the 'each' method. How would I do this for this particular block of code?
sum_array = []
i = 0
while i < array.length - 1
j = i + 1
while j < array.length
sum = array[i] + array[j]
if sum != 0
sum_array << sum
end
j += 1
end
i += 1
end
sum_array = array.combination(2).map{|n, m| n + m}.reject(&:zero?)
array = (1..10).to_a # test array [1,2,3,4,....10]
sum_array = []
(0...array.length).each do |i| # from 0 to array.length-1
(i+1...array.length).each do |j| # from i+1 to array.length-1
sum = array[i] + array[j]
sum_array << sum unless sum == 0 # brief condition
end
end
def sum_array(input)
[].tap do |sums|
input.each_with_index do |x, index|
tail = input[index.next..-1]
tail.each do |y|
sum = x + y
sums << sum unless sum.zero?
end
end
end
end
puts sum_array([1,2,0,0])
# => [3,1,1,2,2]
You could do this:
sum_array = []
array.each_index do |i|
sum_array += (i+1...array.length).collect { |j| array[i] + array[j] }
end
sum_array.reject!(&:zero?)

How do I write a merge sort?

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

Sorting an Array in Ruby without using Sort method

I'm trying to use the bubble sort method to sort an array of only three numbers. The code I'm using is below.
def my_sort(list)
return list if list.size <= 1
swapped = false
while !swapped
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]
swapped = true
end
end
list
end
my_sort([3,1,2])
Here is the error message I keep getting:
Syntax error, unexpected $end, expecting keyword_end
I was just wondering which end shouldn't be included?
You're missing an end after swapped = true. It would be best to indent your code thoroughly and accurately to avoid this kind of problem:
def my_sort(list)
return list if list.size <= 1
swapped = false
while !swapped
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]
swapped = true
end
end
end
list
end
You're missing an end
if list[i] > list[i+1]
list[i], list[i+1] = list[i+1], list[i]
swapped = true
end # <--------------------------------------------------------
Edit:
As the other answer mentions, indent your code to make these errors more visible.
This looks a better and quicker one.
arr = [1,5,7,2,3,50,78,34, 1, 15, 89, 8]
def sort_array(arr)
arr.size.times do
arr.map.with_index do |num, index|
next if index.eql?(arr.size - 1)
arr[index], arr[index+1] = arr[index+1], arr[index] if num > arr[index+1]
end
end
end
Call the above method as print sort_array(arr) to get expected result.
Your code works for that specific array. Because your loop is looking if the next element is higher, then swipe. But what about more elements in the array? This is recursive solution for all cases.
def my_sort(list, new_array = nil)
return new_array if list.size <= 0
if new_array == nil
new_array = []
end
min = list.min
new_array << min
list.delete(min)
my_sort(list, new_array)
end
puts my_sort([3, 1, 2, 20, 11, 14, 3, 6, 8, 5])
What worked for me, is below.
def my_sort(list)
n = list.length
loop do
swapped = false
(n-1).times do |i|
if list[i] > list[i+1]
list[i], list[i+1] = list[i+1], list[i]
swapped = true
end
end
break if not swapped
end
list
end
def sort(arr)
arr_len = arr.length - 1
swap = true
while swap
swap = false
arr_len.times do |i|
if arr[i] > arr[i+1]
arr[i],arr[i + 1] = arr[i + 1],arr[i]
swap = true
end
end
end
p arr
end
arr = [1,2,8,4,5,3,1,0,6]
0.upto(arr.size - 1) do |i|
(i+1).upto(arr.size - 1) do |j|
if arr[i] > arr[j]
arr[j],arr[i] = arr[i],arr[j]
end
end
end
#Using bubble sort algorithm in ruby
a = [1,5,7,2,3,50,78,34,89]
a.size.times.each do |t|
i=0
a.each do |b|
if b > a[i+1]
a[i],a[i+1] = a[i+1],a[i]
end
i+=1 if i < a.size-2
end
end
print a
#output: [1, 2, 3, 5, 7, 34, 50, 78, 89]

Resources