详解排序算法
冒泡排序(稳定)
基本概念
基本思想:
冒泡排序,类似于水中冒泡,较大的数沉下去,较小的数慢慢冒起来,假设从小到大,即为较大的数慢慢往后排,较小的数慢慢往前排。
直观表达,每一趟遍历,将一个最大的数移到序列末尾。
Python实现(n2)
传统算法
def bubbleSort(a_list):
for i in range(len(a_list)-1):
for j in range(len(a_list)-1-i):
if a_list[j] > a_list[j+1]:
a_list[j],a_list[j+1] = a_list[j+1],a_list[j]
return a_list
改进算法
def modBubbleSort(a_list):
exchange =True
passnum = len(a_list)-1
while passnum >= 1 and exchange:
exchange = False
for i in range(passnum):
if a_list[i] > a_list[i+1] :
a_list[i],a_list[i+1] = a_list[i+1],a_list[i]
exchange=True
passnum -= 1
return a_list
插入排序(稳定)
基本概念
将一个记录插入到已排好序的序列中,从而得到一个新的有序序列(将序列的第一个数据看成是一个有序的子序列,然后从第二个记录逐个向该有序的子序列进行有序的插入,直至整个序列有序)
Python实现(n2)
def insertionSort(self,a_list):
for key,item in enumerate(a_list):
index = key
while index > 0 and a_list[index-1] > item:
a_list[index] = a_list[index-1]
index -= 1
return a_list
归并排序(稳定)
基本概念
(1) 归并排序的流程
(2) 合并两个有序数组的流程
Python实现(nlogn)
def mergeSort(a_list):
if len(a_list) > 1:
mid = len(a_list)//2
lefthalf = a_list[:mid]
righthalf = a_list[mid:]
mergeSort(lefthalf)
mergeSort(righthalf)
i,j,k = 0,0,0
while i < len(lefthalf) and j < len(righthalf):
if lefthalf[i] < righthalf[j]:
a_list[k] = lefthalf[i]
i+=1
else:
a_list[k] = righthalf[j]
j+=1
k+=1
while i < len(lefthalf):
a_list[k] = lefthalf[i]
i+=1
k++1
while j < len(righthalf):
a_list[k] = righthalf[j]
j+=1
k+=1
return a_list
快速排序(稳定)
基本概念
基本思想:
选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分;其中一部分的所有数据都比另外一部分的所有数据都要小。然后,再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序流程:
(1) 从数列中挑出一个基准值。
(2) 将所有比基准值小的摆放在基准前面,所有比基准值大的摆在基准的后面(相同的数可以到任一边);在这个分区退出之后,该基准就处于数列的中间位置。
(3) 递归地把"基准值前面的子数列"和"基准值后面的子数列"进行排序。
Python实现(nlogn)
class Solution(object):
def partition(self, a_list, first, last):
pivotvalue = a_list[first]
leftmark = first + 1
rightmark = last
done = False
while not done:
while leftmark <= rightmark and a_list[leftmark] <= pivotvalue:
leftmark += 1
while rightmark >= leftmark and a_list[rightmark] >= pivotvalue:
rightmark -= 1
if leftmark > rightmark:
done = True
else:
a_list[leftmark], a_list[rightmark] = a_list[rightmark], a_list[leftmark]
a_list[rightmark], a_list[first] = a_list[first], a_list[rightmark]
return rightmark
def quickSortHelper(self, a_list, first,last):
if first < last:
splistPoint = self.partition(a_list, first, last)
self.quickSortHelper(a_list, first, splistPoint - 1)
self.quickSortHelper(a_list, splistPoint + 1, last)
def quickSort(self, a_list):
self.quickSortHelper(a_list, 0, len(a_list) - 1)
return a_list
if __name__ == "__main__":
solu = Solution()
alist = [54, 26, 93, 17, 77, 31, 44, 55, 20]
print(solu.quickSort(alist))
选择排序(不稳定)
基本概念
基本思想
选择排序的基本思想:比较+交换
在待排序的一组数据中,选出最小(最大)的一个数与第一个位置的数交换,然后在剩下的数中,再找最小(最大)的数与第二个位置的数交换位置,
依次类推,直到第N-1个元素与第N个元素交换位置,选择排序结束。
Python实现(n2)
def selectionSort(self,a_list):
for i in range(len(a_list)-1):
min = i
for j in range(i+1,len(a_list)):
if a_list[j] < a_list[min]:
min = j
a_list[i],a_list[min] = a_list[min],a_list[i]
return a_list
希尔排序(不稳定)
基本概念
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
基本思想
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
Python实现(平均O(n^1.3),最好为O(n),最坏为0(n ^ 2) )
class Solution(object):
def gapInsertionSort(self,a_list,start,gap):
for i in range(start+gap,len(a_list),gap):
currentValue = a_list[i]
position = i
while position >= gap and a_list[position-gap] > currentValue:
a_list[position] = a_list[position-gap]
position = position - gap
a_list[position] = currentValue
def shellSort(self,a_list):
sublistcount = len(a_list)//2
while sublistcount > 0:
for startposition in range(sublistcount):
self.gapInsertionSort(a_list,startposition,sublistcount)
sublistcount = sublistcount//2
return a_list
堆排序(稳定)
基本概念
堆排序(Heapsort)是指利用堆这种数据结构(后面的【图解数据结构】内容会讲解分析)所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:
大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;
堆排序的平均时间复杂度为 Ο(nlogn)。
Python实现(nlogn)
class Solution(object):
def swap(self,a_list,i,j):
a_list[i],a_list[j] = a_list[j],a_list[i]
def heapify(self,a_list,i):
left = 2*i+1
right = 2*i+2
largest = i
if left < arrLen and a_list[left] > a_list[largest]:
largest = left
if right < arrLen and a_list[right] > a_list[largest]:
largest = right
if largest != i:
self.swap(a_list,i,largest)
self.heapify(a_list,largest)
def buildMaxHeap(self,a_list):
for i in range(len(a_list)//2,-1,-1):
self.heapify(a_list,i)
def heapSort(self,a_list):
global arrLen
arrLen = len(a_list)
self.buildMaxHeap(a_list)
for i in range(len(a_list)-1,0,-1):
self.swap(a_list,0,i)
arrLen -= 1
self.heapify(a_list,0)
return a_list
基数排序
基本概念(稳定)
基数排序(Radix Sort)是桶排序的扩展,它的基本思想是:将整数按位数切割成不同的数字,然后按每个位数分别比较。
具体做法是:将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
在上图中,首先将所有待比较树脂统一为统一位数长度,接着从最低位开始,依次进行排序。
按照个位数进行排序。
按照十位数进行排序。
按照百位数进行排序。
排序后,数列就变成了一个有序序列。
Python实现(O (nlog®m),其中r为所采取的基数,而m为堆数)
class Solution(object):
def radixSortLSD(self,a_list):
#最低位优先法
if len(a_list) == 0:
return
if len(a_list) == 1:
return a_list
tempList = a_list
maxNum = max(a_list)
radix = 10
while maxNum *10 > radix:
newArr = [[], [], [], [], [], [], [], [], [], []]
for n1 in tempList:
testnum = n1 % radix
testnum = testnum // (radix/10)
for n2 in range(10):
if testnum == n2:
newArr[n2].append(n1)
tempList = []
for i in range(len(newArr)):
for j in range(len(newArr[i])):
tempList.append(newArr[i][j])
radix *= 10
return tempList
if __name__ == "__main__":
solu =Solution()
print(solu.radixSortLSD([10, 12, 24, 23, 13, 52, 15, 158, 74, 32, 254, 201, 30, 19]))