BFPRT算法详解

一、BFPRT算法原理

BFPRT算法(也称为中位数的中位数算法)是基于快速排序算法基础上的变种算法,用于寻找一个无序数组中第K小的数(或第K大的数)。

快速排序算法的核心思想是把一个无序数组的第一个数作为划分元素,将数组分为两个部分,左边部分的数都小于划分元素,右边部分的数都大于划分元素,然后分别对左边和右边的部分进行递归调用。但是快速排序算法的时间复杂度并不稳定,最坏情况下时间复杂度为O(n^2),这时候就需要使用BFPRT算法来解决这个问题。

BFPRT算法的核心思想是通过对数组进行特殊的划分,确定第K小的数所在的区间。它首先将数组分成若干个5个元素一组的区间,对每个小区间进行排序,然后取出每个小区间的中位数,把这些中位数作为一个新的数组。

然后递归寻找这个数组的中位数(即第N/2小的数),假设这个数是x,那么以x为中心,将数组分成两部分,如果新数组中数的个数比x小,说明第K小的数在新数组后半部分,否则在新数组前半部分。对于所选择的部分,再次递归调用进行查找,直到找到第K小的数。

int partition_median(int arr[], int left, int right) {
    // 将数组以每5个元素为一组分组,最后剩下的不足5个的单独一组
    for (int i = left; i  right) {
            sub_right = right;
        }
        // 将小组进行插入排序,可以提高查找中位数的效率
        for (int j = i + 1; j = i && arr[k] > key) {
                arr[k + 1] = arr[k];
                k--;
            }
            arr[k + 1] = key;
        }
        // 将每个小组的中位数插入到数组的前面,方便后面进行递归查找
        int mid = (i + sub_right) / 2;
        int temp = arr[mid];
        arr[mid] = arr[left + (i - left) / 5];
        arr[left + (i - left) / 5] = temp;
    }
    // 递归查找所有中位数的中位数
    int median = (left + (right - left) / 10);
    if (left < right) {
        int pivotIndex = partition_median(arr, left, right);
        int i = partition(arr, left, right, pivotIndex);
        if (median  i) {
            // 第K小的数在数组右半部分
            return partition_median(arr, i + 1, right);
        }
        else {
            // 找到第K小的数,返回其值
            return arr[i];
        }
    }
    else {
        // 数组中只有一个元素,直接返回该元素的值
        return arr[left];
    }
}

二、BFPRT算法应用

1、寻找无序数组的中位数或第K小/大的数:使用定位排序算法,将数组划分成若干个小组,对每个小组进行排序,然后将每个小组的中位数插入到一个新数组中,对新数组递归查找其中位数,以此确定第K小/大的数的位置。

int bfprt(int arr[], int left, int right, int k) {
    return partition_median(arr, left, right, k);
}

int main() {
    int arr[] = {3, 2, 1, 5, 6, 4};
    int k = 2; // 寻找第二小的数
    int n = sizeof(arr) / sizeof(arr[0]);
    int ans = bfprt(arr, 0, n - 1, k - 1);
    cout << "第" << k << "小的数是:" << ans << endl;
}

2、求无序数组的中位数与排序时间的实现:使用标准库函数qsort排序,然后计算数组的中位数。这里定义了一个类,其中构造函数中调用了qsort函数,并获取数组的中位数,计算排序所需的时间。

class Median {
public:
    double median_;
    double sort_time_;

    Median(int arr[], int n) {
        clock_t start_time = clock();
        qsort(arr, n, sizeof(int), cmp);
        sort_time_ = (double)(clock() - start_time) / CLOCKS_PER_SEC;

        if (n % 2 == 0) {
            median_ = (double)(arr[n / 2 - 1] + arr[n / 2]) / 2.0;
        } else {
            median_ = (double)arr[n / 2];
        }
    }

    static int cmp(const void* a, const void* b) {
        return *(int*)a - *(int*)b;
    }
};

int main() {
    int arr[] = {3, 2, 1, 5, 6, 4};
    int n = sizeof(arr) / sizeof(arr[0]);
    int k = (n + 1) / 2;
    Median m(arr, n);
    cout << "排序所需时间: " << m.sort_time_ << "s" << endl;
    cout << "无序数组的中位数: " << m.median_ << endl;
}

三、BFPRT算法的优缺点

优点:

1、时间复杂度稳定,最坏情况下也只需要O(n)的时间复杂度。

2、与快速排序算法相比,BFPRT算法在大量数据的排序上表现更加优秀。

3、在寻找数组中第K小/大的数时,其所需时间不超过O(n)。

缺点:

1、在查找较小的K值时,效率可能会变慢。尤其是当K比较小,但N非常大的时候,会造成很大的时间开销。

2、算法比较复杂,实现起来比较困难。

四、BFPRT算法的应用案例

1、使用BFPRT算法实现一道LeetCode的问题,寻找乱序数组中的第K大的元素。

class Solution {
public:
    int findKthLargest(vector& nums, int k) {
        int n = nums.size();
        int arr[n];
        for (int i = 0; i < n; i++) {
            arr[i] = nums[i];
        }
        int ans = bfprt(arr, 0, n - 1, n - k);
        return ans;
    }
};

