0%

BFPRT

BFPRT算法

解释: 在一个无序数组中, 找到第K大/小的数

分析:

  1. 将数组五个一组分组, 不足一组按一组计算.
  2. 将每一组都排序, 取中位数.
  3. 将中位数形成的数组再次进行BFPRT取值, 取中位数.
  4. 得到的第一个中位数作为划分点, 开始进行荷兰国旗划分(快速排序的一部分).
  5. 将原数组分为三部分, 判断第K个值在哪一部分.
  6. 如果在第一部分或第三部分, 递归调用BFPRT.
  7. 如果在第二部分, 直接返回

代码:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public static int BFPRT(int[] arr, int level)
{
if (arr == null || arr.Length < level)
{
throw new Exception("参数错误!");
}
return BFPRT(arr, level - 1, 0, arr.Length - 1);
}

public static void Swap(int[] arr, int left, int right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
}

public static int GetMiddle(int[] arr, int left, int right)
{
if (left == right)
{
return arr[left];
}
int index = left;
while (index <= right - 4)
{
Array.Sort(arr, index, 5);
index += 5;
}
if (index < right)
{
Array.Sort(arr, index, right - index + 1);
}
int count = 0;
index = left;
while (index <= right - 4)
{
Swap(arr, left + count, index + 2);
index += 5;
count++;
}
if (index < right)
{
Swap(arr, left + count, ((right - index) >> 1) + index);
count++;
}
return count == 1 ? arr[left] : BFPRT(arr, count >> 1, left, left + count - 1);
}

public static Tuple<int, int> Partition(int[] arr, int left, int right, int value)
{
int resLeft = left - 1, resRight = right + 1, index = left;
while (index < resRight)
{
if (value > arr[index])
{
Swap(arr, resLeft + 1, index);
resLeft++;
index++;
}
else if (value < arr[index])
{
Swap(arr, index, resRight - 1);
resRight--;
}
else
{
index++;
}
}
return new Tuple<int, int>(resLeft + 1, resRight - 1);
}

public static int BFPRT(int[] arr, int level, int left, int right)
{
int middle = GetMiddle(arr, left, right);
(int item1, int item2) = Partition(arr, left, right, middle);
if (level + left >= item1 && level + left <= item2)
{
return arr[item1];
}
if (level + left < item1)
{
return BFPRT(arr, level, left, item1 - 1);
}
return BFPRT(arr, level - item2 + left - 1, item2 + 1, right);
}