Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将一个数组的每个元素乘以另一个数组的每个元素,然后对新的非常大的数组进行排序_Java_C++_Algorithm_Sorting - Fatal编程技术网

Java 将一个数组的每个元素乘以另一个数组的每个元素,然后对新的非常大的数组进行排序

Java 将一个数组的每个元素乘以另一个数组的每个元素,然后对新的非常大的数组进行排序,java,c++,algorithm,sorting,Java,C++,Algorithm,Sorting,免责声明 这是我的课程练习,不是正在进行的比赛 问题描述 问题描述非常直截了当: 给出了两个数组A和B,分别包含n和m个元素。你需要排序的数字是Ai*Bj,因为1答案的线索在于你的观察 如果我们先对两个数组A和B排序,然后将它们相乘,我们得到 2 8 14 18 7 28 49 63 8 32 56 72 11 44 77 99这是一个带有m 已排序的子阵列 所以有n个数据序列被排序,问题是使用这些序列来生成答案 提示1:您可以使用优先级队列解决此问题吗。队列中元素的数量将与生成的已排序列表的数

免责声明 这是我的课程练习,不是正在进行的比赛

问题描述

问题描述非常直截了当:


给出了两个数组A和B,分别包含n和m个元素。你需要排序的数字是Ai*Bj,因为1答案的线索在于你的观察

如果我们先对两个数组A和B排序,然后将它们相乘,我们得到
2 8 14 18 7 28 49 63 8 32 56 72 11 44 77 99
这是一个带有m 已排序的子阵列

所以有n个数据序列被排序,问题是使用这些序列来生成答案

提示1:您可以使用优先级队列解决此问题吗。队列中元素的数量将与生成的已排序列表的数量相同

我测量了

double Faster(std::vector<int> lhs, std::vector<int>  rhs)
{
    Counter result;
    if (lhs.size() == 0 || rhs.size() == 0) return 0;

    std::sort(lhs.begin(), lhs.end());
    std::sort(rhs.begin(), rhs.end());
    if (lhs.size() < rhs.size()) {
        std::swap(lhs, rhs);
    }
    size_t l = 0;
    size_t r = 0;
    size_t lhs_size = lhs.size();
    size_t rhs_size = rhs.size();
    std::priority_queue<Generator, std::vector< Generator >, MinHeap > queue;
    for (size_t i = 0; i < lhs_size; i++) {
        queue.push(Generator(i, 0, lhs[i] * rhs[0]));
    }
    Generator curr;
    while (queue.size()) {
        curr = queue.top();
        queue.pop();
        result.push_back(curr.product);
        curr.i_rhs++;
        if( curr.i_rhs < rhs_size ){
            queue.push(Generator(curr.i_lhs, curr.i_rhs, lhs[curr.i_lhs] * rhs[curr.i_rhs]));
        }
    }
    return result.sum();
 }
