1、冒泡排序

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

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

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

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

     

 1 for(int i=0;i<n;i++){                              //遍历了n遍
 2 
 3           for(int j=0;j<n-1;j++){                     //每次比较当前元素和下一个元素,所以循环结束条件为n-1
 4 
 5              {
 6 
 7                  if(a[j]>a[j+1])
 8 
 9                  {    int t=a[j];
10 
11                       a[j]=a[j+1];
12 
13                       a[j+1]=t;    }
14 
15               }
16 
17        }

 

 

 

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

 

 1        for(int i=0;i<a.length-1;i++){                              //遍历n-1遍就够了
 2 
 3           for(int j=0;j<a.length-i-1;j++){               //每次比较当前元素和下一个元素,每遍历一遍少比较一个元素,所以循环结束条件为n-i-1
 4 
 5              {
 6 
 7                  if(a[j]>a[j+1])
 8 
 9                  {    int t=a[j];
10 
11                       a[j]=a[j+1];
12 
13                       a[j+1]=t;    }
14 
15               }
16 
17        }

 

 

 

2、选择排序

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

标准选择排序代码如下:

          

 1  for(int i=0;i<a.length-1;i++){               //遍历n-1遍就够了
 2 
 3               int k=i;                                 //k为剩下元素中的最大值下标,初始化为当前位置
 4 
 5               for(int j=i+1;j<a.length-1;j++){        //找出剩下元素中的最大值下标
 6 
 7                  if(a[j]>a[k])
 8 
 9                     k=j;    
10 
11                  }
12 
13              if(k!=i){                               //若最大值不是当前位置的值,则交换,每次将最大值放前边
14 
15               int t=a[k];
16 
17                   a[k]=a[i];
18 
19                   a[i]=t;  
20 
21                 }
22 
23           }

 

 

 

3、插入排序

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

   插入排序代码如下:

     

 1  for(int i=1;i<a.length-1;i++){       //从下标1开始,一个元素的时候一定有序啊
 2 
 3       int j=i-1;                          // j初始值为前一个元素,因为要将前边的元素一一和当前元素比较
 4 
 5       int k=a[i];                         //记录当前位置元素的值,因为如果后边要移动的话会覆盖的
 6 
 7       while(j>0&&a[j]>k){                //将大于当前元素值的都依次向前移一位,好空出适合的位置给当前元素值
 8 
 9           a[j+1]=a[j];
10 
11           j--;
12 
13       }
14 
15      a[j+1]=k;                          //因为j处元素值小于等于k (j处跳出循环的),所以k的适合位置为j+1
16 
17    }

 

 

 

4、堆排序

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

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

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

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

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

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

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

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

  堆排序代码如下:

       

 1 //更新最大堆操作
 2 
 3           void dfDui(int x) {                         //参数为父亲节点下标
 4 
 5             int lchild=x*2;                           //左孩子下标
 6 
 7             int rchild=x*2+1;                         //右孩子下标
 8 
 9             int max=x;                                //最大值下标初始为父亲下标
10 
11           if(lchild<size&&a[lchild]>a[max])           //比较找出最大值
12 
13                max=lchild;
14 
15           if(rchild<size&&a[rchild]>a[max])
16 
17               max=rchild;
18 
19           if(max!=x){           //若父亲节点为最大值,则符合性质,否则交换,将最大值移到父亲节点处,然后因为孩子节点处已改变,更新此节点。
20 
21             int t=a[max];
22 
23                 a[max]=a[x];
24 
25                 a[x]=t;
26 
27             dfDui(max);
28 
29            }
30 
31        }
32 
33    //建最大堆操作
34 
35           void creatDui(){
36 
37           for(int i=a.length/2+1;i>=0;i--){     //叶子结点数为结点总数一半且都在最后(可以从孩子节点下标的算法为父亲节点*2看出),因此                     duDui(i);                       // a.length/2+1处开始为非叶子节点     
38 
39           }
40 
41       }
42 
43    //堆排序操作
44 
45        void sort(){
46 
47         creatDui();                                //建最大堆
48 
49         for(int i=size-1;i>=1;i--){               //每次将第一个数与最后一个数交换,然后大小-1,更新已经改变的根节点
50 
51             int t=a[0];
52 
53                 a[0]=a[size-1];
54 
55                 a[size-1]=t;
56 
57                 size--;
58 
59                 dfDui(0);
60 
61          }
62 
63      }

 

 

 

5、快速排序

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

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

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

           

 1   int partsort(int a[],int l,int r){                 //将比a[r]小的元素放左边,比它大的放右边,最后把a[r]放中间
 2 
 3                 int i=l;                                        //i为比a[r]大的元素的下标,初始为开始位置l
 4 
 5                 for(int j=l;j<r;j++){                           
 6 
 7                  if(a[j]<=a[r]){                               //如果元素比a[r]小则和大的元素交换位置,目的让小的放一起,大的放一起
 8 
 9                    int t=a[j];                                 //可以自己手运行几遍这个循环
10 
11                        a[j]=a[i];
12 
13                        a[i]=t;
14 
15                        i++;
16 
17                   }
18 
19                }
20 
21               int t=a[i];                                   //a[i]为小元素和大元素的交界处,将a[r]与之交换
22 
23                   a[i]=a[r];
24 
25                   a[r]=t;
26 
27               return i;                                    //返回交界处下标,继续排前边的和后边的这俩组
28 
29       }
30 
31            void quicksort(int a[],int l,int r){
32 
33                if(l<r){                                   //递归结束条件为组中只剩一个元素
34 
35                int p=partsort(a,l,r);                    //分成俩组返回交界处
36 
37                    quicksort(a,l,p-1);                  //继续分左边
38 
39                    quicksort(a,p+1,r);
40 
41                 }
42 
43            }

 

 

 

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

 

 

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

 posted on 2017-08-20 17:08  几缕清风依旧  阅读(7838)  评论(0编辑  收藏  举报