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

排序算法(学习整理)

时间:2019-01-21 00:00:32      阅读:281      评论:0      收藏:0      [点我收藏+]

标签:sed   由来   利用   没有   证明   ast   数组遍历   设置   ext   

  排序的算法有很多,冒泡、选择、直接插入、鸡尾酒、快排、堆排......,下文主将尽可能的介绍本人学过的所有排序(会不断更新,本人还在学习),以从小到大为最终排序结果,C 为主要实现语言。

一、冒泡排序(Bubble Sort):

  冒泡排序是一种简单的利用交换来完成排序的算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

  冒泡算法的步骤

  • 比较相邻的元素。如果前一个元素数比后一个元素大,就交换它们两个。
  • 对每一对相邻元素做同样的工作,从开始0和1到结尾的n-1和n。所以,最后的元素应该会是最大的数。
  • 针对所有的元素重复以上的步骤,除了最后一个。
  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

  下面是代码

技术分享图片
 1 void bubble_sort(int arr[], int len)
 2 {
 3     int i, j;  
 4     for (i = 0; i < len - 1; i++)                  //需要进行比较的轮数
 5     {    
 6         for (j = 0; j < len - 1 - i; j++)          //每轮需要进行比较的次数,
 7        //因为每一轮都有一个最大的数被放到了最后一个,所以第i轮就有i个数不需要排序(这里就存在优化的可能)
 8         if (arr[j] > arr[j + 1])                      //相邻的两个元素两两进行比较
 9         {
10             arr[j] = arr[j] ^ arr[j+1];                 
11             arr[j+1] = arr[j] ^ arr[j+1];
12             arr[j] = arr[j] ^ arr[j+1];            // 交换
13         }
14     }
15 }
Bubble sort

 

冒泡排序的问题很明显,举个例子

当数组元素为 1 2 3 9 4 5 6 7 8 时:

  第一轮:1 2 3 4 5 6 7 8 9;

  第二轮:1 2 3 4 5 6 7 8 9;

  第三轮:1 2 3 4 5 6 7 8 9;

至此我们可以看出在第一轮的时候数组就已经排好序了,然而冒泡排序仍然在兢兢业业的工作(真是好员工,可惜效率低了点)。

所以我们可尝试着优化一下,在进行交换的时候标记一下,当发数组遍历完都没有交换的情况,也就证明已经排好序了,我们的冒泡排序就可以提前下班了。

  优化后的代码如下

技术分享图片
 1 void bubble_sort(int arr[], int len)
 2 {
 3     int i, j; 
 4     for (i = 0; i < len - 1; i++)                  //需要进行比较的轮数
 5     {    
 6         int isSorted = 1;                          //用isSorted进行标记,默认其为已经完成排序,也可以设置为bool型
 7         for (j = 0; j < len - 1 - i; j++)          //每轮需要进行比较的次数
 8         {
 9             //因为每一轮都有一个最大的数被放到了最后一个,所以第i轮就有i个数不需要排序
10             if (arr[j] > arr[j + 1])                   //相邻的两个元素两两进行比较
11             {
12                 isSorted = 0;                     //进入交换后立刻置0, 表示排序未完成
13                 arr[j] = arr[j] ^ arr[j+1];                 
14                 arr[j+1] = arr[j] ^ arr[j+1];
15                 arr[j] = arr[j] ^ arr[j+1];            //交换
16             }
17         }
18         if (isSorted)                   //如果一直未交换就代表已经完成了排序,也就是说可以提前下班了
19         {
20             break;
21         }
22     }
23 }
View Code

 

当我们继续测试后会发现冒泡排序的另一个问题

打个比方:

  当数组为 33 54 32 21 56 67 78 89 时:

  第二个for里

     第一轮比较次数:7

     第二轮比较次数:7

     第三轮比较次数:7

     第四轮比较次数:7

  程序结束

  第一轮的7次是怎么来的呢?

    33和54比较,33 < 54,所以不变。    

    54和32比较,54 > 32,所以54和32换。 

       33 32 54 21 56 67 78 89

    54和21比较,54 > 21,所以54和21换。 

       33 32 21 54 56 67 78 89

    54和56比较,54 < 56, 不变。

    56和67比较,56  < 67,不变。

    67和78比较, 67 < 78,不变。

    78和89比较, 78  < 89, 不变。

  第一轮至此结束。

  第二轮的6次

    33和32比较, 33 > 32, 所以33和32交换。

       32 33 21 54 56 67 78 89

    33和21比较, 33 > 21,所以33和21交换。

       32 21 33 54 56 67 78 89

    33和54比较,33 < 54,所以不变。

    54和56比较,54 < 56, 不变。

    56和67比较,56  < 67,不变。

    67和78比较, 67 < 78,不变。

  第二轮至此结束。

到这里基本就能看出问题了,这个测试组,从56往后都是有序的,但是冒泡这位员工仍然一丝不苟的执行的他的任务。

从56往后的比较都是没有意义的,所以我们应该考虑如何让程序识别已排好序的子列。大家可以思考一下然后再往后看。

 

解决方法:我们只需将要再最后一次元素进行交换的位置进行记录,让第二for循环再这个范围内进行比较。

    

  最终优化代码如下(对我来说):

技术分享图片
 1 void bubble_sort(int arr[], int len)
 2 {
 3     int i, j;
 4     int lastIndex, sortBorder;                      //用来记录最后一次交换的下标和交换边界
 5     sortBorder = len -1;                            //因为第一轮的时候i = 0,所以第一轮的sortBorder == len - i - 1
 6     for (i = 0; i < len - 1; i++)                  //需要进行比较的轮数
 7     {    
 8         int isSorted = 1;                          //用isSorted进行标记,默认其为已经完成排序,也可以设置为bool型
 9         for (j = 0; j < sortBorder; j++)          //每轮需要进行比较的次数
10         {
11             //这里不在由i确定循环边界了,这也是这次优化的核心
12             if (arr[j] > arr[j + 1])                   //相邻的两个元素两两进行比较
13             {
14                 isSorted = 0;                     //进入交换后立刻置0, 表示排序未完成
15                 lastIndex = j;                         //记录下最后一次交换的位置
16                 arr[j] = arr[j] ^ arr[j+1];                 
17                 arr[j+1] = arr[j] ^ arr[j+1];
18                 arr[j] = arr[j] ^ arr[j+1];            //交换
19             }
20         }
21         sortBorder = lastIndex;               //讲最后一次交换的位置作为下次比较的边界
22         if (isSorted)                   //如果一直未交换就代表已经完成了排序,也就是说可以提前下班了
23         {
24             break;
25         }
26     }
27 }
View Code

当然这也不最优的冒泡优化,但是继续优化就涉及到另一个算法了,所以目前对冒泡这个员工的整改就到这里


  

排序算法(学习整理)

标签:sed   由来   利用   没有   证明   ast   数组遍历   设置   ext   

原文地址:https://www.cnblogs.com/daker-code/p/10296730.html

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