归并排序的基本思想:
\qquad 归并排序可以看做一个分而治之的过程,先将待排序列等分为两半,再对每一半继续归并排序(递归操作,将序列等分直到每个序列只有一个元素时结束递归),最后将得到的每两个有序序列归并成一个即可
归并排序的性能分析:
时间复杂度:
空间复杂度:
def mergeSort(arr, low, high):
if low < high:
mid = (low + high) // 2
mergeSort(arr, low, mid)
mergeSort(arr, mid+1, high)
merge(arr, low, mid, high)
helper = [None] * len(arr) # 与整个待排序列等长的辅助数组helper
def merge(arr, low, mid, high):
n = low; i = low; j = mid+1
for k in range(low,high+1):
helper[k] = arr[k]
while i < mid+1 and j < high+1:
if(helper[i] < helper[j]):
arr[n] = helper[i]
i += 1
else:
arr[n] = helper[j]
j += 1
n += 1
# 将剩下的未归并的序列元素依次放入辅助数组中(两个while循环只会执行其中一个)
while i < mid+1:
arr[n] = helper[i]
i += 1; n += 1
while j < high+1:
arr[n] = helper[j]
j += 1; n += 1
快速排序的基本思想:
\qquad 通过一趟排序将要排序的数据根据枢轴值分割成独立的两部分,一部分都比枢轴值小,另外一部分都比枢轴值大,然后再按此方法对这两部分数据再分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
时间复杂度:
空间复杂度:
from random import randint
def quickSort(arr, low, high):
'''
这里取arr[low]到arr[high]的任意一个值作为枢轴值pivot作为对快速排序的改进
(减少区域被划分为0个元素和n-1个元素的几率)
'''
i = low; j = high
if low < high:
pivotPos = randint(low, high)
pivot = arr[pivotPos]
arr[low], arr[pivotPos] = arr[pivotPos], arr[low] # 将枢轴值放到下标low处
while i < j:
while i < j and arr[j] > pivot:
j -= 1
if i < j: # 每次交换前,判断该轮是否其实已经结束
arr[i] = arr[j]
i += 1
while i < j and arr[i] < pivot:
i += 1
if i < j:
arr[j] = arr[i]
j -= 1
arr[i] = pivot
quickSort(arr, low, i-1)
quickSort(arr, i+1, high)
直接插入排序的基本思想:
\qquad 每趟将一个待排序列的关键字按照其值的大小插入到前面已经排好的有序序列中,直到所有待排序列的关键字都被插入到有序序列
时间复杂度:
空间复杂度:O(1)
def DinsertSort(arr):
# 直接插入排序算法
length = len(arr)
for i in range(1, length):
j = i - 1
temp = arr[i]
while j>=0 and arr[j]>temp:
arr[j+1] = arr[j]
j -= 1
arr[j+1] = temp
折半插入排序的基本思想:
\qquad 其实是直接插入排序的改进,只是将查找有序序列的插入位置的方法改为二分查找法
时间复杂度:
空间复杂度:O(1)
def Bsearch(arr, low, high, k):
# 二分查找法
while low <= high:
mid = (low + high) // 2
if arr[mid] == k:
return mid
elif arr[mid] < k:
low = mid + 1
else:
high = mid - 1
return high + 1
def BinsertSort(arr):
length = len(arr)
for i in range(1,length):
temp = arr[i]
insertPos = Bsearch(arr, 0, i-1, temp)
for j in range(i-1, insertPos-1, -1):
arr[j+1] = arr[j]
arr[insertPos] = temp
冒泡排序基本思想:
\qquad 第一趟从头开始依次将连在一起的两个数两两比较,较大的数换到后一位,第一趟结束时最大值换到了序列最后;同理对序列进行第二趟排序,结束位置此时为倒数第二个;当没有发生交换时排序结束
时间复杂度:
空间复杂度:O(1)
def bubbleSort(arr):
# 这里用lastIndex记录每一趟最后发生交换的位置,依次作为对普通冒泡排序的改进
length = len(arr)
change = length - 1
while change:
lastIndex = 0 # lastIndex记录该趟最后移动元素的位置
for i in range(change):
if a[i] > a[i+1]:
a[i+1], a[i] = a[i], a[i+1]
lastIndex = i + 1
change = count # 当该趟没有移动元素,lastIndex的值为0,结束排序
简单选择排序基本思想:
\qquad 从头到尾扫描整个序列,找出最小的关键字和第一个关键字交换,接着从剩余的关键字中继续这种选择和交换,最终使序列有序
def selectSort(arr):
length = len(arr)
for i in range(length):
minnumIndex = i
for j in range(i+1, length):
if arr[j] < arr[minnumIndex]:
minnumIndex = j
arr[i], arr[minnumIndex] = arr[minnumIndex], arr[i]
堆可以看做是一棵完全二叉树,这里使用大顶堆,则该完全二叉树的根结点即为最大值。
堆排序的基本思想:
\qquad 将初始序列按照顺序写出其完全二叉树形式,对所有的非叶子节点从下往上,从右往左依次做调整(要求以其为根结点的二叉树也是大顶堆),建堆完毕;此时根结点为最大值,将其与最后一个结点交换,则最大值到达其最终位置,之后继续对二叉树剩下的结点做同样的调整(此时只有刚换上去的根结点需要调整)
def adjust(arr, low, high):
# 向下调整k位置上的结点
i = low; j = 2*i;
temp = arr[low]
while i <= j and j < high:
if arr[j] < arr[j+1]: # 将左右结点中最大的结点当做arr[j]
j += 1
if arr[j] > temp:
arr[i] = arr[j]
i = j; j = 2*i # 循环做对下一个根结点的调整
else:
break
arr[i] = temp # 存于最终位置
def heapSort(arr):
length = len(arr)
for i in range(length//2,-1,-1): # 建堆
adjust(arr, i ,length-1)
# 将根结点与每一趟的最后一个结点交换,再调整
for index in range(length-1, -1, -1):
arr[index], arr[0] = arr[0], arr[index] # 该趟最大值已到最终位置
adjust(arr, 0, index-1) # 新一轮的调整
def Bsearch(arr, low, high, k):
# 二分查找法
while low <= high:
mid = (low + high) // 2
if arr[mid] == k:
return mid
elif arr[mid] < k:
low = mid + 1
else:
high = mid - 1
return high + 1
def Bsearch(arr, low, high, k):
# 模糊二分查找法查找大于等于给定值的第一个元素和其下标
highTemp = high
while low <= high:
mid = (low + high) // 2
if arr[mid] == k:
while arr[mid-1] == k:
mid -= 1
return arr[mid],mid
elif arr[mid] < k:
low = mid + 1
else:
high = mid - 1
if high+1 < highTemp:
return arr[high+1],high+1
else:
return
def mySqrt(x):
if x == 1:
return 1
left = 0
right = x
while left+1 < right:
m = (right + left) / 2
if m ** 2 < x:
left = m
elif m ** 2 == x:
return int(m)
else:
right = m
if int(right) ** 2 <= x:
return int(right)
else:
return int(left)