def bubbleSort(L):
assert(type(L)==type(['']))
length = len(L)
if length==0 or length==1:
return L
for i in xrange(length):
for j in xrange(length-1-i):
if L[j] < L[j+1]:
temp = L[j]
L[j] = L[j+1]
L[j+1] = temp
return L
pass
def selectSort(L):
assert(type(L)==type(['']))
length = len(L)
if length==0 or length==1:
return L
def _max(s):
largest = s
for i in xrange(s,length):
if L > L[largest]:
largest = i
return largest
for i in xrange(length):
largest = _max(i)
if i!=largest:
temp = L[largest]
L[largest] = L
L = temp
return L
pass
和冒泡排序一样,稳定,原位排序,同样比较慢。但是它的挑选和置换的方法,确实巧妙的,比如另一个面试提:0~100的已经排序的序列,如何随机打乱它的顺序,当然也可以变成如何最快的生成0~100的随机数。一种比较好的方法,就是随机在数组里挑选元素,然后置换这个数据和最后一个元素的位置,接下来在不包含最后一个元素的数组里继续找随机数,然后继续后置。
这个shuffle的方法,事实上难倒了很多面试的同学,甚至有些链表和树什么的都已经用到了。选择排序的思维可以轻松搞定这个问题。
def insertSort(L):
assert(type(L)==type(['']))
length = len(L)
if length==0 or length==1:
return L
for i in xrange(1,length):
value = L
j = i-1
while j>=0 and L[j]0):
if left[0]>right[0]:
L = left.pop(0)
else:
L = right.pop(0)
s+=1
while(len(left)>0):
L = left.pop(0)
s+=1
while(len(right)>0):
L = right.pop(0)
s+=1
pass
if start L[child]:
L[root],L[child] = L[child],L[root]
root = child
else:
break
for start in range((len(L)-2)/2,-1,-1):
sift_down(L,start,len(L)-1)
for end in range(len(L)-1,0,-1):
L[0],L[end] = L[end],L[0]
sift_down(L,0,end-1)
return L
由于堆排序的堆的高度为log2N,而它每次调整的时候需要对比的次数趋向于N,所以整体的时间复杂度是N*log2N,但是它并不稳定的一种算法,依赖于给定的待排序数组。另外,堆排序是在原来的数组(二叉树)上进行调整和换位,并没有申请多余的空间。和冒泡一类两两相比的排序算法比较,堆排序主要是使用二叉树构建堆的方式,传递的排序结果。
但是事实上,每次根节点和后面元素置换的同时,二叉树其他节点并没有改变,所以我们可以使用额外的空间来记录这些节点的排列情况,提高排序速度。
def binaryTreeSort(l):
assert(type(l)==type(['']))
length = len(l)
if length==0 or length==1:
return l
class Node:
def __init__(self,value=None,left=None,right=None):
self.__value = value
self.__left = left
self.__right = right
@property
def value(self):
return self.__value
@property
def left(self):
return self.__left
@property
def right(self):
return self.__right
class BinaryTree:
def __init__(self,root=None):
self.__root = root
self.__ret=[]
@property
def result(self):
return self.__ret
def add(self,parent,node):
if parent.value>node.value:
if not parent.left:
parent.left = node
else:
self.add(parent.left,node)
pass
else:
if not parent.right:
parent.right = node
else:
self.add(parent.right,node)
def Add(self,node):
if not self.__root:
self.__root = node
else:
self.add(self.__root, node)
def show(self,node):
if not node:
return
if node.right:
self.show(node.right)
self.__ret.append(node.value)
if node.left:
self.show(node.left)
def Show(self):
self.show(self.__root)
b = BinaryTree()
for i in l:
b.Add(Node(i))
b.Show()
return b.result
按之前提到的,我们需要构建节点和二叉树的对象或者结构,然后进行遍历排序。本身需要构建二叉树和遍历输入,所以复杂度不如好的直接排序算法;如果不考虑空间开销和输出遍历,它整体的复杂度还是N*log2N的。所以整体的复杂度介于冒泡算法等普通排序算法和快速排序等高级排序算法之间。
文中要讨论的基于比较模型的排序算法暂时只讨论这么多,最后讨论二叉树排序,是为了引深一个问题——比较模型的排序算法复杂度还能在优化吗?答案是不行的,纯比较模型的排序算法,最好的时间复杂度就是N*log2N了。我们可以改造二叉树排序来证明这一点,当然还是以大白话为主,我不喜欢繁琐的公式。
这个问题的证明,是需要一套模型理论的,即决策树。我们抛开各种理论,可以简单的认为,这就是一个二叉树。这个二叉树的最终展开,就是所有的决策,在这里就是一个待排序数组的所有数序集合,一个N个元素的所有排序个数为N!个。也就是说,从这个二叉树的根节点开始,最终会有N!个子节点。那么这个二叉树的深度,也就是最终执行的次数。实际上,也就是2^h=N!,通过数学推导,可以得到h0:
ret.append(x)
tem-=1
map(lambda x:count(x),l)
map(lambda x:pop(x),xrange(m,0,-1))
return ret