-
Notifications
You must be signed in to change notification settings - Fork 7
/
util.c
89 lines (66 loc) · 2.18 KB
/
util.c
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
87
88
typedef union pgnum {
int16 i16;
int32 i32;
int64 i64;
float4 f4;
float8 f8;
} pgnum;
/*
* This Quickselect routine is based on the algorithm described in
* "Numerical recipes in C", Second Edition,
* Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5
* This code adapted from Public domain code by Nicolas Devillard - 1998 from here:
* http://ndevilla.free.fr/median/median/index.html
*/
#define ELEM_SWAP(a,b) { register float8 t=(a);(a)=(b);(b)=t; }
float8 select_kth_value(float8 *arr, int n, int k);
float8 select_kth_value(float8 *arr, int n, int k) {
int low, high;
int middle, ll, hh;
low = 0;
high = n-1;
for (;;) {
// One element only
if (high <= low) return arr[k];
// Two elements only
if (high == low + 1) {
if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]);
return arr[k];
}
// Find median of low, middle and high items; swap into position low
middle = (low + high) / 2;
if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ;
if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ;
if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ;
// Swap low item (now in position middle) into position (low+1)
ELEM_SWAP(arr[middle], arr[low+1]) ;
// Nibble from each end towards middle, swapping items when stuck
ll = low + 1;
hh = high;
for (;;) {
do ll++; while (arr[low] > arr[ll]);
do hh--; while (arr[hh] > arr[low]);
if (hh < ll) break;
ELEM_SWAP(arr[ll], arr[hh]);
}
// Swap middle item (in position low) back into correct position
ELEM_SWAP(arr[low], arr[hh]);
// Re-set active partition
if (hh <= k) low = ll;
if (hh >= k) high = hh - 1;
}
}
#undef ELEM_SWAP
typedef struct {
float8 value;
int count;
} valcount;
int compare_float8(const void *a, const void *b);
int compare_valcount(const void *a, const void *b);
int compare_float8(const void *a, const void *b) {
float8 x = *(const float8*)a - *(const float8*)b;
return x < 0 ? -1 : x > 0;
}
int compare_valcount(const void *a, const void *b) {
return ((const valcount*)b)->count - ((const valcount*)a)->count;
}