//数组大小确定 找第k大 一个位置确定(分治(快排))的值的的下标正好等于k 这个数为第k大 //因为数组大小确定 类似二分 当一个划分后的数的下标正好等于 k 时 此数为要查找数 //而因为为划分后的数 所以可以明显知道 求的 k 个数是在左边还是右边
void nswap(int &a, int &b) { int t = a; a = b; b = t; }
void bubble(int *arr, int l, int r) { for (int i = l; i < r + 1; ++i) for (int j = l; j < r - i; ++j) if (*(arr + j) < *(arr + j + 1)) neSwap(*(arr + j), *(arr + j + 1)); }
int parttion(int *arr, int l, int r, int loc) { int i = l - 1; nswap(*(arr + loc), *(arr + r));//交换到右边 进行划分 for (int j = l; j < r; ++j) if (*(arr + j) < *(arr + r)) nswap(*(arr + (++i)), *(arr + j)); nswap(*(arr + (++i)), *(arr + r));//将r移到准确位置 return i; }
//找出中位数 的中位数 对数组进行划分 找出第 k 大所在的左右位置 递归找出第k大数
int select(int *arr, int l, int r, int n, int k) {//k代表第几大 n代表元素个数 int i = 0;//片段内游标 int size = r - l + 1;//片段大小 //排序得到中位数 for (; i < size / 5; ++i) {//片段内元素个数为 r-l+1 个 bubble(arr, 5 * i + l, 5 * i + l + 4);//排序 nswap(arr[l + i], arr[l + 5 * i + 2]);//将中位数添加到前面方便查找中位数 } //不足5个 排序得到中位数 bubble(arr, i * 5 + l, r);//跳到没有5个的位置 nswap(arr[l + i], arr[(l + r + 1 + i * 5) / 2]);//交换中位数较小的哪一位arr + l + i * 5 + (size - i * 5) / 2) //找出中位数的中位数 bubble(arr, l, l + i); //按位置划分 并得到准确位置 int loc = parttion(arr, 0, n - 1, l + i / 2); if (loc == k) return arr[loc]; else if (loc > k) return select(arr, l, loc - 1, n, k); else if (loc < k)return select(arr, loc + 1, r, n, k); }
int BFPRT(int *arr, int n, int k) { if (k > 0 && k <= n) { return select(arr, 0, n - 1, n, k - 1); } } |