我们经常在排序算法中会遇见这样的一种情况,数组中连续的两个值会不停的相互交换,类似于我们前面在插入排序和堆排序中的swap()优化,例如:
在我们的插入排序算法中:
原始的交换操作为:
void insertsort(T arr[],int n)
{
for(int i=1;i<n;i++)
{
for(int j=i;j>0&&arr[j]<arr[j-1];j--)
{
swap(arr[j],arr[j-1]);
}
}
}
void swap(int &a, int &b) //引用类型方式
{
int temp; //辅助变量
temp = a;
a = b;
b = temp;
}
这样在每次相互交换的时候都会浪费大量的时间,那么我们有没有什么优化的方法能够尽量的去减少这样的swap操作,也就是减少赋值操作呢?当然有,首先,让我们研究一下连续赋值的规律:首先,如上图所示,假设如果数组前一位比后一位的数要小,则进行交换操作,这样就可以尽量把大的值往前排,第一次操作,第三层与第二层交换,第二次操作,第二层与第一层交换。这样我们就使数字3排到了他应该在的位置。我们来计算一下这种交换操作的消耗,因为使用了2次swap操作,实际上就进行了2*3=6次的赋值操作,那么我们来看一下优化的方法。
如上图所示,我们可以先声明一个变量用来保存起始需要开始变化的值,如上图中的数字3,我们先给他复制一份,然后以同样的方法让其与其前面的数字比较,如果其数字比前面的数字要大,我们不进行swap()交换操作,而是直接让其被赋值为前一位数字,然后我们在去查看第二位的数字,以同样的方法,如果也需要进行swap()的交换操作,我们还是直接让其被赋值为前一位的数字,知道我们发现有一个数字不比他的前置位数字要大了,也就是说不用再进行swap交换操作了,此时我们会发现因为他的后一位已经继承了他的值,所以此时就会出现重复的情况,那么这个不能交换的值该何去何从呢?不用急,别忘了我们还保存了一份最起始的开始值,只要把这个开始值赋给他就好了,我们会惊奇的发现,这样操作下来,3还是排到了应该排的位置,但是我们计算一下,这样的赋值操作只用到了一共4次!!!所以在插入排序中优化过后的swap()函数是这样的:
template<typename T>
void pinsertsort(T arr[],int n)
{
for(int i=1;i<n;i++)
{
T e=arr[i];
int j;
for(j=i;j>0&&arr[j-1]>e;j--)
{
arr[j]=arr[j-1];
}
arr[j]=e;
}
}
以下是他们所花费的时间:
我们可以清楚的看到,没有优化的插入排序算法所用的时间为15秒,而优化了交换操作的插入排序算法却只用了7秒,差不多为原来的一半,使得插入算法的效率大大的提高了。这样的优化不仅仅可以用在插入排序算法上,还可以用在堆排序上等需要进行连续交换操作的算法上。
博客文章版权说明
第一条 本博客文章仅代表作者本人的观点,不保证文章等内容的有效性。
第二条 本博客部分内容转载于合作站点或摘录于部分书籍,但都会注明作/译者和原出处。如有不妥之处,敬请指出。
第三条 在征得本博客作者同意的情况下,本博客的作品允许非盈利性引用,并请注明出处:“作者:____转载自____”字样,以尊重作者的劳动成果。版权归原作/译者所有。未经允许,严禁转载。
第四条 对非法转载者,“扬俊的小屋”和作/译者保留采用法律手段追究的权利。
第五条 本博客之声明以及其修改权、更新权及最终解释权均属“扬俊的小屋”。
第六条 以上声明的解释权归“扬俊的小屋”所有。