常见的排序问题(一)

  排序是编程中非常重要的一个需求与功能,经常需要用到排序,在现实中又有太多排序的例子,像电话簿联系人,很多体育比赛,包括各种选举都是通过排序来决定名次与结果的。所以排序问题也是c语言中的一个非常经典的问题,接下来,我将用这篇和下一篇博客来分析一下用c语言实现的排序的几种方法以及它们的特点及各自的改进。(接下来都是以从小到大排序为例介绍一下这几种排序方法),通常情况下用数组来处理排序问题。

  先说一下非常经典的一种方法,选择排序法吧,选择排序是c语言中常用的一种排序算法,它的基本思想是,:每步从待排序的记录中选出剩下的元素中最小的元素,把其与当前还没有完成排序的数列中的第一个数进行交换,这样每在第i轮排序完成后,就可以保证前i个元素是这一组元素中的最小的i个数,且从小到大排列。它的代码如下。

#include
void selectsort(int a[],unsigned int n)
{
  int i=0,j=0,temp=0,min=0;// 接下来嵌套的for循环将完成选择排序的主要工作
  for (i=0;i   {min=i;
    for (j=i+1;j    {
       if (a[min]>a[j])
        {
          temp=a[min];
          a[min]=a[j];
         a[j]=temp;
        }
     }
   }
}
//接下来试一下这个函数
int main()
{  int test[]={5,8,28,38,94,96,78,9,67};
   unsigned int n;  
   n=sizeof(test)/sizeof(int);
   int i=0;
    selectsort(test, n);
     printf ("After select sort:");
     i=0;
        while (i            printf ("%3d",test [i++]);
            return 0;

}

运行后的结果如图:

常见的排序问题(一)_第1张图片


  选择排序不管内容的初始状态如何,在第i趟排序中选出最小关键字的记录需要做n-i次比较,因此,它的总的比较次数一直是n(n-1)/2=O(n^2)。但是,移动的次数与初始的内容是有关的,当初始内容恰为正序时,移动次数为0。当初始内容为反序时,每次排序均要执行交换操作,总的移动次数我感觉为3×n(n-1)/2(但有一本参考书中说是3(n-1))。选择排序的平均时间复杂度为O(n^2).因为在排序的过程中如果有相同的两个数可能会交换次序,所以选择排序是一种稳定的排序方法。

  接下来说一下也是非常经典的一类算法:冒泡排序法。冒泡排序算法是针对排序记录中的关键字的每相邻两个元素的比较,发现两个元素次序相反时立即进行交换,直到没有反序的记录为止。冒泡排序法的代码如下。

 #include
void bublesort (int a[],unsigned int n)

    int i=0,j=0;
    int temp=0;//接下来的嵌套的for循环完成了冒泡排序的核心工作
    for (i=0;i      {
         for (j=1;j          {
            if (a[j]              {
                temp=a[j];
                a[j]=a[j-1];
                a[j-1]=temp;               
              }
           }
      }
}
//接下来调用后检验一下这个函数
int main ()
{
   int test[]= {14,67,35,98,75,92,65,71}                                                 
   unsigned int n;
   n=sizeof (test)/sizeof(int);
   int i=0;
   bublesort (test,n);
    printf ("After buble sort:\n");
    i=0;
     while (i           printf ("3d",test[i++]);
           return 0;


}

运行结果类似于选择排序,不再赘述。

  这种方法实现的冒泡排序,不管数据的初始排布是怎样的,都要进行n-1次起泡,而且,第i次起泡要做n-i次关键码(其实吧,在单纯的数据排序中,关键码就是数字。),而具体移动的次数和数据的初始次序是有关系的,当开始的数据就是按从小到大的次序排列时,不需要移动对象,而最坏的情形是每一次都需要移动对象,这样的话也要执行3n(n-1)/2次交换数据的操作(每移动两个数据都要引入一个中间变量,进而需要交换3)。冒泡排序法的时间复杂度和选择排序法一样,也为O(n^2).因为一般情况下在冒泡排序中遇到两个相等的数是不需要交换次序的。(所以这就要求在代码中交换数据的条件不带等号。)所以一般而言冒泡排序是一种稳定的排序方法。而通过加标志位从而改进后的冒泡排序可以有效的减少不必要的交换,提高程序的执行效率。改进后的代码如下。

#include
void bublesort (int a[],unsigned int n)
{ bool flag=false;// 通过加标志位减少在数据结构较好时的可能的执行次数   
    int i=0,j=0;
    int temp=0;//接下来的嵌套的for循环完成了冒泡排序的核心工作
    for (;i      {  flag=false; 
         for (j=1;j          {
            if (a[j]              {  flag=true;
                temp=a[j];
                a[j]=a[j-1];
                a[j-1]=temp;               
              }
           }
           if (flag==false)
           {
            break;
  }
      }
}
//接下来调用后检验一下这个函数
 int main ()
{
   int test[]= {14,67,35,98,75,92,65,} ;                                               
   unsigned int n;
   n = sizeof (test)/ sizeof(int);
   int i=0;
   bublesort (test,n);
    printf ("After buble sort:\n");
    i=0;
     while (i           printf ("%3d",test[i++]  );
           return 0;


}

 改进后的代码当数据的初始情况比较好的时候,通过引入标志位和break语句,可以减少进行不必要的比较,提前完成程序。

你可能感兴趣的:(常见的排序问题(一))