int main() {
    Solution s;
    vector nums = {3,2,1,5,6,4};
    int k = 2;
    int ans = s.findKthLargest(nums, k);
    cout << "第" << k << "大的数是:" << ans << endl;
}

2、使用BFPRT算法对海量数据进行快速排序。

// 将数组划分成若干个小区间,对每个小区间排序,然后获取各个小区间的中位数即可
template 
void bfprt_sort(vector& nums, int left, int right, int k) {
    if (left >= right) {
        return;
    }
    if (right - left + 1 <= 5) {
        sort(nums.begin()+left, nums.begin()+right+1);
        return;
    }
    int pivotIndex = partition_median(nums, left, right);
    int index = partition(nums, left, right, pivotIndex);
    if (k  index) {
        bfprt_sort(nums, index+1, right, k);
    } else {
        return;
    }
}

template 
void big_data_sort(vector& nums) {
    int len = nums.size();
    int left = 0;
    int right = len - 1;
    int group_num = len / 5;
    int mod_num = len % 5;
    vector helper;
    for (int i = 0; i  0) {
        sort(nums.begin() + group_num*5, nums.begin() + group_num*5 + mod_num);
        helper.push_back(nums[group_num*5 + mod_num/2]);
    }
    // 新数组中的中位数即为整个数组的中位数
    int median_index = helper.size() / 2;
    bfprt_sort(helper, 0, helper.size()-1, median_index);
    T median = helper[median_index];
    // 使用整个数组的中位数进行划分
    int pivot_index = partition_big_data(nums, left, right, median);
    int k = len / 2;
    if (len % 2 == 0) {
        bfprt_sort(nums, left, right, k-1);
    } else {
        bfprt_sort(nums, left, right, k);
    }
}

五、总结

BFPRT算法是一种常见的查找算法,其能够在大量数据的排序问题中表现出较高的效率和稳定性。通过对数据进行特殊的划分和查找,BFPRT算法能够寻找无序数组中第K小/大的数,得到数组的中位数,或对大量数据进行快速排序等应用。

原创文章,作者:PTQS,如若转载,请注明出处:https://www.506064.com/n/144581.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
PTQSPTQS
上一篇 2024-10-25 13:53
下一篇 2024-10-25 13:53

相关推荐

  • 蝴蝶优化算法Python版

    蝴蝶优化算法是一种基于仿生学的优化算法,模仿自然界中的蝴蝶进行搜索。它可以应用于多个领域的优化问题,包括数学优化、工程问题、机器学习等。本文将从多个方面对蝴蝶优化算法Python版…

    编程 2025-04-29
  • Python实现爬楼梯算法

    本文介绍使用Python实现爬楼梯算法,该算法用于计算一个人爬n级楼梯有多少种不同的方法。 有一楼梯,小明可以一次走一步、两步或三步。请问小明爬上第 n 级楼梯有多少种不同的爬楼梯…

    编程 2025-04-29
  • AES加密解密算法的C语言实现

    AES(Advanced Encryption Standard)是一种对称加密算法,可用于对数据进行加密和解密。在本篇文章中,我们将介绍C语言中如何实现AES算法,并对实现过程进…

    编程 2025-04-29
  • Harris角点检测算法原理与实现

    本文将从多个方面对Harris角点检测算法进行详细的阐述,包括算法原理、实现步骤、代码实现等。 一、Harris角点检测算法原理 Harris角点检测算法是一种经典的计算机视觉算法…

    编程 2025-04-29
  • 数据结构与算法基础青岛大学PPT解析

    本文将从多个方面对数据结构与算法基础青岛大学PPT进行详细的阐述,包括数据类型、集合类型、排序算法、字符串匹配和动态规划等内容。通过对这些内容的解析,读者可以更好地了解数据结构与算…

    编程 2025-04-29
  • 瘦脸算法 Python 原理与实现

    本文将从多个方面详细阐述瘦脸算法 Python 实现的原理和方法,包括该算法的意义、流程、代码实现、优化等内容。 一、算法意义 随着科技的发展,瘦脸算法已经成为了人们修图中不可缺少…

    编程 2025-04-29
  • 神经网络BP算法原理

    本文将从多个方面对神经网络BP算法原理进行详细阐述,并给出完整的代码示例。 一、BP算法简介 BP算法是一种常用的神经网络训练算法,其全称为反向传播算法。BP算法的基本思想是通过正…

    编程 2025-04-29
  • 粒子群算法Python的介绍和实现

    本文将介绍粒子群算法的原理和Python实现方法,将从以下几个方面进行详细阐述。 一、粒子群算法的原理 粒子群算法(Particle Swarm Optimization, PSO…

    编程 2025-04-29
  • Python回归算法算例

    本文将从以下几个方面对Python回归算法算例进行详细阐述。 一、回归算法简介 回归算法是数据分析中的一种重要方法,主要用于预测未来或进行趋势分析,通过对历史数据的学习和分析,建立…

    编程 2025-04-28
  • 象棋算法思路探析

    本文将从多方面探讨象棋算法,包括搜索算法、启发式算法、博弈树算法、神经网络算法等。 一、搜索算法 搜索算法是一种常见的求解问题的方法。在象棋中,搜索算法可以用来寻找最佳棋步。经典的…

    编程 2025-04-28

发表回复

登录后才能评论