快速排序
快速排序在大多情况下的表现优异,其核心思想为分而治之。
具体操作:对于一个长度为
n
n
n的数组
A
A
A,根据改变元素
x
=
A
[
i
]
x=A[i]
x=A[i]的位置,使得数组
A
A
A满足:
*
x
x
x左边的元素都不大于
x
x
x。
*
x
x
x右边的元素都不小于
x
x
x。
此时
x
x
x就位于数组排序完成后其应所在位置。然后对
x
x
x左右两侧进行递归操作即可完成排序。值得注意的是,通常将
x
x
x选定为数组靠中间的元素时效果较好。
def quick_sort(sequence):
if len(sequence) == 1:
return sequence
elif len(sequence) == 0:
return []
mid = len(sequence) // 2
sequence[0], sequence[mid] = sequence[mid], sequence[0]
split = 1
for ii in range(1, len(sequence)):
if sequence[ii] < sequence[0]:
sequence[ii], sequence[split] = sequence[split], sequence[ii]
split += 1
sequence[0], sequence[split - 1] = sequence[split - 1], sequence[0]
left = quick_sort(sequence[:split - 1])
right = quick_sort(sequence[split:])
return left + [sequence[split - 1]] + right
每层递归加起来相当于对于数组进行了一次扫描,共需进行
log
n
\log{n}
logn层递归,故时间复杂度为
n
log
n
n\log{n}
nlogn;每层递归需常数个变量,故空间复杂度为
log
n
\log{n}
logn。
最佳运行时间为
n
log
n
n\log{n}
nlogn;当所有的
x
x
x元素都需要放到当次递归数列后方时,有最差运行时间
n
2
n^2
n2。
归并排序
核心思想:分而治之。对于一个长度为
n
n
n的数组
A
A
A,进行以下操作:
* 将
A
A
A分为两个长度相等或相差一的新数组。
* 对每一个新数组进行归并排序。
* 将排序好的数组归并得到最终结果。
def merge_sort(sequence):
if len(sequence) == 1:
return sequence
elif len(sequence) == 2:
if sequence[0] < sequence[1]:
return sequence
else:
sequence[0], sequence[1] = sequence[1], sequence[0]
return sequence
mid = len(sequence) // 2
left = merge_sort(sequence[:mid])
right = merge_sort(sequence[mid:])
return merge(left, right)
def merge(sequence1, sequence2):
index1, index2 = 0, 0
sequence = []
while index1 <= len(sequence1) - 1 and index2 <= len(sequence2) - 1:
if sequence1[index1] < sequence2[index2]:
sequence.append(sequence1[index1])
index1 += 1
else:
sequence.append(sequence2[index2])
index2 += 1
if index1 == len(sequence1):
sequence += sequence2[index2:]
elif index2 == len(sequence2):
sequence += sequence1[index1:]
return sequence
每层递归加起来相当于对于数组进行了一次扫描,共需进行
log
n
\log{n}
logn层递归,故时间复杂度为
n
log
n
n\log{n}
nlogn;每层递归需使用一个数组存储数据,各层递归总数组长度为
n
n
n,故空间复杂度为
n
n
n。
最佳运行时间与最差运行时间均为
n
log
n
n\log{n}
nlogn。
求数组中的逆序对个数
def merge_sort(sequence, count = 0):
if len(sequence) == 1:
return sequence, 0
mid = len(sequence) // 2
left, left_count = merge_sort(sequence[:mid], count)
right, right_count = merge_sort(sequence[mid:], left_count)
return merge(left, right, left_count + right_count)
def merge(sequence1, sequence2, count):
index1, index2 = 0, 0
sequence = []
while index1 <= len(sequence1) - 1 and index2 <= len(sequence2) - 1:
if sequence1[index1] <= sequence2[index2]:
sequence.append(sequence1[index1])
index1 += 1
else:
sequence.append(sequence2[index2])
count += len(sequence1) - index1
index2 += 1
if index1 == len(sequence1):
sequence += sequence2[index2:]
elif index2 == len(sequence2):
sequence += sequence1[index1:]
return sequence, count