几种简单的排序算法总结

 

注:

  (1)以下所有排序算法均按照从小到大的顺序排列

  (2)以下算法中用到的交换函数都一样,如下:

    void Swap(int *a,int i,int j)
    {
        int temp;
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }

    因此不在每个排序算法中进行详解

1.冒泡排序

  1.最简单的冒泡排序

  思想:

    该排序算法在排序的过程中总共进行n-1趟排序,每一趟排序都将当前的关键字和其后面的每一个关键字进行比较,若当前关键字大于其后面的关键字则进行交换。

  代码实现如下:

    void BubbleSort(int *a)        //a表示待排序的记录集合,这里以数组存储为例,以下排序算法相同,即都是对数组里的记录元素进行排序
    {
        int i,j;
        for(i = 0;i < MAXSIZE-1;i++)
        {
            for(j = (i + 1);j < MAXSIZE;j++)    //注意j从前往后循环与当前记录比较
            {
                if(a[i] > a[j])            //若当前记录大于其后的记录
                {
                    Swap(a,i,j);           //两者交换在数组中的位置
                }
            }
        }
    }

  分析:

    该算法从严格意义上讲并不是标准的冒泡排序,因为不满则“两两比较相邻记录”的冒泡排序思想,它更应该是最最简单的交换排序。

    该算法代码简单易懂,却是有缺陷的。每一趟的比较和交换对下一轮没有任何影响,将导致进行很多重复的比较,算法效率是非常低的  

  2.冒泡排序

    思想

      跟上面的排序算法的思想一样,都是当前趟的记录跟其之后的记录相比,只是该算法不同的是:每一趟都是两个相邻记录比较

    代码实现如下(蓝色加粗的即为和上面算法不同的部分):

      void BubbleSort(int *a)
      {
          int i,j;

        for(i = 0;i < MAXSIZE-1;i++)
           {
              for(j = MAXSIZE-2;j >= i;j--)    //注意j是从后往前遍历和其前面相邻的记录进行比较
              {
                  if(a[j] > a[j+1])          //若前者大于后者(注意两者相邻)
                  {
                      Swap(a,j,j+1);
                  }
              }
          }
      }

  3.冒泡排序算法的优化

    思想:该算法在上诉冒泡排序算法的基础上进行优化,由上面可知,若进过第一趟排序后若结果已经有序,则后面还要进行循环判断工作,因此该算法实现的是当在某一趟排序后若该序列已经有序,则不再进行循环比较了。

    代码实现如下:

      void BubbleSort(int *a)
      {
          int i,j;
          int flag = 1;               //新增flag标志,默认为1
          for(i = 0;i < MAXSIZE-1 && flag;i++)  //若i<n-1趟,且上一趟没有进行任何记录交换时说明该记录集合已经有序了,退出循环
          {
              flag = 0;
              for(j = MAXSIZE-2;j >= i;j--)
              {
                  if(a[j] > a[j+1])          //若前者都小于后者(即不需要交换时),说明该记录集合已经有序,则在当前循环结束后退出总循环
                  {
                      flag = 1;            //若只要有一次记录交换,则说明该集合还没有完全有序,继续循环
                      Swap(a,j,j+1);
                  }
              }
          }
      }

  4.冒泡复杂度分析

    时间复杂度:

      最好的情况:也就是带排序的记录集合本身是有序的,那么需要进行n-1(n为待排序的记录个数,代码中为MAXSIZE)次比较,没有数据交换,时间复杂度为O(n)

      最坏的情况:也就是待排序的记录集合本市是逆序的,那么时间复杂度为O(n*n)。

      因此平均复杂度为O(n * n)。

    空间复杂度:

      由于该算法没有借助辅助空间,所以空间复杂度为常数,即为O(1)。

    稳定性:

      稳定

2.简单选择排序

  思想:对待排序的n个记录进行n-1趟循环,每一趟进行两两相邻比较找到该趟最小的记录和当前记录进行比较,若最小记录的位置不是当前记录所在的位置,则两者进行交换。

  代码实现如下:

    void SelectSort(int *a)
    {
        int i,j,min;
        for(i = 0;i < MAXSIZE - 1;i++)
        {
            min = i;              //初始化当前记录为最小的记录
            for(j = i + 1;j < MAXSIZE;j++)  //将最小记录依次与其后面的记录比较
            {
                if(a[min] > a[j])        //若其后的记录小于该机记录
                {
                    min = j;          //把其后的记录的下标赋给min
                }    
            }
            if(i != min)            //若min不等于当前记录的下标
            {
                Swap(a,min,i);        //进行交换
            }
        }
    }

  简单选择排序复杂度分析:

    时间复杂度:

      最好情况:即待排序记录集合本身是有序的,需要比较的次数是1+2+...+(n-1) = n * (n - 1) / 2,不需要交换数据。由于最终的时间复杂度是比较与交换次数之和,因此总的时间复杂度为O(n * n)。

      最坏情况:即待排序的记录集合本身是逆序的,需要比较的次数同最好情况相同都为n * (n - 1) / 2,交换的次数是n-1次,因此最终的时间复杂度也是O(n * n)。

      因此平均复杂度为O(n * n)。

    空间复杂度:

      由于该算法不需要辅助空间,因此空间复杂度为常数,即为O(1)。

    稳定性:

      不稳定

3.直接插入排序

  思想:该算法的存储结构数组a[0]不存放记录(不同于上面算法),用作哨兵,每一趟都假设其前面的记录集合是有序的,然后比较当前记录和其前面相邻的记录,若小于其前面相邻记录,则把该值放在a[0]的位置上,然后从其前面相邻记录向前开始遍历,只要记录小于a[0]的记录,则把当前记录后移,直到大于等于a[0]元素则退出循环,然后把a[0]的记录插入到适当位置,则结束当前趟的操作。

  代码实现如下:

    void InsertSort(int *a)
    {
        int i,j;
        for(i = 2;i < MAXSIZE;i++)    //i从2开始循环,默认第一个记录是有序的
        {
            if(a[i] < a[i - 1])        //若当前记录大于前面的记录
            {  
                a[0] = a[i];          //设置哨兵,把当前记录赋给哨兵
                for(j = i - 1;a[0] < a[j];j--)
                {
                    a[j+1] = a[j];      //记录后移
                }
                  a[j + 1] = a[0];    //插入到正确位置
            }
        }
    }

  直接插入排序算法复杂度分析:

    时间复杂度:

      最好情况:即带排序的集合本身就是有序的,则需要比较n-1次,不需要移动,因此时间复杂度为O(n)。

      最坏情况:即待排序的集合本身是逆序的,则需要比较2+3+...+n = (n + 2) * (n - 1) / 2次,需要移动3+4+...+(n+1) = (n + 4)*(n - 1) /2次,因此时间复杂度为O(n * n)。

      因此平均复杂度为O(n * n)。

    空间复杂度:

      由于该算法需要一个辅助空间(a[0]),因此空间复杂度为常数,即为O(1)。

    稳定性:

      稳定

 

      

  

posted @ 2015-08-22 21:28  梦想的天空分外蓝  阅读(409)  评论(0编辑  收藏  举报