优化一个函数,找到最小和最大元素
Optimization of a function to find min and max element
我有以下代码,但我需要优化它以获得更好的运行时间。这可能吗?这里minLR从左到右取出最小元素
minRL other从右到左。我不能使用标准库函数,因为我也必须在反向迭代。如果' I '是奇数,我必须将数组的最小元素从'左'增加到'右',如果' I '是偶数,我必须将数组的最小元素从'r'增加到'l '。M相当大。
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);
}
}
求最小值或最大值或同时求最小值和最大值的复杂度总是O(n)。如果数组必须保持未排序,则无法改进这一点。
使用原始方法
通过巧妙地同时搜索最小值和最大值,使用本文中解释的稍微改进的算法,最终可以略微提高性能。
然后在每次最小/最大搜索中省去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上,这根本不是真的。性能结果是灾难性的。
所以我稍微修改了一下代码来优化诉诸。
优化后的代码可以在这里在线查看和试用
结论我没有时间深入分析,但我认为复杂度应该在O(nlog(n))左右。
20万个随机元素的实际实验(MSVC 2013, release, i7处理器)显示:
- 你最初的方法花了30秒(134.5百万次迭代!!)
- 阴影选择耗时32毫秒(631千次迭代)
一个更有效的解决方案(假设n非常大)是首先将数据转录到std::set的std::map中,然后再处理它:
映射的键应该是在数组中出现一次或多次的值。映射的有效载荷将是该值在数组中出现的所有位置的集合。这是很容易和相对有效的构建。
然后很容易找到与方向无关的最小值(映射中的第一个元素),并从该最小集中取出左或右元素,并将其移动到下一个更高的最小集。
如果使用优先级队列而不是map,编程的复杂性会高一些,效率会好一些。
据我所知,标准优先级队列不能让您轻松访问第二个优先级元素(访问它,修改它,可能插入新的第二个优先级,而保持第一个优先级不变)。我通常发明我自己的优先级队列来获得像这样的额外功能,所以我不确定标准队列是否可以推到那么远,或者您是否需要自己发明。
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 使用不带参数的函数访问结构元素
- 使用函数"remove"删除重复元素
- 如何将元素添加到数组的线程安全函数?
- 如何通过 getter 函数删除矢量的元素?
- 如何在C++向量中奇数元素前面加上值-1,我在使用insert函数时遇到了问题
- 复制包含C++所有元素的对象!(构造函数和赋值,最佳实践?
- 如何在基类指针向量的元素上应用重载的多态函数
- 这个返回元素位置的基于循环的函数有什么问题?
- 如何在 STL 函数中找到传递给谓词的元素的索引?
- 为什么用户定义的函数不按照给定的顺序对相同长度的元素进行排序?
- 如何为 std::vector 分配内存,然后稍后为某些元素调用构造函数?
- 交换函数不是在 C++ 中交换 2D 数组的元素
- C++:带有大括号初始化列表的函数调用表达式 - 标准是否规定在单个元素列表的微不足道的情况下忽略大括号?
- 如何在 c++ 中将整个数组初始化为类构造函数中的单个元素
- 动态分配列表 - 创建一个函数,用于删除所有包含偶数值的元素
- 使用并行参数向量调用元素向量的成员函数
- C 在双链接列表中删除元素函数
- 将类向量的两个函数返回值与其他类向量元素函数进行比较
- 访问c++中的列表元素函数