关于插入排序的bug记录

应用场景:

使用插入排序对10个元素的一维数组进行升序排序。


问题描述

出现了元素丢失和排序不正确的情况
具体代码如下:

  int main(void)
  {
     int a[10] = {1,24,3,47,5,6,7,89,12,45};
     int i;
    for(i = 1 ; i < 10;++i)
     {
          if(a[i] < a[i - 1])
         {
            int t = a[i];
              int j = i - 1;
                  for(j = i - 1;a[j] > a[i] && j > 0;--j)
                 {
                     a[j] = a[j - 1];
                 }
                     a[j +1] = t;
          }       
      }
     for(int i = 0;i < 10;++i)
     {
         printf("%d ",a[i]);
     }
     printf("\n");
 }

 输出结果

1 3 3 5 5 6 7 12 12 45 

原因分析:

首先我们先看一个正确的选择插入的代码示例:

#include
int main(void)
{
    int i = 0;
    int k = 0;
    int n = 0;
    int a[10] = {1,24,3,47,5,6,7,89,12,45};
    int len = sizeof(a)/sizeof(a[0]);
    for(i = 1;i < len;++i)
    {
         int temp = a[i];
         k = i - 1;
         while(k >=0 && a[k]>temp)
         {
             a[k + 1]=a[k];
             --k;
         }
         a[k + 1] = temp;    
    }
    for(n = 0;n < len;++n)
    {
        printf("%d ",a[n]);
    }
    printf("\n");
    return 0;
}

 输出结果为:

1 3 5 6 7 12 24 45 47 89

语句冗余

  int main(void)
  {
     int a[10] = {1,24,3,47,5,6,7,89,12,45};
     int i;
    for(i = 1 ; i < 10;++i)
     {
 7         if(a[i] < a[i - 1])//判断a[i] 和 a[i -1]大小
         {
            int t = a[i];
            int j = i - 1;//将 j 赋值为i - 1;
11            for(j = i - 1;a[j] > a[i] && j > 0;--j)//循环条件判断a[i] 和 a[j]
            {
                a[j] = a[j - 1];
            }
                a[j + 1] = t;
          }       
      }
     for(int i = 0;i < 10;++i)
     {
         printf("%d ",a[i]);
     }
     printf("\n");
 }

阅读代码可知,j = i - 1,那么11行代码a[i]与a[j]的比较可以等价为a[i] 和 a[i - 1]的比较,与4行的语句作用重复。因为插入排序要求进行a[i] 和 a [i - 1]多次比较,所以应该删除4行语句。

修改为:

  int main(void)
  {
     int a[10] = {1,24,3,47,5,6,7,89,12,45};
     int i;
    for(i = 1 ; i < 10;++i)
    {
          
       int t = a[i];
       int j = i - 1;
       for(j = i - 1;a[j] > a[i] && j > 0;--j)
       {
             a[j] = a[j - 1];
       }
             a[j +1] = t;
               
    }
    for(int i = 0;i < 10;++i)
    {
         printf("%d ",a[i]);
    }
    printf("\n");
 }

改变的对象错误

  int main(void)
  {
     int a[10] = {1,24,3,47,5,6,7,89,12,45};
     int i;
    for(i = 1 ; i < 10;++i)
    {
          
       int t = a[i];
       int j = i - 1;
       for(j = i - 1;a[j] > a[i] && j > 0;--j)//循环条件判断a[i] 和 a[j]
       {
             a[j] = a[j - 1];   //如果a[j] > a[i],将 a[j - 1]赋值给a[j]
       }
             a[j + 1] = t;
               
    }
    for(int i = 0;i < 10;++i)
    {
         printf("%d ",a[i]);
    }
    printf("\n");
 }

这里是一个明显的逻辑错误,对 a[i] 与 a[j] 进行比较,最后却将 a[j - 1] 的值赋值给 a[j]。

相当于比较a[i] 和a[i - 1],a[i - 1]赋值为a[ i - 2]。插入排序要求我们两个数值进行比较,将大值赋值给位号大的那一个。根据判断条件来看,我们对于a[ i -2]的情况是未知的(不清楚a[i -2] 和 a[ i -1]的大小关系),因此这种赋值是不恰当的。

修改为

  int main(void)
  {
     int a[10] = {1,24,3,47,5,6,7,89,12,45};
     int i;
    for(i = 1 ; i < 10;++i)
    {
          
       int t = a[i];
       int j = i - 1;
       for(j = i - 1;a[j] > a[i] && j > 0;--j)//循环条件判断a[i] 和 a[j]
       {
             a[j + 1] = a[j];   //如果a[j] > a[i],将 a[j]赋值给a[j + 1]
                                //  即赋值给a[i]
       }
             a[j + 1] = t;
               
    }
    for(int i = 0;i < 10;++i)
    {
         printf("%d ",a[i]);
    }
    printf("\n");
 }

比较的对象错误

  int main(void)
  {
     int a[10] = {1,24,3,47,5,6,7,89,12,45};
     int i;
    for(i = 1 ; i < 10;++i)
    {
          
       int t = a[i];
       int j = i - 1;
       for(j = i - 1;a[j] > a[i] && j > 0;--j)//循环条件判断a[i] 和 a[j]
       {
             a[j + 1] = a[j];   //如果a[j] > a[i],将 a[j]赋值给a[j + 1]
                                //  即赋值给a[i]
       }
             a[j + 1] = t;
               
    }
    for(int i = 0;i < 10;++i)
    {
         printf("%d ",a[i]);
    }
    printf("\n");
 }

再上一轮修改后,可以发现,a[i] 的值被改变。在第一轮循环后,循环条件变成了a[ j ]和被改变后的a[i]的比较。然而选择插入的思想是将希望被排序的元素temp与a[i]之前的元素作比较,为temp选择一个适合的位置将其插入。第一次循环后,a[i] 的值为 temp和a[j]二者比较中的较大值,因此我们无法保障始终进行的是temp和a[i]前面的元素比较。

  int main(void)
  {
     int a[10] = {1,24,3,47,5,6,7,89,12,45};
     int i;
    for(i = 1 ; i < 10;++i)
    {
          
       int t = a[i];
       int j = i - 1;
       for(j = i - 1;a[j] > temp && j > 0;--j)//循环条件判断 temp 和 a[j]
       {
             a[j + 1] = a[j];   //如果a[j] > a[i],将 a[j]赋值给a[j + 1]
                                //  即赋值给a[i]
       }
             a[j + 1] = t;
               
    }
    for(int i = 0;i < 10;++i)
    {
         printf("%d ",a[i]);
    }
    printf("\n");
 }

 阅读代码没有其他错误,进行编译检验。


解决方案:

修改后的代码:

  int main(void)
  {
     int a[10] = {1,24,3,47,5,6,7,89,12,45};
     int i;
    for(i = 1 ; i < 10;++i)
     {
            int t = a[i];
            int j = i - 1;
            for(j = i - 1;a[j] > t && j > 0;--j)
            {
                 a[j + 1] = a[j ];
            }
             a[j +1] = t;    
      }
     for(int i = 0;i < 10;++i)
     {
         printf("%d ",a[i]);
     }
     printf("\n");
 }

运行结果

1 3 5 6 7 12 24 45 47 89

结果正确。

你可能感兴趣的:(c语言,bug记录,c语言,学习)