最近萌生了重新学习算法的想法。由于目前正在研究前端,索性就把JS作为我们联系算法的基本语言吧。又由于本人对CoffeeScript的喜欢加上其本身写出来的代码更像是伪代码,所以代码实现部分是就用CoffeeScript了。闲话不多说,排序篇一就只练习两个最基础排序吧。经典的快速排序和堆排序。下面为了方便和容易理解,两种算法分别针对从大到小和从小到大实现一遍。
(一)快速排序
先说快速排序的基本思路,这个大家都应该知道,针对入门者来说我认为有两个地方需要注意。
首先这排序本身肯定都有一个基本动作,对于程序来说你要告诉他基本动作让后让他不停的重复。我们假设快排的基础动作为sort()。那么快排中sort()要完成的任务就是:给定一个Arr[index],它会使得Arr中index前面的数一定都比Arr[index]大,index后面的一定都比Arr[index]小。如[12, 23,34, 4, 45, 8, 9]针对index = 3也就是元素34来说,sort()会使得数组变成[12, 23, 4, 8, 9,34, 45]。然后每次在剩下的前后两部分分别在选取一个index执行同样的sort()过程。
其次,他的结束条件,用比较通俗的话来说就是当边界与index重合的时候便不再执行sort(),如上面例子在针对34后面的部分sort()时就符合结束条件,sort()不会在执行。
有了基本动作和结束条件就比较好写了。我们就假设每一次sort()动作都选取当前边界的中点作为index,也就是index = (start+end)/2,那么程序如下:
Array::swap = (begin, end) -> //这个排序会交换数组内元素的位置
swap = this[begin]
this[begin] = this[end]
this[end] = swap
return this
Array::quickSort = () ->
sort = (array, _begin, _end)-> //基本动作,执行边界为array[_begin]到array[_end]
if _begin >= _end
return
begin = _begin
end = _end
now = Math.floor (begin+end)/2
while begin < end
while array[begin] >= array[now] && now > begin
begin++
if array[now] > array[begin]
array.swap(now, begin)
now = begin
while array[end] <= array[now] && now < end
end--
if array[now] < array[end]
array.swap(now, end)
now = end
if _begin < now-1
sort(array, _begin, now)
if _end > now+1
sort(array, now, _end)
sort(this, 0, this.length-1)
return this
arr = [5,12,1,134,1,23,51,2,34,4,2,5]
console.log arr.quickSort()
(二)堆排序
堆排序的话也要分基本动作,它的基本动作相对比快排要复杂点。临时有事。。。。晚上回来继续吧==||。
现在回来补齐,继续上面堆的概念不再详细描述,通俗点就是数组表示的二叉树。我们说最大二叉堆就是一定满足根比孩子大,这样说数组中最大的就是二叉树的根,也就是Arr[0],我们的思路就是每次把最大的数(Arr[0])取出来,然后将剩下的长度为(Arr.length-1)的数组再次变成最大二叉堆,这样这个数组里面的最大的0元素便是以前Arr中第二大的数。。。。。以此类推排序就可以完成。因此,其实你可以有这种想法:
while Arr.len>1
BuildHeap(Arr);
pop(Arr[0]);
不过这样每次建立二叉堆效率实在是低,所以为了减少不停的建立堆,我们可以有如下策略:每次不要改变堆的结构,只是把堆中不合适的元素向下移动。于是我们只需要建立一次堆,然后将最大的元素Arr[0](假设为max1)与组后一个元素对调,然后保持max1在Arr[len-1]不动,再针对Arr[0...len-2]个元素调整肯定不合适的Arr[0](现在为以前的最后一个元素)。基于这个思想,代码如下:
Array::swap = (begin, end)->
swa = this[begin]
this[begin] = this[end]
this[end] = swa
return this
Array::MaxHeapify = (i, end)->
if typeof i isnt "number"
i = Number(i)
len = end || this.length
lch = 2*i + 1
rch = 2*i + 2
if lch < len and this[i] < this[lch]
largest = lch
else
largest = i
if rch < len and this[largest] < this[rch]
largest = rch
if i != largest
this.swap(i, largest)
# console.log this
this.MaxHeapify(largest, len)
return this
Array::BuildMaxHeap = ->
len = this.length
index = Math.floor(len/2)
while index >= 0
this.MaxHeapify(index--)
return this
Array::HeapSort = ->
len = this.length
this.BuildMaxHeap()
while len > 1
this.swap(0, len-1)
this.MaxHeapify(0, len-1)
len--
return this
arr = [5,12,1,134,1,23,51,2,34,4,2,5]
console.log arr.HeapSort()