您的位置:首页 > 编程语言 > Ruby

Ruby实现的快排 [Coursera Algorithms: Design and Analysis, Part 1]

2013-07-23 10:56 260 查看
Algorithms: Design and Analysis, Part 1 这门课的第二个编程问题。

这一道题要求对比在快排算法中,使用不同的pivot策略所带来的总的比较数的不同。这道题我试了5次才使得所有的结果正确,前边错误主要的问题在于partition算法和课上讲的不一致。

题目要求的选取pivot的方法共分三种:1)选取第一个;2)选取最后一个;3)选取第一个数、最后一个数和位于中间的数这三个数中的中间数(既不是最大也不是最小),分别计算在这三种方法下快排需要进行多少次比较才能完成。在计算比较数的时候,求中间数所需要的比较数不计入内,也就是说排序一个长度为m的子串所需要的比较数是m-1(pivot分别与m-1个数进行比较)

第一次尝试的时候用ruby写了最简单的快排算法:

def qsort1 array
if array.size <= 1
#长度小于等于1,比较数为0,直接返回
return 0
end
arr = array.dup

#取第一个为pivot
pivot = arr.shift

#把当前arr拆分成比pivot小和比pivot大两部分
smaller,bigger = arr.partition {|x| x<pivot}
return qsort1(smaller) + qsort1(bigger) + array.size - 1
end


结果全错, 错误原因是arr.partiton的实现与课上所讲的partition的实现不同,于是又去看了看slides:









手动实现了一下这个算法,因为实现方法不太一样,细节上有些小差异,导致还调整了几次才过(都是因为不认真看slide……),最终实现代码如下:

def pivot1 array
#总是取第一个为pivot
array.shift
end

def pivot2 array
#总是取最后一个为pivot,方法是先交换最后一个和第一个数,然后取第一个
array[0],array[array.size-1] = array[array.size-1],array[0]
array.shift
end

def pivot3 array
#取中间数为pivot,不管中间数是哪一个,都把它和第一个数交换
mp = (array.size + 1)/2 - 1

h = array[0]
m = array[mp]
t = array[array.size-1]

if (m<h||t<=h)&&(h<=m||h<=t)
elsif (h<m||t<m)&&(m<h||m<t)
array[0],array[mp] = array[mp],array[0]
else
array[0],array[array.size-1] = array[array.size-1],array[0]
end

array.shift
end

def qsort array,type
# end condition
if array.size <= 1return 0
end

bigger = array.dup

if type==1
pivot = pivot1 bigger
elsif type==2
pivot = pivot2 bigger
else
pivot = pivot3 bigger
end

i = j = 0
while j < bigger.size
if bigger[j] < pivot
bigger[i],bigger[j] = bigger[j],bigger[i]
i += 1
end
j += 1
end

smaller = bigger.shift(i)
#因为最后要把smaller的最后一个数同位于第一个位置的pivot交换,所以做一次-1的rotate
smaller.rotate! -1

return qsort(smaller, type) + qsort(bigger, type) + array.size - 1
end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: