中位数:分为上中位数和下中位数,上中位数即长度除2向上取整,下中位数为长度除2向下取整。一般说中位数默认下中位数。
顺序统计量:即第几小的数。一个数组的第一顺序统计量即为最小的数,第n顺序统计量即为最大的数。
1.最小值和最大值
如果我们要找出一个序列中的最小值,我们需要进行n-1次比较,同样,如果我们要找出一个序列中的最大值,也需要进行n-1次比较。
那如果我们需要同时找出最小值和最大值呢,那就需要2n-2次比较。
但是如果我们不再是用一个数与已经记录的最大最小值进行比较,而是用两个数先比较,然后取较小的一个和最大值比较,较大的和最大值比较,这样三次比较就可以完成两个数的比较,较上面的方法节约了一次比较,因而我们只需要

次比较即可。
2.期望为线性时间的选择算法
我们知道,快速排序的每一趟的结果,标记元素都会落在它最终结果的位置上,因此我们可以利用这个性质,达到以线性时间来寻找序列的顺序统计量。
def quick_sort(self, init_list, i, left, right):
"""
快速排序
:param init_list: 排序列表
:param i: 比较元素索引
:return:
"""
length = len(init_list)
# 计算左右索引
left_index = left
right_index = right
# 将比较元素放到最后,防止它是最大值时不进行交换
temp = init_list[i]
init_list[i] = init_list[right_index]
init_list[right_index] = temp
# 比较元素值
flag = init_list[right_index]
# 比较元素索引(因为交换元素位置会变)
flag_index = right_index
# 重复执行直至左右标记重叠
while left_index != right_index:
# 从左向右找比flag大的数交换
for i in range(left_index, right_index):
if flag < init_list[left_index]:
temp = flag
init_list[flag_index] = init_list[left_index]
flag_index = i
init_list[left_index] = temp
break
else:
left_index += 1
# 从右向左找比flag小的数交换
for i in range(right_index, left_index, -1):
if flag > init_list[right_index]:
temp = flag
init_list[flag_index] = init_list[right_index]
flag_index = i
init_list[right_index] = temp
break
else:
right_index -= 1
return init_list, left_index
def randomized_select(self, init_list, order_statistic_idx, left, right):
"""
利用快速排序找出第n个顺序统计量
:param init_list:
:param order_statistic_idx:
:return:
"""
if len(init_list) == 1:
return init_list
random_index = random.randint(left, right)
init_list, flag_idx = self.quick_sort(init_list, random_index, left, right)
# 这里进行了剪枝,不需要想快排一样左右均排序,选择一侧的进行排序即可
if flag_idx == order_statistic_idx:
return init_list[flag_idx]
elif flag_idx > order_statistic_idx:
return self.randomized_select(init_list, order_statistic_idx, left, flag_idx - 1)
else:
return self.randomized_select(init_list, order_statistic_idx, flag_idx + 1, right)
3.最坏情况为线性时间的选择算法
通过将序列分区排序查找中位数的操作来确定整个整个序列的(近似)中位数,然后利用这个中位数执行一趟快排,然后就和上面类似了。
0 条评论