Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implemented quicksort and quicksort for visual list #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
gem 'minitest'
51 changes: 51 additions & 0 deletions examples/quick.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env ruby
#
# Classsic quick sort
#
require_relative '../visual_list'

def partition(arr, start_idx, end_idx)
# pick middle point between start and end
pivot = (end_idx - start_idx) / 2 + start_idx

target = arr[pivot]

idx = start_idx
while idx <= end_idx do
if idx < pivot
# move value if > target. keep idx the same, subtract 1 from pivot. move to pivot + 1
if arr[idx] > target
arr.move(idx, pivot)
pivot -= 1
else
idx += 1
end
elsif idx > pivot
# move value if < target. keep idx the same, add 1 to pivot. move to pivot - 1
if arr[idx] < target
arr.move(idx, pivot)
pivot += 1
else
idx += 1
end
else
idx += 1
end

end
pivot
end

def quicksort(arr, start_idx, end_idx)
if (end_idx - start_idx) > 0
p = partition(arr, start_idx, end_idx)
quicksort(arr, start_idx, p - 1)
quicksort(arr, p + 1, end_idx)
end
end

#v = VisualList.new(generator: :linear, count: 35)
v = VisualList.new(values: [3,2,5,7,1,4,10,21,6,8])
quicksort(v, 0, v.last_index)

v.sorted!
45 changes: 45 additions & 0 deletions quick_sort.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
def move(arr, source_index, destination_index)
arr.insert(destination_index, arr.delete_at(source_index))
end


def partition(arr, start_idx, end_idx)
# pick middle point between start and end
pivot = (end_idx - start_idx) / 2 + start_idx

target = arr[pivot]

idx = start_idx
while idx <= end_idx do
if idx < pivot
# move value if > target. keep idx the same, subtract 1 from pivot. move to pivot + 1
if arr[idx] > target
move(arr, idx, pivot)
pivot -= 1
else
idx += 1
end
elsif idx > pivot
# move value if < target. keep idx the same, add 1 to pivot. move to pivot - 1
if arr[idx] < target
move(arr, idx, pivot)
pivot += 1
else
idx += 1
end
else
idx += 1
end

end
pivot
end

def quicksort(arr, start_idx, end_idx)
if (end_idx - start_idx) > 0
p = partition(arr, start_idx, end_idx)
quicksort(arr, start_idx, p - 1)
quicksort(arr, p + 1, end_idx)
end
arr
end
59 changes: 59 additions & 0 deletions test_quick_sort.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
require 'minitest/autorun'
require 'minitest/spec'
require './quick_sort'

class TestQuickSort < MiniTest::Spec
def test_sort_single_item_array_returns_identity
source_array = [1]
retval = quicksort(source_array, 0, 0)
assert_equal(source_array, retval)
end

def test_two_item_array_already_sorted_returns_identity
source_array = [1,4]
retval = quicksort(source_array, 0, 1)
assert_equal(source_array, retval)
end

def test_two_item_array_unsorted_returns_sorted_array
source_array = [5,4]
retval = quicksort(source_array, 0, 1)
assert_equal(source_array.sort, retval)
end

def test_three_item_array_unsorted_returns_sorted_array
source_array = [5,4,1]
retval = quicksort(source_array, 0, source_array.length - 1)
assert_equal(source_array.sort, retval)
end

def test_arbitrary_item_array_unsorted_returns_sorted_array
source_array = [3,2,5,7,1,4,10,21,6,8]
retval = quicksort(source_array, 0, source_array.length - 1)
assert_equal(source_array.sort, retval)
end

def test_randomly_generated_unsorted_arrays_returns_sorted_array
(1..5000).each do
source_array = rand(50).times.map {rand(20)}
retval = quicksort(source_array, 0, source_array.length - 1)

if retval != source_array.sort
puts source_array.inpsect
end
assert_equal(source_array.sort, retval)
end
end

def test_failing_array
source_array = [0, 1, 1, 1, 1, 1, 2, 1, 2, 3, 3, 4, 3, 4, 5, 6, 7, 7, 7, 8, 8, 9, 13, 9, 13, 13, 13, 14, 14, 15, 16, 15, 16, 17, 17, 17, 17, 17, 18, 18]
retval = quicksort(source_array, 0, source_array.length - 1)

if retval != source_array.sort
puts source_array.inpsect
end
assert_equal(source_array.sort, retval)
end


end
35 changes: 35 additions & 0 deletions test_visual_list.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require 'minitest/autorun'
require 'minitest/spec'
require './examples/quick'


class TestVisualList < MiniTest::Spec
def test_obj_valid
v = VisualList.new(values: [3,2,5,7,1,4,10,21,6,8], delay: 0)
assert(v.is_a? VisualList)
end

def test_simple_sort_works
v = VisualList.new(values: [3,2,5,7,1,4,10,21,6,8], delay: 0)
quicksort(v, 0, v.last_index)
end

def test_random_sort
(1..50).each do
arr = source_array = rand(50).times.map {rand(20)}
next if arr.length < 8
v = VisualList.new(values: arr, delay: 0)
quicksort(v, 0, v.last_index)

v.sorted!
end
end

def test_failing_sort
arr = [0, 1, 1, 1, 1, 1, 2, 1, 2, 3, 3, 4, 3, 4, 5, 6, 7, 7, 7, 8, 8, 9, 13, 9, 13, 13, 13, 14, 14, 15, 16, 15, 16, 17, 17, 17, 17, 17, 18, 18]
v = VisualList.new(values: arr, delay: 0)
quicksort(v, 0, v.last_index)
v.sorted!
end

end
44 changes: 35 additions & 9 deletions visual_list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,24 @@ class VisualList
# - :random - random values from minimum to maximum. Duplicates possible.
# - :linear - 1 to count in random order. No duplicates. Default.
# - :reversed - count down to 1 in descending order. No duplicates.
def initialize(count: 10, generator: :linear, minimum: 1, maximum: nil, delay: 0.1)
@count = count.to_i.abs
@reads = 0
@swaps = 0
@generator = generator
@delay = delay
@minimum = minimum.to_i.abs
@maximum = (maximum || count).to_i.abs
@values = self.send("generator_#{@generator}")
def initialize(count: 10, generator: :linear, minimum: 1, maximum: nil, delay: 0.1, values: nil)
@reads = 0
@swaps = 0
@delay = delay

if values
@count = values.length
@values = values
else
@count = count.to_i.abs
@generator = generator
@delay = delay
@minimum = minimum.to_i.abs
@maximum = (maximum || count).to_i.abs
@values = self.send("generator_#{@generator}")
end
@largest_value = @values.inject{|a,b| b > a ? a = b : a }

clear_screen
display_list
end
Expand All @@ -39,6 +47,21 @@ def get(index)
@values[index]
end
alias :[] :get

# move a value in the array to another location
# returns true if success, raises exception if arguments are out of bounds
def move(source_index, destination_index)
[source_index, destination_index].each do |index|
in_bounds!(index)
end

display_list(swap_index_a: source_index, swap_index_b: destination_index)

@values.insert(destination_index, @values.delete_at(source_index))
@swaps += 1

display_list(swap_index_a: source_index, swap_index_b: destination_index)
end

# Swap the values of two index locations. Returns true if operation is
# successful. Raises exception of either argument is our of list bounds.
Expand Down Expand Up @@ -68,6 +91,7 @@ def sorted!
puts "Success! List is sorted!"
true
else
puts @values.inspect
raise "Sorry, list has not been sorted."
end
end
Expand Down Expand Up @@ -140,4 +164,6 @@ def generator_linear
def generator_reversed
@count.downto(1).map{|i| i }
end


end