排序是指将集合元素按某种顺序排列的过程。影响排序算法的因素包括元素的数目和交换次数。
冒泡排序
冒泡排序是遍历列表,比较相邻的元素,如果大小不符合要求则交换元素次序,若有n个元素,则第一次要比较n-1次,第二次要比较n-2次,完成n-1轮后完成排序。
冒泡排序的python实现如下:
def bubblesrt(alist):
for passnum in range(len(alist)-1,0,-1):
for x in range(passnum):
if alist[x] > alist[x+1]:
temp = alist[x]
alist[x] = alist[x+1]
alist[x + 1] = temp
在完成这个排序的过程中,会利用到临时变量:
temp = alist[x]
alist[x] = alist[x+1]
alist[x + 1] = temp
冒泡排序总的比较次数是前n-1个整数之和,为n*(n+1)/2,因此冒泡排序的时间复杂度是O(n^2)。
冒泡排序还有一种改良方法,一旦在一轮遍历中没有发生交换,可以确定元素已经完成排序,因此可以终止后面的排序。
def shortbubblesrt(alist):
changenum = len(alist) - 1
change = True
while changenum > 0 and change:
change = False
for x in range(changenum):
if alist[x] > alist[x + 1]:
change = True
temp = alist[x]
alist[x] = alist[x + 1]
alist[x + 1] = temp
changenum -= 1
选择排序
选择排序对冒泡排序进行了改进,每次只进行一次交换,比如对一个升序排序来说,就每次比较出最大的元素并放到最后一位,而每轮排序完成后,下一轮只比较排在最大值以前的元素,因此每轮比较的元素会少一个。给n个元素排序,需要比较n-1轮。
# 选择排序
def selectionsort(alist):
for changenum in range(len(alist)-1,0,-1):
posmax = 0
for location in range(1,changenum + 1):
if alist[location] > alist[posmax]:
posmax = location
temp = alist[changenum]
alist[changenum] = alist[posmax]
alist[posmax] = temp
选择排序比较的次数和冒泡排序相同,因此时间复杂度也是O(n^2)。
插入排序
插入排序将0处的元素看作是只含单个元素的有序子列表,从1到n-1,每轮都将当前元素与有序子列表的元素比较,在有序子列表中,比他大的右移,比他小或抵达终点则插入元素。
# 插入排序
def insertionsort(alist):
for index in range(1,len(alist)):
concurrentvalue = alist[index]
pos = index
while pos > 0 and alist[pos - 1] > concurrentvalue:
alist[pos] = alist[pos] - 1
pos -= 1
alist[pos] = concurrentvalue
算法需要遍历n-1轮,其时间复杂度同样是O(n^2)。
希尔排序
希尔排序是对插入排序的改进,他将列表拆分为数个子列表,并对子列表应用插入排序,i是步长,他将间隔为i的元素组成子列表。
在本例中,先为n/2个列表排序,再为n/4个列表排序。
def shellsort(alist):
subliscount = alist // 2
while subliscount > 0:
for start in range(subliscount):
gapinsertionsort(alist, start, subliscount)
print(subliscount)
subliscount = alist // 2
def gapinsertionsort(alist, start, gap):
for index in range(start + gap,len(alist),gap):
concurrentvalue = alist[index]
pos = index
while pos >= gap and alist[pos - gap] > concurrentvalue:
alist[pos] = alist[pos - gap]
pos -= gap
alist[pos] = concurrentvalue
希尔排序的时间复杂度在O(n)和O(n^2)之间。
归并排序
分治策略的第一个算法是归并排序,他是递归算法,他将每个列表一分为二,当列表只有一个元素或没有元素认为他有序。当每个列表都有序了,再使用归并将列表合并为大的有序列表。
def mergesort(alist):
print("s",alist)
if len(alist) > 1:
mid = len(alist) // 2
left = alist[:mid]
right = alist[mid:]
mergesort(left)
mergesort(right)
i = 0
j = 0
k = 0
while i < len(left) and j < len(right):
if left[i] < right[j]: #合并大列表前半部分
alist[k] = left[i]
i += 1
else:
alist[k] = right[j]
j += 1
k += 1
while i < len(left): #合并大列表后半部分
alist[k] = left[i]
k += 1
i += 1
while j < len(right):
alist[k] = right[j]
k += 1
j += 1
print(alist)
快速排序
快速排序同样分治策略,但不占用额外的空间,他先选出一个基准值帮助切分列表。并利用递归重复切分来实现排序。
下面的例子以第一个元素作为切分点:
首先加大leftmark,直到有一个大于基准值的元素,然后缩小rightmarket。直到遇到一个小于基准值的元素,这样就互换两个元素的位置,直到leftmark>rightmark,这样rightmark就是分割点,分割点左侧元素小于他,右侧大于他,在左右两侧递归调用函数,直到列表长度小于等于1.
def quicksort(alist):
quicksorthelp(alist,0,len(alist)-1)
def quicksorthelp(alist,first,last):
if first < last:
splitpoint = partition(alist,first,last)
quicksorthelp(alist,first,splitpoint -1 )
quicksorthelp(alist,splitpoint+1,last)
def partition(alist,first,last):
pivotvalue = alist[first]
leftmarket = first + 1
rightmarket = last
done = False
while not done:
while leftmarket <= rightmarket and alist[leftmarket] <= pivotvalue:
leftmarket += 1
while alist[rightmarket] >=pivotvalue and rightmarket >= leftmarket:
rightmarket -= 1
if leftmarket < rightmarket:
done = True
else:
temp = alist[leftmarket]
alist[leftmarket] = alist[rightmarket]
alist[rightmarket] = temp
temp = alist[first]
alist[first] = alist[rightmarket]
alist[rightmarket] = temp
return rightmarket