明早去面试,今天复习了一下八大排序,把总结以及代码实现记录一下~~~
希望明天面试顺利!!
结合本科的数据结构课件。
可以参考链接[https://www.cnblogs.com/wuxinyan/p/8615127.html]
原理
依次遍历数组中的每个元素,当插入到第 i 个位置时,前边的所有元素V[0] V[1]··· V[i-1]都已经排序完毕。此时将V[i] 与前边的所有元素比较,找到插入位置,插入V[i] ,原来位置上的元素向后顺移。
def InsertSort(lis):
length = len(lis)
for i in range(length):
key = lis[i]
j = i-1
while j >= 0:
if lis[j] > key:
lis[j+1] = lis[j]
lis[j] = key
j -= 1
return lis
平均时间复杂度: $O(n^{2})$
原理
就是在上述插入排序算法中,插入元素V[i]时,在前i-1个有序数组中采用二分搜索的方法。
def BinaryInsertSort(lis):
for i in range(len(lis)):
low = 0
high = i-1
tmp = lis[i]
while high >= low:
middle = int((high+low)/2)
if lis[middle] > tmp:
high = middle - 1
else:
low = middle + 1
j = i-1
# 成块后移
while j >= low:
lis[j+1] = lis[j]
j -= 1
lis[j+1] = tmp
return lis
BinaryInsertSort(a)
平均时间复杂度:$O(nlogn)$
原理
缩小增量。就是对于插入排序的一种改进,因为插入排序对于已经排序好的数组效率较高;但是对于一般的数组,每次只移动一位,效率较低。
希尔排序是想先大叔组分成几个小的数组进行插入排序,然后拼成一个基本有序的大数组在进行排序。
def shellSort(lis):
length = len(lis)
gap = length
while gap > 1:
gap //= 2
for i in range(gap,length):
for j in range(i%gap, i, gap):
if lis[i] < lis[j]:
lis[i], lis[j] = lis[j], lis[i]
return lis
shellSort(a)
不稳定的排序。
希尔排序的时间复杂度为:O(n^(3/2))
原理
数组长度为n,比较第i个元素时,从后往前(n-1,n-2····)依次比较
def bubbleSort(lis):
if lis == []:
return lis
for i in range(len(lis)):
for j in range(i+1, len(lis)):
if lis[i] > lis[j]:
lis[i],lis[j] = lis[j], lis[i]
return lis
原理
定一个基准pivot,将数组分成两个大的部分。基准左边的都小于基准,基准右边的都大于基准。
然后对左右两个数组重复上述方法。
def quickSort2(lis,left = None,right = None):
left = 0 if not isinstance(left,(int, float)) else left
right = len(lis)-1 if not isinstance(right,(int, float)) else right
if left < right:
partitionIndex = partition(lis,left,right)
quickSort(lis, left, partitionIndex-1)
quickSort(lis, partitionIndex+1, right)
return lis
def partition(lis,left,right):
pivot = left
index = pivot + 1
i = index
while i <= right :
if lis[i] < lis[pivot]:
swap(lis, i, index)
index += 1
i += 1
swap(lis, pivot, index-1)
return index -1
def swap(lis,m,n):
lis[m], lis[n] = lis[n], lis[m]
def QuickSort(lists, left, right):
if left > right :
return lists
key = lists[left]
low = left
high = right
while left < right:
while left < right and lists[right] >= key:
right -= 1
lists[left] = lists[right]
while left <right and lists[left] <= key:
left += 1
lists[right] = lists[left]
lists[right] = key
QuickSort(lists, low, left-1) #执行左侧
QuickSort(lists, left+1, high) #执行右侧
return lists
当数组长度较小时,不适用。
适用于较大数组。
不稳定的排序。
平均时间复杂度:
最好:O(nlogn)
最坏:O(n^2)
原理
选择最小的元素,如果不在数组首位,与首位交换。
剔除刚刚最小的,重复此步骤。
def selectSort2(lis):
for i in range(len(lis)):
min_index = i
for j in range(i+1, len(lis)):
if lis[min_index] > lis[j]:
min_index = j
# 与首位交换
lis[min_index], lis[i] = lis[i], lis[min_index]
return lis
平均复杂度 O(n^2)
空间复杂度:O(1)
原理
每次都取堆顶的元素,将其放在序列最后面,然后将剩余的元素重新调整为最大堆,依次类推,最终得到排序的序列。
步骤 :
1、建立最大堆
2、堆顶元素与堆底元素交换,然后从堆底外的元素进行shift_down,目的是想把新的堆顶元素调整到相应位置
3、重复步骤2,直至堆长度为1
def build_heap(lis,size):
for i in range(size//2,-1,-1):
shift_down(lis,i,size)
def shift_down(lis,i,size):
left = 2 * i + 1
right = 2 * i + 2
max_index = i
if left < size and lis[left] > lis[max_index]:
max_index = left
if right < size and lis[right] > lis[max_index]:
max_index = right
if i!= max_index:
lis[i], lis[max_index] = lis[max_index], lis[i]
shift_down(lis,max_index, size)
def heapSort(lis):
size = len(lis)
build_heap(lis,size)
for i in range(size,-1,-1):
lis[i],lis[0] = lis[0],lis[i]
shift_down(lis,0,i)
return lis
shift_dowm:O(nlogn)
建立初始最大堆的时间复杂度也就是shift_down的时间复杂度O(nlogn)
然后排序是使用n-1次shift_down,也是:O(nlogn)
空间复杂度:O(1)
原理
设初始元素序列有 n 个元素,首先把它看成是 n 个长度为 1 的有序子序列(归并项),做两两归并,得到 n/2 个长度为 2 的归并项(最后一个归并项的长度为1);
再做两两归并,得到 n/4 个长度为 4 的归并项(最后一个归并项长度可以短些)…,如此重复,最后得到一个长度为 n 的有序序列
def merge(left,right):
i,j = 0,0
res = []
while i < len(left) and j < len(right):
if left[i] < right[j]:
res.append(left[i])
i += 1
else:
res.append(right[j])
j += 1
res += (left[i:])
res += (right[j:])
return res
def mergeSort(lis):
if len(lis) <= 1:
return lis
middle = len(lis)//2
left = mergeSort(lis[:middle])
right = mergeSort(lis[middle:])
return merge(left, right)
时间复杂度:O(nlogn)