我有以下代码,但我需要优化它以获得更好的运行时间。这是可能的。 这里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);
}
}
答案 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处理器)显示:
答案 1 :(得分:1)
一个更有效的解决方案(假设非常大的n)是首先将数据转录到std :: set的std :: map,然后对其进行处理:
地图的关键字是在数组中出现一次或多次的值。地图的有效负载将是值出现在数组中的所有位置的集合。这很容易且相对有效地构建。
然后很容易找到方向独立min(地图中的第一个元素)并从该min set中取出左或右元素并将其移动到下一个更高的min set。
如果您使用优先级队列而不是地图,编程的复杂性会更高,效率会更好。
据我所知,标准优先级队列不能让您轻松访问第二个优先级元素(访问它,修改它,可能插入新的第二优先级,同时保持第一个优先级不变)。我通常会创建自己的优先级队列以获得类似的额外功能,所以我不确定标准版本是否可以被推到那么远,或者你是否需要发明自己的。