排序是数据结构这门课里的重点内容。主要有:插入排序、希尔排序、选择排序、冒泡排序、快速排序、归并排序、堆排序、基数排序、桶排序等等。其中选择、冒泡等算法都很简单,没什么细节就不多说了。
其实我们在学算法的时候不仅要学会它的实现细节,更重要的是它的思想和特点,会把它的思想应用于其他的具体问题中,同时也会从具体问题中归纳出某个算法的模型。
插入排序
插入排序是我们很熟悉的排序算法,希尔排序也是其中一种,但我想大家平时用的不多,它有两个特点:
一是将一个元素插入已排好序的序列中;
二是实现方法用数组的倒插法。
#InsertSort
def InsertSort(seq):
length = len(seq)
for i in range(1,length):
temp = seq[i]
for j in range(i-1, -1, -1):
if temp < seq[j]:
seq[j+1]=seq[j]
else:
j+=1
break
if seq[j] is not temp:
seq[j]=temp
快速排序
快排被认为是速度最快的排序算法,它的特点是把所有的元素和一个选定的基准元素比较,大于基准元素的放后面,小的放前面,每次循环确定一个基准元素的位置。基准元素选的好,效率会大大提高。它的特点是:
一它的实现是一种二叉树的结构;
二每次循环确定一个元素位置。
#QuickSort
def QuickSort(seq, low, high):#[low, high]
if low >= high:
return
start = low
end = high
temp = seq[low]
if low < high:
while low < high:
while low < high and seq[high] >= temp:
high = high - 1
if low < high:
seq[low] = seq[high]
while low < high and seq[low] <= temp:
low = low + 1
if low < high:
seq[high] = seq[low]
seq[low] = temp
QuickSort(seq, start, low-1)
QuickSort(seq, low+1, end)
堆排序
堆排序是s[i] >=s [2*i] and s[i] >= s[2*i+1] ,堆排序是二叉树的结构,堆排序每次只能确定根节点为最小值或者最大值,其他节点顺序未定。典型应用求topK的数。特点:
一每次确定一个最值,适用于topK;
二是二叉树结构,速度为k*logn
#HeapSort,small root heap
def HeapSort(seq):
def SmallRootHeap(seq):
_len = len(seq)
fromIndex = _len//2
for i in range(fromIndex, 0, -1):
k = 2*i-1
j = i-1
while k <= _len-1:
if k+1 <= _len-1 and seq[k] > seq[k+1]:
k = k+1
if seq[j] > seq[k]:
seq[j], seq[k] = seq[k], seq[j]
j = k
k = 2*j
else:
break
def RemoveRoot(seq):
_len = len(seq)
val = seq[0]
seq[0] = seq[_len-1]
seq.pop()
SmallRootHeap(seq)
return val
_seq = []
_seq.extend(seq)
SmallRootHeap(_seq)
i = 0
while i != len(seq):
seq[i] = RemoveRoot(_seq)#
i = i+1
归并排序
归并排序是一种贪心算法,可以将复杂的问题化简为具有相同特征的子问题。这种结构模型是:
function(root):
if some condition:
function(lchild)
function(rchild)
do something
以上可以看出这种结构关键在于do something,其他的都是递归调用function
#MergeSort
def MergeSort(seq):
def Merge(seq, low, mid, high):#[low, high]
_seq = []
k = low
j = mid+1
i = 0
while k <= mid and j <= high:
if seq[k] <= seq[j]:
_seq.append(seq[k])
k = k+1
else:
_seq.append(seq[j])
j = j+1
i = i+1
while k <= mid:
_seq.append(seq[k])
i = i+1
k = k+1
while j <= high:
_seq.append(seq[j])
i = i+1
j = j+1
for i in range(len(_seq)):
seq[low+i] = _seq[i]
def Sort(seq, low, high):
if low < high:
mid = (high+low)//2
Sort(seq, low, mid)
Sort(seq, mid+1, high)
Merge(seq, low, mid, high)
Sort(seq, 0, len(seq)-1)
桶排序
桶排序类似于hash表,在一定范围内的大量元素排序有很高的效率,特点是分治。如1亿个在1000以内的整数排序。可以建立1001个桶,然后遍历1亿个元素,再对1001个桶内的元素排序(可以用快排等等)。
#BucketSort
def BucketSort(seq, minVal, maxVal, num = 10):
bucketNum = (maxVal-minVal)//num +1
bucket = [[] for i in range(bucketNum)]
#step one
for i in range(len(seq)):#put seq[i] into the correct bucket
bucket[(seq[i]-minVal)//num].append(seq[i])
#step two
seq.clear()
for i in range(len(bucket)):#quick sort of the i-th bucket's elements
QuickSort(bucket[i], 0, len(bucket[i])-1)
seq.extend(bucket[i])
基数排序
基数排序也用到了桶的思想,给定d组关键字,先按关键字k1排序分组入桶,同一组中记录关键码k1相等,然后将各桶依次连接即合并各分组,再按k2排序分组入桶,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。
#RadixSort
def RadixSort(seq, radix):
bucketNum = 10
for k in range(radix):
bucket = [[] for i in range(bucketNum)]
for i in range(len(seq)):
if k == 0:
bucket[seq[i]%bucketNum].append(seq[i])
else:
bucket[(seq[i]//(bucketNum*k))%bucketNum].append(seq[i])
seq.clear()
for i in range(bucketNum):
QuickSort(bucket[i], 0, len(bucket[i])-1)
seq.extend(bucket[i])
bucket.clear()
测试代码
#Date :2013-9-23 #Author :DVD0423 #Function:Sort def do_test(): seq = [8,7,6,5,4,3,112,113,116,115,118,34,38,37,35,39,99,90,98,95] print('Please input the sequence:') print(seq) print('After the Sort:') RadixSort(seq, 3) print(seq) if __name__ == '__main__': do_test()