1. 冒泡排序
冒泡排序法的复杂度是O(n^2)
# buble sort
def buble_sort(inList):
for i in range(len(inList)):
for j in range(len(inList)-i-1):
if inList[j] <= inList[j+1]:
continue
else:
inList[j], inList[j+1] = inList[j+1], inList[j]
return inList
2插入排序
插入排序,取数组里每一个元素,插入一个新的列表里,插入的时候,保证新的列表按照顺序排列,把最后一个元素插入完成之后,也完成了整个数组的排序。以下为实现方式。
#insertion sort
def insertion_sort(list1):
temp = []
for i in range(len(list1)):
# 每一个循环,往temp中放入一个数据
temp.append(list1[i])
j = len(temp) - 1
while True and j>0:
# 如果数组中有数据,则把数据放入放在第一个大于他的数字前面,从而保证排序
if temp[j] < temp[j-1]:
temp[j], temp[j-1] = temp[j-1], temp[j]
j -= 1
return temp
实现过程中,temp完全可以不存在。程序编写如下。
def insertion_sort(list1):
for i in range(2, len(list1)):
# 每一个循环,往temp中放入一个数据\
j = i
while True and j>0:
# 如果数组中有数据,则把数据放入放在第一个大于他的数字前面,从而保证排序
if list1[j] < list1[j-1]:
list1[j], list1[j-1] = list1[j-1], list1[j]
j -= 1
3归并排序
归并排序是采用分而治之的原则,先将要排序的数组分成两部分,再将剩余部分再分,直至每个数组只剩下一个或者两个元素,进行排序。之后,再进行归并。
算法核心部分是归并的过程,分别从两个数组中取元素,按照顺序排列,当其中一个取尽时,另一个数组剩下的部分就追加到这个元素后面,从而实现排序的目的。
# merge ort
def merge(list1, list2):
temp = []
i = j = 0
while True:
if i== len(list1):
temp.extend(list2[j:])
break
if j== len(list2):
temp.extend(list1[i:])
break
if list1[i] <= list2[j]:
temp.append(list1[i])
i += 1
else:
temp.append(list2[j])
j += 1
return temp
def merge_sort(list1):
length = len(list1)
if length == 1:
return list1
elif length == 0:
return []
splitIndex = int(length/2)
left_arr = list1[:splitIndex]
right_arr = list1[splitIndex:]
return merge(merge_sort(left_arr), merge_sort(right_arr))
4堆排序
堆排序主要分三个过程
- 构建最大堆或者最小堆
最大堆满足的性质:A[parent[i]] >= A[i]
最小堆满足的性质:A[parent[i]] <= A[i] - 交换堆顶和本次调整最后一个数据。
- 最大节点值减掉1,重复前两步
import random
def reAdjustHeap(dataIn, maxNodeIndex):
nodeIndex = (maxNodeIndex-1)//2
while nodeIndex>=0:
# adjust node
leftIndex = nodeIndex*2 + 1
rightIndex = nodeIndex*2 + 2
if rightIndex <= maxNodeIndex:
if dataIn[nodeIndex]<dataIn[rightIndex]:
dataIn[nodeIndex], dataIn[rightIndex] = dataIn[rightIndex], dataIn[nodeIndex]
if dataIn[nodeIndex]<dataIn[leftIndex]:
dataIn[nodeIndex], dataIn[leftIndex] = dataIn[leftIndex], dataIn[nodeIndex]
nodeIndex -= 1
def heapSort(Arr):
maxNodeIndex = len(Arr)-1
while maxNodeIndex>1:
reAdjustHeap(Arr, maxNodeIndex)
print("dataIn[0]={} dataIn[maxNodeIndex]={} maxNodeIndex".format(Arr[0], Arr[maxNodeIndex],maxNodeIndex))
# swap head with tail
Arr[0], Arr[maxNodeIndex] = Arr[maxNodeIndex], Arr[0]
maxNodeIndex -= 1
if __name__ == "__main__":
length = 1000
A = [random.randint(0,length) for i in range(length)]
heapSort(A)
print(A)
5最大(小)优先队列
堆排序的一个典型应用就是最大(小)优先队列。
最大有限序列支持的方法有
- Insert:将一个新元素增加到新新的集合中
- max :返回最大键字的元素
- extractMax:返回并去掉最大键字元素。
- increaseKey:将一个关键字的值增加到另一个值
class PriorityQueue():
def __init__(self, arrData=None):
# 初始化,并排成最大堆
self.data = []
if arrData is not None:
self.data = arrData
self.reAdjustHeap(self.data, len(self.data)-1)
def heapSort(self):
# 实现堆排序,但结果保存在副本,不对原数据造成影响
Arr = self.data[:]
maxNodeIndex = len(Arr)-1
while maxNodeIndex>1:
self.reAdjustHeap(Arr, maxNodeIndex)
# swap head with tail
Arr[0], Arr[maxNodeIndex] = Arr[maxNodeIndex], Arr[0]
maxNodeIndex -= 1
return Arr
@staticmethod
def reAdjustHeap(dataIn, maxNodeIndex):
# 静态方法,完成最大堆调整
nodeIndex = (maxNodeIndex-1)//2
while nodeIndex>=0:
# adjust node
leftIndex = nodeIndex*2 + 1
rightIndex = nodeIndex*2 + 2
if rightIndex <= maxNodeIndex:
if dataIn[nodeIndex]<dataIn[rightIndex]:
dataIn[nodeIndex], dataIn[rightIndex] = dataIn[rightIndex], dataIn[nodeIndex]
if dataIn[nodeIndex]<dataIn[leftIndex]:
dataIn[nodeIndex], dataIn[leftIndex] = dataIn[leftIndex], dataIn[nodeIndex]
nodeIndex -= 1
# 插入操作
def insert(self, data):
self.data = list(set(self.data) | {data})
self.reAdjustHeap(self.data, len(self.data)-1)
# 返回堆顶
def maxData(self):
return self.data[0]
# 返回并去除堆顶
def extractMaxData(self):
maxNodeIndex = len(self.data)-1
self.data[0], self.data[maxNodeIndex] = self.data[maxNodeIndex], self.data[0]
maxData = self.data[-1]
del self.data[-1]
return maxData
# 更改优先级
def updateKey(self, i, data):
self.data[i] = data
if data< self.data[parentNode]:
return self.data
reAdjustHeap(dataIn, maxNodeIndex)
return self.data
if __name__ == "__main__":
obj = PriorityQueue([3,12,5])
print(obj.data)
快速排序
快速排序的思想是分治,将一个完整数组分解成一个个更小的数组进行排序。
其核心部分是对数组进行分割的过程,即取一个分割数组的元素,然后将数组分成小于等于这个元素和大于这个元素的两部分。
最终实现原址排序的效果
def quickSort(A, p, r):
if p >= r:
return
# 数据分割
q = partition(A, p, r)
quickSort(A, p, q-1)
quickSort(A, q, r)
def partition(A, p, r):
print("p={} r={}".format(p,r))
splitElement = A[r]
i = p
for j in range(p+1, r):
if A[j] <= splitElement:
i += 1
A[i], A[j] = A[j], A[i]
A[i+1], A[r] = A[r], A[i+1]
return i+1
if __name__ == "__main__":
data = [1, 4, 7, 9, 12, 10, 8,4, 8]
quickSort(data, 0, len(data)-1)
print(data)
以上算法中,分割元素都是采用的是取最后一个元素作为分割元素,这样有可能会影响算法效率,一种改进措施是,采用随机算法选取分割元素(主元素)。将partition函数按照如下方式进行改写。
def quickSort(A, p, r):
if p >= r:
return
q = partition(A, p, r)
quickSort(A, p, q-1)
quickSort(A, q, r)
def partition(A, p, r):
import random
print("p={} r={}".format(p,r))
# 随机选取主元素
splitElement = A[random.randint(p,r)]
i = p
for j in range(p+1, r):
if A[j] <= splitElement:
i += 1
A[i], A[j] = A[j], A[i]
A[i+1], A[r] = A[r], A[i+1]
return i+1
if __name__ == "__main__":
data = [1, 4, 7, 9, 12, 10, 8,4, 8]
quickSort(data, 0, len(data)-1)
print(data)
计数排序
计数排序的要求是,输入数据位非负整数序列。
核心思想是,利用数组索引的顺序特性,将数据元素转化为数组的索引,这样实现自动排序的目的。
计数排序再实现速度的同时,也牺牲了空间。如代码中,C数组的使用,浪费的大量空间。
def countSort(A):
# 初始化C用于计数
maxIndex = max(A)
minIndex = min(A)
C = []
[C.append(0) for _ in range(maxIndex-minIndex+1)]
# 统计每一个元素的,其实就默认实现了数组的排序
for i in range(len(A)):
C[A[i]-minIndex] += 1
# 取出结果放到B中
B = []
for j in range(len(C)):
count = C[j]
# print("count={}".format(count))
while count > 0:
B.append(j+minIndex)
count -= 1
return B
if __name__ == "__main__":
A = [10, 3, 5, 7, 9, 4]
print(countSort(A))