第 9 章 中位数和顺序统计量
-
顺序统计量
- 在一个由n个元素组成的集合中,第i个顺序统计量(order statistic)是该集合中第i小的元素
- 例如,在一个元素集合中,最小值是第1个顺序统计量,最大值是第n个顺序统计量(i=n)
-
一个中位数是它所属集合的中点元素
9.1 最小值和最大值
9.1.1 在一个有n个元素的集合中,需要做多少次比较才能确定其最小元素呢
-
例程: MINIMUM算法
-
结论: 为了确定最小值,至少要做
n-1
次比较
9.1.2 同时找到最小值和最大值
-
我们只需要最多
3 * Math.floor(n/2)
次比较就可以同时找到最小值和最大值 -
具体方法如下
0. 我们需要记录已知的最小值和最大值- 我们将一对输入元素相互进行比较
- 我们将较小的与当前最小值比较,将较大的与当前最大值比较,这样,对每两个元素共需要3次比较
-
如何设定已知的最小值和最大值的初始值依赖于n是奇数还是偶数
- 如果n是奇数,我们就将最小值和最大值的初值都设为第一个元素的值,然后成对地处理余下地元素
- 如果n是偶数,就对前两个元素做一次比较,以决定最小值和最大值的初值,然后与n是奇数的情形一样,成对处理剩下的元素
-
代码实现: 同时求解最大值和最小值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26def minimum_and_maximum(arr):
arr_len = len(arr)
print(arr_len)
if arr_len == 0:
raise IndexError("param: arr is empty")
if arr_len % 2:
max_val, min_val = arr[0], arr[0]
start = 1
else:
max_val, min_val = (arr[0], arr[1]) if (arr[0] > arr[1]) else (arr[1], arr[0])
start = 2
for i in range(start, arr_len, 2):
temp_max, temp_min = (arr[i], arr[i + 1]) if (arr[i] > arr[i + 1]) else (arr[i + 1], arr[i])
if temp_max > max_val:
max_val = temp_max
if temp_min < min_val:
min_val = temp_min
return max_val, min_val
if __name__ == '__main__':
arr = [-3, 19, -2, 4, 1, 3, 2, 16, 9, 10, 14, 8, 7, 17, 0, -1, 18]
max_val, min_val = minimum_and_maximum(arr)
print(max_val, min_val)
9.2 期望为线性时间的选择算法
-
选择算法: 用于选择序列中的第i个顺序统计量
-
伪代码
-
解释
- 第一行检查递归的基本情况
- 若不符合基本情况,第三行调用
RANDOMIZED-PARTITION
将数组A[p...r]
划分为两个子数组A[p..q-1]
和A[q+1..r]
,使得A[p..q-1]
中的每个元素都小于或等于A[q]
,而A[q+1..r]
中的元素都大于A[q]
- 然后检查
A[q]
是否是第i个统计量 - 若不是则继续递归的调用此算法
-
代码实现:
RANDOMIZED-SELECT
算法
1 | import random |
- 时间复杂度
- 最坏情况
- O(n2)
- 每次划分都极不走运地总是按余下地元素中最大地来进行划分
- 平均情况
- O(n)
- 又因为它是随机化的,所以不存在一个特定的会导致其最坏情况发生的输入数据
- 最坏情况
9.3 最坏情况为线性时间的选择算法
9.3.1 简介
SELECT
算法通过对输入数组的递归划分来找出所需元素,但是,在该算法中能够保证得到对数组的一个好的划分
9.3.2 算法步骤
-
将输入数组的n个元素划分为
floor(n / 5)
组,每组有5个元素,且至多只有一组由剩下的n % 5
个元素组成 -
寻找这
ceil(n / 5)
组中每一组的中位数: 首先对每组元素进行插入排序, 然后确定每组有序元素的中位数 -
对第二步中找到的
ceil(n / 5)
个中位数,递归调用SELECT
以找出其中位数x
-
通过
PARTITION
函数按照x
对输入数组进行划分, 假设x
是数组的第k
个顺序统计量 -
如果
i=k
,则返回x
; 如果i<k
,则在低区递归调用SELECT
来找出第i
小的元素;如果i>k
,则在高区递归查找第i-k
小的元素
9.3.3 算法实现:Python
1 | import math |
9.3.4 时间复杂度
-
最坏情况下的递归式
-
最坏情况下的时间复杂度
O(n)
, 带入主方法可以证明