优化函数以查找最小和最大元素

时间:2015-08-02 11:41:10

标签: c++ arrays optimization

我有以下代码,但我需要优化它以获得更好的运行时间。这是可能的。 这里minLR从左到右取出min元素 minRL其他从右到左。我无法使用标准库函数,因为我也必须反向迭代。 我必须从' left'增加数组的min元素。以'右'如果'我'通过查找来自' r'的min元素是奇数和增量数组。到'升'如果'我'甚至。 米很大。

int minLR(int *arr,int s){
    int ind=0;
    int min=arr[0];
    for(int i=1;i<s;i++){
        if(min>arr[i]){min=arr[i];ind=i;}
    }
    arr[ind]++;
    return ind;
}

int minRL(int *arr,int s){
    int ind=s-1;
    int min=arr[s-1];
    for(int i=s-2;i>=0;i--){
        if(min>arr[i]){ min=arr[i];ind=i;}
    }
    arr[ind]++;
    return ind;
}

for(int i=1;i<=m;i++){
    if(i%2==0){
        ind=minRL(arr,n);    
    }
    if(i%2!=0){
        ind=minLR(arr,n);
    }
}

2 个答案:

答案 0 :(得分:2)

查找最小值或最大值或最小值和最大值的复杂度始终为O(n)。如果阵列必须保持未排序,则无法改进。

使用您的原始方法

通过巧妙地将搜索最小值和最大值同时组合,使用稍微改进的算法in this article,可以最大限度地提高性能。

然后,您将在每次最小/最大搜索时节省n / 2-2比较。但这不会改变每次搜索的O(n)的数量级。所以整体算法将保持在O(n²)。

替代尊重您的方法

另一种方法是使用指向未排序表中元素的阴影排序数据结构。这是一个基于标准向量和算法的实现:

vector<int*> myshadow(n);  // sorted shadow structure 
transform(arr, arr+n, myshadow.begin(), [](int& x)->int* { return &x; });

for(int i = 0; i < n; i++){
    sort(myshadow.begin(), myshadow.end(), [](int* a, int*b)->bool { return *a < *b; }); 
    // now myshadow[0] holds the smallest element:  
    if(i % 2 == 0)
        minRLi(myshadow, n);
    else minLRi(myshadow, n);
}

结果与原始算法相同,以下函数以优化方式复制左右搜索(循环仅迭代几个最小元素):

int* minLRi(vector<int *>arr, int s){
    int ind = 0;
    int* min = arr[0]; // min shall be the smallest element address of the same minimal value (leftmost)
    for(int i = 1; i<s && *arr[0]==*arr[i]; i++){
        if(min>arr[i]){ min = arr[i]; ind = i; }
    }
    (*arr[ind])++;
    return arr[ind]; 
}
int* minRLi(vector<int *>arr, int s){
    int ind = 0;
    int* min = arr[0]; // min shall be the largest element address of the same minimal value (rightmost)
    for(int i = 1; i<s && *arr[0] == *arr[i]; i++){
        if(min<arr[i]){ min = arr[i]; ind = i; }
    }
    (*arr[ind])++;
    return arr[ind];
}

进一步优化

现在我假设std::sort()在重新排序几乎已排序的向量时非常有效。实验告诉我,至少在我的MSVC2013上,这根本不是真的。 PPerformance是灾难性的结果。

所以我稍微修改了优化求助的代码。

优化代码可以是viewed and tried online here

结论

我没有时间深入分析它,但我认为复杂性应该在O(nlog(n))附近。

20万随机元素的实际实验(MSVC 2013,发布,i7处理器)显示:

  • 你的原始方法需要30秒(1 345百万次迭代!!)
  • 阴影替代方案需要32毫秒(631千次迭代)

答案 1 :(得分:1)

一个更有效的解决方案(假设非常大的n)是首先将数据转录到std :: set的std :: map,然后对其进行处理:

地图的关键字是在数组中出现一次或多次的值。地图的有效负载将是值出现在数组中的所有位置的集合。这很容易且相对有效地构建。

然后很容易找到方向独立min(地图中的第一个元素)并从该min set中取出左或右元素并将其移动到下一个更高的min set。

如果您使用优先级队列而不是地图,编程的复杂性会更高,效率会更好。

据我所知,标准优先级队列不能让您轻松访问第二个优先级元素(访问它,修改它,可能插入新的第二优先级,同时保持第一个优先级不变)。我通常会创建自己的优先级队列以获得类似的额外功能,所以我不确定标准版本是否可以被推到那么远,或者你是否需要发明自己的。