速度加倍(std::vector lhs,std::vector rhs)
{
反结果;
if(lhs.size()==0 | | rhs.size()==0)返回0;
排序(lhs.begin(),lhs.end());
排序(rhs.begin(),rhs.end());
如果(lhs.size()queue;
对于(大小i=0;i
要比下面的简单实现更快

double Naive(std::vector<int> lhs, std::vector<int>  rhs)
{
    std::vector<int> result;
    result.reserve(lhs.size() * rhs.size());
    for (size_t i = 0; i < lhs.size(); i++) {
        for (size_t j = 0; j < rhs.size(); j++) {
            result.push_back(lhs[i] * rhs[j]);
        }
    }
    std::sort(result.begin(), result.end());
    Counter aCount;
    for (size_t i = 0; i < result.size(); i++) {
        aCount.push_back(result[i]);
    }
    return aCount.sum();
}
double-Naive(标准::向量lhs,标准::向量rhs)
{
std::向量结果;
结果.保留(lhs.size()*rhs.size());
对于(size_t i=0;i
排序输入向量比排序输出向量快得多。 我们为每一行创建一个生成器,它将遍历所有列。当前产品将作为优先级值添加到队列中,一旦生成了所有生成器,我们将从队列中读取它们

然后,如果每个生成器还剩下一列,我们将其添加回队列。这是从预先排序的输入的输出中有m个大小为n的子阵列的观察得出的。队列保存每个子数组的所有m个当前最小值,其中最小的一个是整个列表中剩余的最小值。当删除并重新添加生成器时,它将确保
top
值是结果的下一个最小项

循环仍然是O(nm),因为每个生成器创建一次,读取的最小值是O(1),插入队列的值是O(logn)。我们每行做一次,所以O(nm*logn+nm)简化为O(nm logn)

原始解决方案是O(nm对数nm)

我从上面的解决方案中发现的性能瓶颈是插入队列的成本,在这方面我有一个性能提升,但我不认为它比
算法
更快

合并O(mn)中所有这些已排序的子阵列

乘积<2^31,因此32位整数就足够了,基数排序基数为256就可以了。每10项的总和可能需要64位

更新-您在评论中没有提到256MB的内存限制,我只是注意到了这一点。输入数组大小为6000*6000*4=137.33MB。分配一个工作数组,其大小为原始数组的一半(四舍五入:工作数组大小=(1+原始数组大小)/2),最坏情况下,3000*6000个元素(<210MB所需总空间)。处理原始(产品)将数组分成两半,并使用基数排序对原始数组的两半进行排序。将已排序的下半部分移动到工作数组中,然后将工作数组与原始数组的上半部分合并回原始数组。在我的系统(英特尔3770K 3.5 ghz,Win 7 Pro 64位)上,两个基数排序将花费不到0.4秒的时间(每个大约0.185秒)和3000*6000个整数的一次合并大约需要0.16秒,排序部分不到0.6秒。使用这种方法,在执行乘法之前不需要对A或B排序

是否允许使用SIMD/xmm寄存器对A和B进行外积乘法(AO.x B)

基C++ 256基数排序的C++代码:< /P>

//  a is input array, b is working array
uint32_t * RadixSort(uint32_t * a, uint32_t *b, size_t count)
{
size_t mIndex[4][256] = {0};            // count / index matrix
size_t i,j,m,n;
uint32_t u;
    for(i = 0; i < count; i++){         // generate histograms
        u = a[i];
        for(j = 0; j < 4; j++){
            mIndex[j][(size_t)(u & 0xff)]++;
            u >>= 8;
        }       
    }
    for(j = 0; j < 4; j++){             // convert to indices
        m = 0;
        for(i = 0; i < 256; i++){
            n = mIndex[j][i];
            mIndex[j][i] = m;
            m += n;
        }       
    }
    for(j = 0; j < 4; j++){             // radix sort
        for(i = 0; i < count; i++){     //  sort by current lsb
            u = a[i];
            m = (size_t)(u>>(j<<3))&0xff;
            b[mIndex[j][m]++] = u;
        }
        std::swap(a, b);                //  swap ptrs
    }
    return(a);
}
//a是输入数组,b是工作数组
uint32_t*半径排序(uint32_t*a、uint32_t*b、大小计数)
{
size_t mIndex[4][256]={0};//计数/索引矩阵
尺寸i,j,m,n;
uint32_t u;
对于(i=0;i>=8;
}       
}
对于(j=0;j<4;j++){//转换为索引
m=0;
对于(i=0;i<256;i++){
n=mIndex[j][i];
mIndex[j][i]=m;
m+=n;
}       
}
对于(j=0;j<4;j++){//基数排序
对于(i=0;im=(size_t)(u>>(j
想不出任何好的解决方案来将所有这些已排序的子数组合并到O(n)
你想到的最好的方法是什么?(我想我问的是O(mn log(min(m,n))会做什么?)(没有被指定为非负的元素并不完全有帮助。)@greybeard它们都是非负的,你知道吗
// helper to catch every tenth element.
struct Counter {
    int mCount;
    double mSum;
    Counter() : mCount(0), mSum(0) {}
    void push_back(int val)
    {
        if (mCount++ % 10 == 0)
        {
            mSum += val;
        }
    }
    double sum() { return mSum; }
};

// Storage in the priority queue for each of the sorted results.
struct Generator {
    int i_lhs;
    int i_rhs;
    int product;
    Generator() : i_lhs(0), i_rhs(0), product(0) {}
    Generator(size_t lhs, size_t rhs, int p) : i_lhs(lhs), i_rhs(rhs), product(p)
    {
    }
 };

// comparitor to get lowest value product from a priority_queue
struct MinHeap
{
    bool operator()(const Generator & lhs, const Generator & rhs)
    {
        if (lhs.product > rhs.product) return true;
        return false;
    }
};
double Faster(std::vector<int> lhs, std::vector<int>  rhs)
{
    Counter result;
    if (lhs.size() == 0 || rhs.size() == 0) return 0;

    std::sort(lhs.begin(), lhs.end());
    std::sort(rhs.begin(), rhs.end());
    if (lhs.size() < rhs.size()) {
        std::swap(lhs, rhs);
    }
    size_t l = 0;
    size_t r = 0;
    size_t lhs_size = lhs.size();
    size_t rhs_size = rhs.size();
    std::priority_queue<Generator, std::vector< Generator >, MinHeap > queue;
    for (size_t i = 0; i < lhs_size; i++) {
        queue.push(Generator(i, 0, lhs[i] * rhs[0]));
    }
    Generator curr;
    while (queue.size()) {
        curr = queue.top();
        queue.pop();
        result.push_back(curr.product);
        curr.i_rhs++;
        if( curr.i_rhs < rhs_size ){
            queue.push(Generator(curr.i_lhs, curr.i_rhs, lhs[curr.i_lhs] * rhs[curr.i_rhs]));
        }
    }
    return result.sum();
 }
double Naive(std::vector<int> lhs, std::vector<int>  rhs)
{
    std::vector<int> result;
    result.reserve(lhs.size() * rhs.size());
    for (size_t i = 0; i < lhs.size(); i++) {
        for (size_t j = 0; j < rhs.size(); j++) {
            result.push_back(lhs[i] * rhs[j]);
        }
    }
    std::sort(result.begin(), result.end());
    Counter aCount;
    for (size_t i = 0; i < result.size(); i++) {
        aCount.push_back(result[i]);
    }
    return aCount.sum();
}
//  a is input array, b is working array
uint32_t * RadixSort(uint32_t * a, uint32_t *b, size_t count)
{
size_t mIndex[4][256] = {0};            // count / index matrix
size_t i,j,m,n;
uint32_t u;
    for(i = 0; i < count; i++){         // generate histograms
        u = a[i];
        for(j = 0; j < 4; j++){
            mIndex[j][(size_t)(u & 0xff)]++;
            u >>= 8;
        }       
    }
    for(j = 0; j < 4; j++){             // convert to indices
        m = 0;
        for(i = 0; i < 256; i++){
            n = mIndex[j][i];
            mIndex[j][i] = m;
            m += n;
        }       
    }
    for(j = 0; j < 4; j++){             // radix sort
        for(i = 0; i < count; i++){     //  sort by current lsb
            u = a[i];
            m = (size_t)(u>>(j<<3))&0xff;
            b[mIndex[j][m]++] = u;
        }
        std::swap(a, b);                //  swap ptrs
    }
    return(a);
}