排序算法
冒泡排序(bubble sort)
冒泡排序是指每次比较相邻的两个数,如果前一个数大于后一个数,则两个数进行交换,每遍历一次,即可得到一个最大数,最坏情况需要遍历n-1次。
Python代码实现如下:
def Bubble_Sort(arr):
exchange = False
length = len(arr)
num = 0
while num < length and not exchange:
exchange = True
for j in range(length-num-1):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
exchange = False
num += 1
return arr
选择排序(selection sort)
选择排序 每次遍历只进行一次数据交换,第一次遍历找出最大或最小的数,第二次遍历找剩余数中的最大或最小数,总共需要进行n-1次遍历。
Python代码实现如下:
def Selection_Sort1(arr, sortmode='up'):
length = len(arr)
for i in range(length-1):
index = 0
for j in range(length-i-1):
if sortmode == 'up':
if arr[index] < arr[j+1]:
index = j + 1
else:
if arr[index] > arr[j+1]:
index = j + 1
arr[index], arr[j+1] = arr[j+1], arr[index]
print(arr)
return arr
插入排序 (insertionSort)
插入排序是将数插入到一个有序数列中,最终得到一个有序的数列。
Python代码实现如下:
def insertionSort(alist):
for index in range(1,len(alist)):
currentvalue = alist[index]
position = index
while position > 0 and alist[position-1] > currentvalue:
alist[position] = alist[position-1]
position = position-1
alist[position] = currentvalue
return alist
希尔排序(shell sort)
希尔排序是将原数列分解为多个子数列,然后对每个子数列使用插入排序进行排序。在希尔排序中,分解为多个子数列并不是对原数列进行连续拆分,而是通过增量的形式来对原数列进行拆分,得到多个子数列。例如数组[1,2,3,4,5,6,7,8,9],使用增量3来拆分原数组,得到三个子数组[1, 4, 7]、 [2, 5, 8]、[3, 6, 9]
Python代码实现如下:
def Shell_Sort(arr):
subcount = len(arr) // 2
while subcount > 0:
for start in range(subcount):
#insert sort
for i in range(start+subcount, len(arr), subcount):
current = arr[i]
pos = i
while pos > 0 and arr[pos-subcount] > current:
arr[pos] = arr[pos-subcount]
pos -= subcount
arr[pos] = current
subcount = subcount // 2
return arr
归并排序(merge sort)
归并排序是基于分治法的思想来设计的。归并排序是一种递归算法,它不断将数列拆分为一半,直到数列中只有一个 元素时,进行排序。此外,还需要一个合并的操作,将两个有序的数列重新合并为一个有序的数列。
Python代码实现如下:
def mergeSort(alist):
print("Splitting ",alist)
if len(alist)>1:
mid = len(alist)//2
lefthalf = alist[:mid]
righthalf = alist[mid:]
mergeSort(lefthalf)
mergeSort(righthalf)
#进行归并排序
i=0
j=0
k=0
while i < len(lefthalf) and j < len(righthalf):
if lefthalf[i] <= righthalf[j]:
alist[k]=lefthalf[i]
i=i+1
else:
alist[k]=righthalf[j]
j=j+1
k=k+1
while i < len(lefthalf):
alist[k]=lefthalf[i]
i=i+1
k=k+1
while j < len(righthalf):
alist[k]=righthalf[j]
j=j+1
k=k+1
print("Merging ",alist)
快速排序(quick sort)
快速排序也是基于分治法来设计的,相对于归并排序,快速排序不需要额外的空间和合并操作。首先,快速排序会先选择一个值,作为分割值( pivot value)。一般可以选择数列的第一项或者使用中值三来选择,中值三是在数列中的第一项、中间项和最后一项中选择中间值作为分割值。根据分割值,将原数列分割为小于分割值和大于分割值得两部分。
分割方法是通过左标记(leftmark)和右标记(rightmark)来实现的。例如数组[10, 5,12,8,45,19,8,6,78],选取第一个元素10作为分割值其分割过程如下:
首先,leftmark指向5,rightmark指向最后一个元素78,如果leftmark指向的数小于分割值10,则leftmark指向下一个元素,否则leftmark停止移动;
然后,判断rightmark指向的元素是否大于分割值10,如果大于,则移动rightmark到下一个元素,否则停止移动;
最后,交换leftmark指向的元素和rightmark指向的元素;
如此循环,直到rightmark小于leftmark时,rightmark指向的数与分割值10交换。
数组[10, 5,12,8,45,19,8,6,78]的
第一次交换是12和6交换
第二次交换是45和8
第三次交换是8和10
最终交换完成后的数列如下
[8, 5,6,8, 10, 19,45,12,78]
接下来对数组[8, 5,6,8,]和数组[19,45,12,78]分别进行分割
当数组的长度等于1时,它已经排好序,不需要进行递归分割,如果大于1,则继续递归分割。
Python代码实现如下:
def quickSort(alist):
quickSortHelper(alist,0,len(alist)-1)
#递归求解
def quickSortHelper(alist,first,last):
if first<last:
splitpoint = partition(alist,first,last)
quickSortHelper(alist,first,splitpoint-1)
quickSortHelper(alist,splitpoint+1,last)
#进行分割操作,返回分割位置
def partition(alist,first,last):
pivotvalue = alist[first]
leftmark = first+1
rightmark = last
done = False
while not done:
while leftmark <= rightmark and alist[leftmark] <= pivotvalue:
leftmark = leftmark + 1
while alist[rightmark] >= pivotvalue and rightmark >= leftmark:
rightmark = rightmark -1
if rightmark < leftmark:
done = True
else:
temp = alist[leftmark]
alist[leftmark] = alist[rightmark]
alist[rightmark] = temp
temp = alist[first]
alist[first] = alist[rightmark]
alist[rightmark] = temp
return rightmark
堆排序(heap sort)
堆排序是基于二叉堆来设计的,下面先介绍二叉堆
二叉堆可以看成一棵完全二叉树,其节点i(从1开始)的父节点是i/2向下取整,在Python中可以用i//2来表示;节点i的左孩子节点是2i;节点i的右孩子节点是2i+1。此外,相对于二叉树,二叉堆还需要满足堆的性质,即所以父节点的值都要大于等于或小于等于孩子节点的值。如果是大于等于,就称为最大堆,如果是小于等于,就称为最小堆。
堆排序思想:首先,将需要进行排序的数列alist=[1…n]构造成一个最大堆或最小堆,此时根节点存放的就是最大值或最小值,然后将根节点和最末尾的节点进行交换,就可以将最大值或最小值移动到最末尾的位置。接着对数列alist=[1…n-1]从新构建为最大堆或最小堆,继续交换根节点和堆的最末尾节点,如此循环,直到堆只有两个节点位置。此时,数组alist=[1…n]已经排好序(最大堆对应升序,最小堆对应降序)。
最大堆的排序算法Python实现如下:
代码来源
def heapify(arr, n, i):
largest = i
l = 2 * i + 1 # left = 2*i + 1 i可以循环到0
r = 2 * i + 2 # right = 2*i + 2
if l < n and arr[i] < arr[l]:
largest = l
if r < n and arr[largest] < arr[r]:
largest = r
if largest != i:
arr[i],arr[largest] = arr[largest],arr[i] # 交换
heapify(arr, n, largest)
def heapSort(arr):
n = len(arr)
# Build a maxheap.
for i in range(n, -1, -1):
heapify(arr, n, i)
# 一个个交换元素
for i in range(n-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i] # 交换
heapify(arr, i, 0)
arr = [ 12, 11, 13, 5, 6, 7]
heapSort(arr)
print ("排序前:", arr)
heapSort(arr)
print ("排序后: ", arr)
上面提及的算法都可以认为是基于比较来设计的,一般称为比较排序,此外,还有不基于比较来进行排序的算法,例如计数排序、基数排序和桶排序,这种算法一般也称为线性时间排序。