数组连续交换的优化方法

我们经常在排序算法中会遇见这样的一种情况,数组中连续的两个值会不停的相互交换,类似于我们前面在插入排序和堆排序中的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]);  
        }  
    }  
}  


然而,我们会发现,每次swap()操作实际上进行了三个赋值操作:

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;  
    }  
}  



这样还不能较为直观的体现出优化的效率,我们来用这两种交换算法去给100000个随机的数字排序,把优化的交换算法命名为pinsertsort。

以下是他们所花费的时间:


我们可以清楚的看到,没有优化的插入排序算法所用的时间为15秒,而优化了交换操作的插入排序算法却只用了7秒,差不多为原来的一半,使得插入算法的效率大大的提高了。这样的优化不仅仅可以用在插入排序算法上,还可以用在堆排序上等需要进行连续交换操作的算法上。

博客文章版权说明


第一条 本博客文章仅代表作者本人的观点,不保证文章等内容的有效性。

第二条 本博客部分内容转载于合作站点或摘录于部分书籍,但都会注明作/译者和原出处。如有不妥之处,敬请指出。

第三条 征得本博客作者同意的情况下,本博客的作品允许非盈利性引用,并请注明出处:“作者:____转载自____”字样,以尊重作者的劳动成果。版权归原作/译者所有。未经允许,严禁转载

第四条 对非法转载者,“扬俊的小屋”和作/译者保留采用法律手段追究的权利

第五条 本博客之声明以及其修改权、更新权及最终解释权均属“扬俊的小屋”。

第六条 以上声明的解释权归扬俊的小屋所有。



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值