C++ 我还能在哪里改进这种合并排序 虚拟索引和排序(索引和数据) { //基本情况 向量temp1,temp2,temp3; //对于(int i=0;i
您的代码过于复杂。合并排序有两个部分:divide和merge。每个部分都应该是一个函数 您还应该具有顶级功能(用户将使用的公共界面) 为了获得最大的速度,您应该在顶级函数中分配一次所需的所有额外内存,并将其向下传递以供较低级别的函数使用。(使用向量并根据数据长度调整大小。) 当(end-begin==0)是一对浪费的函数调用时,不要见底。当它们的差异为2时停止。对这两个函数进行排序,然后开始在树的后面工作 您的合并算法应该都在一个函数中,您可以对其进行一些清理。基本合并算法是:C++ 我还能在哪里改进这种合并排序 虚拟索引和排序(索引和数据) { //基本情况 向量temp1,temp2,temp3; //对于(int i=0;i,c++,mergesort,C++,Mergesort,您的代码过于复杂。合并排序有两个部分:divide和merge。每个部分都应该是一个函数 您还应该具有顶级功能(用户将使用的公共界面) 为了获得最大的速度,您应该在顶级函数中分配一次所需的所有额外内存,并将其向下传递以供较低级别的函数使用。(使用向量并根据数据长度调整大小。) 当(end-begin==0)是一对浪费的函数调用时,不要见底。当它们的差异为2时停止。对这两个函数进行排序,然后开始在树的后面工作 您的合并算法应该都在一个函数中,您可以对其进行一些清理。基本合并算法是: A和B都有元
- A和B都有元素:
- 如果A的第一个元素小于B的第一个元素:
- 删除并将其附加到结果
- 否则删除B并将其附加到结果中
- 如果A的第一个元素小于B的第一个元素:
- 在结果中附加仍然包含元素(A或B)的序列
希望这能有所帮助。首先,要知道霍尔将他的新排序命名为“快速排序”是有充分理由的——它比当时已知的其他排序(包括合并排序)要快得多。换句话说,不要指望合并排序能跟上快速排序(作为一般规则),几乎不管它的实现有多好 也就是说,您通常可以比这里更好地实现合并排序。特别是,合并排序可以“自下而上”而不是“自上而下”实现。现在,您的函数基本上将数组拆分为两半,然后调用自身对数组的每一半进行排序 所以,你做了很多递归调用,基本上每个都是计算需要排序的数组中间部分的索引。这给一个相对简单的计算增加了相当多的开销 最后,不管怎样,这样做的结果几乎是必然的。你总是不断地进行递归调用,直到一个分区只有一两个元素(大约) 就所需的额外空间而言,一个与输入大小相同的额外数组就足够了(尽管这不是绝对必要的,但就地合并技术增加了复杂性,因此它们更难正确写入,而且运行速度也更慢) 既然您知道要拆分数组,直到只得到两个项目,那么您可以首先从那里开始。只需获取第一对元素,如果它们的顺序不正确,则交换它们。对于数组的其余部分,继续使用对 然后进入合并阶段:将第一对与第二对合并,第三对与第四对合并,依此类推。继续对数组的其余部分进行合并。重复该过程,直到对整个数组进行排序
不过,您通常不希望一个分区中只有两个项目。您通常希望一次对(比如)10个项目进行插入排序,然后进入合并阶段(尽管精确的大小并不重要).这里的问题最多是常数因素,而不是渐进性能。尽管如此,过早进行微观优化的风险很大。也就是说,在不那么过早的情况下,仍然值得学习如何进行优化,所以 首先,高性能排序总是混合算法如果n足够小,像插入排序这样的算法实际上是非常好的,所以当n变小时,实用的排序算法往往会切换策略。如果你对一百万个项目进行排序,而策略切换发生在n=10,听起来你可能只会受益于一个微不足道的10个项目排序,但这种情况大约会发生100000次对你的百万物品进行分类,这样累积的利益就能得到很好的回报 对于一个硬编码的which-permutation-am-I-in嵌套的ifs集合,甚至有一个非常小的n的情况,这样,对于每个置换,一个预先确定的移动/交换的最佳集合被应用。例如,对于n=3,有6种可能的项目顺序-6种情况需要检测,6种移动/交换需要计算。对于n=4,现在是24种情况,所以你会感到非常痛苦,不要忘记太多的代码也会减慢速度 一旦你确定算法本身是正确的,看看哪些工作可以从内部循环中移出。这有双重好处——首先,工作做得更少。其次,内部循环本身变得更简单,因此编译器可以更好地对其进行优化。当然,代价是代码的总体复杂性增加,而且要小心——编译器会uld已经在为您做一些这方面的工作了,因此很容易不仅浪费时间让编译器为其工作,而且会因为出错而引入错误,并阻止其他编译器优化,最终导致代码变慢 回归测试,测量前后的性能,如有疑问,检查生成的机器代码等 不过,一个明显的目标是——使用一个循环很方便,每次迭代时都要检查要合并的一个/另一个源是否耗尽,但这也是低效的。因此,当任一源耗尽时,检测一次,并使用一个特例循环来完成对另一个源的处理 另外,为了避免在每个循环中都进行穷举检查,如果其中项目最少的源数组有k个项目,则可以在不进行穷举检查的情况下安全地进行k次迭代。因此,可以在外部循环中检查k是什么,在k个项目上进行内部循环,而不进行穷举检查 第二点使内部循环在大多数合并过程中保持简单,最后的好处较少(因为每次检查时k都会变小)。它还增加了额外的复杂性-外部循环-因此它不是免费的
virtual Indexed<T>& sort(Indexed<T>& data)
{
//base case
Vector<T> temp1, temp2, temp3;
//for (int i = 0; i < data.getSize(); i++)
//{
// cout << data.getElementAt(i) << ", ";
//}
mergeSortHelper(data, 0, data.getSize() - 1, temp1, temp2);
for (int i = 0; i < data.getSize(); i++)
{
cout << data.getElementAt(i) << ", ";
}
cout << endl;
return data;
}
void mergeSortHelper(Indexed<T>& data, int begin, int end, Vector<T> &left, Vector<T> &right)
{
//base case, if there is only 1 item in each side, merge them and return
if ((begin - end) == 0)
{
//left.setElementAt(data.getElementAt(begin), 0);
//left = storage;
return;
}
else
{
//Vector<T> right;
int midPoint = (end + begin) / 2;
mergeSortHelper(data, begin, midPoint, left, right);
mergeSortHelper(data, midPoint + 1, end, left, right);
//perform merging
int i = 0, leftCounter = 0, leftLimit = (midPoint - begin) + 1, rightCounter = 0, rightLimit = (end - (midPoint + 1)) + 1;
for (int i = 0; i < leftLimit; i++)
{
if (i < leftLimit)
left.setElementAt(data.getElementAt(begin + i), i);
if (i < rightLimit)
right.setElementAt(data.getElementAt(midPoint + 1 + i), i);
//cout << left.getElementAt(i) << ", ";
}
while (leftCounter < leftLimit || rightCounter < rightLimit)
{
if (leftCounter >= leftLimit)
{
//done sorting the left side
data.setElementAt(right.getElementAt(rightCounter), begin + i);
//temp.setElementAt(right.getElementAt(rightCounter), i);
rightCounter++;
}
else if (rightCounter >= rightLimit)
{
//done sorting the right side
data.setElementAt(left.getElementAt(leftCounter), begin + i);
//temp.setElementAt(left.getElementAt(leftCounter), i);
leftCounter++;
}
else
{
if (left.getElementAt(leftCounter) < right.getElementAt(rightCounter))
{
data.setElementAt(left.getElementAt(leftCounter), begin + i);
//temp.setElementAt(left.getElementAt(leftCounter), i);
leftCounter++;
}
else if (left.getElementAt(leftCounter) > right.getElementAt(rightCounter))
{
data.setElementAt(right.getElementAt(rightCounter), begin + i);
//temp.setElementAt(right.getElementAt(rightCounter), i);
rightCounter++;
}
else
{
data.setElementAt(right.getElementAt(rightCounter), begin + i);
//temp.setElementAt(right.getElementAt(rightCounter), i);
i++;
data.setElementAt(left.getElementAt(leftCounter), begin + i);
//temp.setElementAt(left.getElementAt(leftCounter), i);
leftCounter++;
rightCounter++;
}
}
i++;
}
}
//return temp;
template <typename T>
void BottomUpMergeSort(T a[], T b[], size_t n);
template <typename T>
void BottomUpCopy(T a[], T b[], size_t ll, size_t rr);
template <typename T>
void BottomUpMerge(T a[], T b[], size_t ll, size_t rr, size_t ee);
template <typename T>
void MergeSort(T a[], size_t n) // entry function
{
if(n < 2) // if size < 2 return
return;
T *b = new T[n];
BottomUpMergeSort(a, b, n);
delete[] b;
}
size_t GetPassCount(size_t n) // return # passes
{
size_t i = 0;
for(size_t s = 1; s < n; s <<= 1)
i += 1;
return(i);
}
template <typename T>
void BottomUpMergeSort(T a[], T b[], size_t n)
{
size_t s = 1; // run size
if(GetPassCount(n) & 1){ // if odd number of passes
for(s = 1; s < n; s += 2) // swap in place for 1st pass
if(a[s] < a[s-1])
std::swap(a[s], a[s-1]);
s = 2;
}
while(s < n){ // while not done
size_t ee = 0; // reset end index
while(ee < n){ // merge pairs of runs
size_t ll = ee; // ll = start of left run
size_t rr = ll+s; // rr = start of right run
if(rr >= n){ // if only left run
rr = n;
BottomUpCopy(a, b, ll, rr); // copy left run
break; // end of pass
}
ee = rr+s; // ee = end of right run
if(ee > n)
ee = n;
BottomUpMerge(a, b, ll, rr, ee);
}
std::swap(a, b); // swap a and b
s <<= 1; // double the run size
}
}
template <typename T>
void BottomUpCopy(T a[], T b[], size_t ll, size_t rr)
{
while(ll < rr){ // copy left run
b[ll] = a[ll];
ll++;
}
}
template <typename T>
void BottomUpMerge(T a[], T b[], size_t ll, size_t rr, size_t ee)
{
size_t o = ll; // b[] index
size_t l = ll; // a[] left index
size_t r = rr; // a[] right index
while(1){ // merge data
if(a[l] <= a[r]){ // if a[l] <= a[r]
b[o++] = a[l++]; // copy a[l]
if(l < rr) // if not end of left run
continue; // continue (back to while)
while(r < ee) // else copy rest of right run
b[o++] = a[r++];
break; // and return
} else { // else a[l] > a[r]
b[o++] = a[r++]; // copy a[r]
if(r < ee) // if not end of right run
continue; // continue (back to while)
while(l < rr) // else copy rest of left run
b[o++] = a[l++];
break; // and return
}
}
}
template <typename T>
void TopDownSplitMergeAtoA(T a[], T b[], size_t ll, size_t ee);
template <typename T>
void TopDownSplitMergeAtoB(T a[], T b[], size_t ll, size_t ee);
template <typename T>
void TopDownMerge(T a[], T b[], size_t ll, size_t rr, size_t ee);
template <typename T>
void MergeSort(T a[], size_t n) // entry function
{
if(n < 2) // if size < 2 return
return;
T *b = new T[n];
TopDownSplitMergeAtoA(a, b, 0, n);
delete[] b;
}
template <typename T>
void TopDownSplitMergeAtoA(T a[], T b[], size_t ll, size_t ee)
{
if((ee - ll) == 1) // if size == 1 return
return;
size_t rr = (ll + ee)>>1; // midpoint, start of right half
TopDownSplitMergeAtoB(a, b, ll, rr);
TopDownSplitMergeAtoB(a, b, rr, ee);
TopDownMerge(b, a, ll, rr, ee); // merge b to a
}
template <typename T>
void TopDownSplitMergeAtoB(T a[], T b[], size_t ll, size_t ee)
{
if((ee - ll) == 1){ // if size == 1 copy a to b
b[ll] = a[ll];
return;
}
size_t rr = (ll + ee)>>1; // midpoint, start of right half
TopDownSplitMergeAtoA(a, b, ll, rr);
TopDownSplitMergeAtoA(a, b, rr, ee);
TopDownMerge(a, b, ll, rr, ee); // merge a to b
}
template <typename T>
void TopDownMerge(T a[], T b[], size_t ll, size_t rr, size_t ee)
{
size_t o = ll; // b[] index
size_t l = ll; // a[] left index
size_t r = rr; // a[] right index
while(1){ // merge data
if(a[l] <= a[r]){ // if a[l] <= a[r]
b[o++] = a[l++]; // copy a[l]
if(l < rr) // if not end of left run
continue; // continue (back to while)
while(r < ee) // else copy rest of right run
b[o++] = a[r++];
break; // and return
} else { // else a[l] > a[r]
b[o++] = a[r++]; // copy a[r]
if(r < ee) // if not end of right run
continue; // continue (back to while)
while(l < rr) // else copy rest of left run
b[o++] = a[l++];
break; // and return
}
}
}