码迷,mamicode.com
首页 > 编程语言 > 详细

排序算法合集(冒泡,选择,插入,堆排,快排)

时间:2017-08-20 18:34:40      阅读:200      评论:0      收藏:0      [点我收藏+]

标签:之间   效率比较   sort   性能   适用于   期望   插入   font   复杂   

1、冒泡排序

    最初在学c语言时,老师就教的这个排序算法,原理比较简单:从数组下标为0处开始遍历,相邻之间进行比较,若a[i]>a[i+1],则exchange(a[i],a[i+1]),当然也可以将小的往后传递,将此过程不断进行,那么最后数组就有序了。

要点:(1)每遍历一遍,末尾就得到一个最大值(或最小值),那么接下来的遍历是不是每次都减少一个元素就好了,因为后边的已经排好序了啊。

      (2)遍历n-1遍就排好序了,因为最后一遍只剩一个元素了,它一定放那儿,所以最后一遍就不用遍历了。

当然如果数据小,又懒得优化,多进行几遍也一样可以排序的,比如这样:

     for(int i=0;i<n;i++){                              //遍历了n遍

          for(int j=0;j<n-1;j++){                     //每次比较当前元素和下一个元素,所以循环结束条件为n-1

             {

                 if(a[j]>a[j+1])

                 {    int t=a[j];

                      a[j]=a[j+1];

                      a[j+1]=t;    }

              }

       }

 那么标准的冒泡排序,就是算法复杂度为n*(n-i)次也就是n^2如下:

 

       for(int i=0;i<a.length-1;i++){                              //遍历n-1遍就够了

          for(int j=0;j<a.length-i-1;j++){               //每次比较当前元素和下一个元素,每遍历一遍少比较一个元素,所以循环结束条件为n-i-1

             {

                 if(a[j]>a[j+1])

                 {    int t=a[j];

                      a[j]=a[j+1];

                      a[j+1]=t;    }

              }

       }

2、选择排序

    这个也是学c语言的时候和冒泡一起学的,它和冒泡算法复杂度一样,原理为:从数组下标为0处开始遍历,每次取出剩下元素的最大值(或最小值)放在当前位置,也就是说,第一次取最大的放第一个位置,第二次取次大的放第二个位置....执行n-1次就好了,最后一个只能放最后了。

标准选择排序代码如下:

           for(int i=0;i<a.length-1;i++){               //遍历n-1遍就够了

              int k=i;                                 //k为剩下元素中的最大值下标,初始化为当前位置

              for(int j=i+1;j<a.length-1;j++){        //找出剩下元素中的最大值下标

                 if(a[j]>a[k])

                    k=j;    

                 }

             if(k!=i){                               //若最大值不是当前位置的值,则交换,每次将最大值放前边

              int t=a[k];

                  a[k]=a[i];

                  a[i]=t;  

                }

          }

3、插入排序

   适用于较少元素时,效率比较高,原理:从数组下标为0处开始遍历,每次保证已经遍历的元素为有序序列,即每次将要遍历的数插入到前边数列的合适位置,保证已经遍历的元素为有序数列。如:遍历第一个元素,因为目前前边只有这一个元素,所以它是有序的,遍历第二个元素,和第一个元素比较,看它插在他前边还是后边,这样就保证已经遍历的元素都有序了,之后的类似,和前边的比较,然后插入合适的位置。

   插入排序代码如下:

      for(int i=1;i<a.length-1;i++){       //从下标1开始,一个元素的时候一定有序啊

      int j=i-1;                          // j初始值为前一个元素,因为要将前边的元素一一和当前元素比较

      int k=a[i];                         //记录当前位置元素的值,因为如果后边要移动的话会覆盖的

      while(j>0&&a[j]>k){                //将大于当前元素值的都依次向前移一位,好空出适合的位置给当前元素值

          a[j+1]=a[j];

          j--;

      }

     a[j+1]=k;                          //因为j处元素值小于等于k (j处跳出循环的),所以k的适合位置为j+1

   }

4、堆排序

   要想理解堆排序,首先你要知道最大堆,要想理解最大堆,你得知道二叉树。

  二叉树:每个节点最多有俩个孩子节点。

  最大堆:父亲节点的值总是大于孩子节点的值。

  当然在这里二叉树的存储结构不是链表,是使用数组存的:(1)数组下标为0处是根节点。

                                                      (2)父亲节点下标*2为左孩子下标,父亲节点下标*2+1为右孩子下标。

                                                        根据这俩条准则我们就可以将二叉树存在数组了。

堆排序原理:我们知道最大堆的性质(父亲节点的值总是大于孩子节点的值),那么根节点处不就是当前数列的最大值吗,那么我们每次取根节点的值放在末尾,然后将最大堆的大小-1,更新最大堆,取根节点放后边.....不断执行这个过程,直到最大堆中只剩一个元素,此时数组就是一个有序数组了。

根据原理可以看出我们需要编的操作有(1)建最大堆  (2)更新最大堆,其实建立最大堆就是不断更新最大堆的过程,如果我们将每个结点都执行一遍更新最大堆操作(即父亲节点的值总是大于孩子节点的值,不符合的话将父亲节点与最大的孩子交换位置),当然执行顺序必须是从下往上,然后只需从非叶子节点开始执行就好了(非叶子节点就是有孩子的结点)。

  堆排序代码如下:

       //更新最大堆操作

          void dfDui(int x) {                         //参数为父亲节点下标

            int lchild=x*2;                           //左孩子下标

            int rchild=x*2+1;                         //右孩子下标

            int max=x;                                //最大值下标初始为父亲下标

          if(lchild<size&&a[lchild]>a[max])           //比较找出最大值

               max=lchild;

          if(rchild<size&&a[rchild]>a[max])

              max=rchild;

          if(max!=x){           //若父亲节点为最大值,则符合性质,否则交换,将最大值移到父亲节点处,然后因为孩子节点处已改变,更新此节点。

            int t=a[max];

                a[max]=a[x];

                a[x]=t;

            dfDui(max);

           }

       }

   //建最大堆操作

          void creatDui(){

          for(int i=a.length/2+1;i>=0;i--){     //叶子结点数为结点总数一半且都在最后(可以从孩子节点下标的算法为父亲节点*2看出),因此                     duDui(i);                       // a.length/2+1处开始为非叶子节点     

          }

      }

   //堆排序操作

       void sort(){

        creatDui();                                //建最大堆

        for(int i=size-1;i>=1;i--){               //每次将第一个数与最后一个数交换,然后大小-1,更新已经改变的根节点

            int t=a[0];

                a[0]=a[size-1];

                a[size-1]=t;

                size--;

                dfDui(0);

         }

     }

5、快速排序

    快速排序是实际运用中用的最多的算法,虽然它在最坏的情况下会达到n^2,但它的平均性能非常好,期望时间复杂度为nlgn,而且隐含的常数因子非常小,并且是原址排序。

    快速排序原理:从一组数中任意选出一个数,将大于它的数放右边,小于它的数放左边,然后再从左边和右边的俩组数中分别执行此操作,知道组中元素数为1,此时,数组就是有序的了。

从原理中可以清楚的看出此操作为递归操作,其代码如下:

             int partsort(int a[],int l,int r){                 //将比a[r]小的元素放左边,比它大的放右边,最后把a[r]放中间

                int i=l;                                        //i为比a[r]大的元素的下标,初始为开始位置l

                for(int j=l;j<r;j++){                           

                 if(a[j]<=a[r]){                               //如果元素比a[r]小则和大的元素交换位置,目的让小的放一起,大的放一起

                   int t=a[j];                                 //可以自己手运行几遍这个循环

                       a[j]=a[i];

                       a[i]=t;

                       i++;

                  }

               }

              int t=a[i];                                   //a[i]为小元素和大元素的交界处,将a[r]与之交换

                  a[i]=a[r];

                  a[r]=t;

              return i;                                    //返回交界处下标,继续排前边的和后边的这俩组

      }

           void quicksort(int a[],int l,int r){

               if(l<r){                                   //递归结束条件为组中只剩一个元素

               int p=partsort(a,l,r);                    //分成俩组返回交界处

                   quicksort(a,l,p-1);                  //继续分左边

                   quicksort(a,p+1,r);

                }

           }

主函数中调用代码为,若数组大小为n,则:quicksort(a,0,n-1);

 

 

待续待续哈..........

排序算法合集(冒泡,选择,插入,堆排,快排)

标签:之间   效率比较   sort   性能   适用于   期望   插入   font   复杂   

原文地址:http://www.cnblogs.com/llsq/p/7400587.html

(0)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!