排序算法详解01-冒泡排序

排序算法的重要性

 排序算法对于大家来说应该都不陌生。计算机相关专业的同学入门的第一门课程C语言课程中,老师通常都会讲解冒泡排序。软件开发当中用到排序算法的场景挺多,比如一个年级学生的成绩按照总分大小进行排名次,再比如我们网购的时候通常会按照销量,按照价格进行排序等。学好排序算法不管是考试、笔试|面试、工作都可以用的上。面试找工作的时候,排序算法也是高频出现的考题之一,比如现场手撕冒泡排序,快速排序的原理等。 因此排序算法也是比较重要的需要好好掌握的一类算法

算法的学习最重要的是理解实现原理

冒泡排序算法通常是新手接触排序算法时,最先接触到的算法。所以雷老师在这里也以冒泡排序算法为例,讲透冒泡排序,以及排序算法当中比较重要的一些概念。如果你在学习冒泡排序的时候,学习的时候感觉是懂了,一到自己写的时候写不出来,这就是一知半解,没有彻底的搞懂。我们在学习算法的时候不需要去死记硬背代码,重要的是要理解原理,思路清楚了,代码自然就有了如果是死记硬背的代码,时间长了不用,很容易忘记。只有理解了实现原理,才能活学活用,变成自己的技能。假如我们没有理解算法 或者理解的不透彻可能看书之后或者听老师讲解之后觉得懂了,到自己写的时候却写不出来,或者写出来了,过段时间不用又忘了。 我们以C语言为例来讲解冒泡排序。

冒泡排序算法原理

 void bubble_sort (int arr[], int len) {}

冒泡排序只会操作相邻的两个数,对相邻的两个数进行比较,看时候满足大小关系要求。如果不满足就让这两个数互换位置。一次冒泡之后至少会让一个数移动到它应该在的位置。n个数,我们只需要冒泡n-1次即可完成排序。

举个栗子,我们对一下数列9  1 5 8 3 7进行从小到大冒泡排序

第一次冒泡

首先比较9和1,9 比1大,交换位置

1 9 5 8 3 7

继续比较9和5,9比5大,交换位置

1 5 9 8 3 7

继续比较9和8,9比8大,交换位置

1 5 8 9 3 7

继续比较9和3,9比3大,交换位置

1 5 8 3 9 7

继续比较9和7,9比7大,交换位置

1 5 8 3 7 9

在经过一轮冒泡之后数字9已经到了正确的位置,接下来,在除了9之外的剩余5个数中继续冒泡

第二次冒泡

首先比较1和5,1比5小,不做处理,继续比较5和8,5比8小,不做处理,继续比较8和3,8比3小,交换位置

1 5 3 8 7 9

继续比较8和7,8比7大,交换位置

1 5 3 7 8 9

经过第二次冒泡之后,数字8到了正确的位置,接下来,在除了数字8,9之外的剩余4个数中继续冒泡

第三次冒泡

首先比较1和5,1比5小不做处理,继续比较5和3,5比3大,交换位置

1 3 5 7 8 9

比较5和7,5比7小,不做处理

1 3 5 7 8 9

经过第三次冒泡数字7到了正确的位置,接下来在除了数字7,8,9之外的剩余3个数中继续冒泡

第四次冒泡

比较1和3,1比3小不做处理,比较3和5,3比5小不做处理

第四次冒泡之后数字5到了正确的位置,接下来在剩余的两个数中继续冒泡

1 3 5 7 8 9

第五次冒泡

1和3比较,1比3小,不做处理

1 3 5 7 8 9

此时数列已经是从小到大一次排列了。

将以上步骤用代码表示如下:

#include <stdio.h>
 void bubble_sort (int arr[], int len) {
     int i, j, temp;
       for (= 0; i < len - 1; i++) {
           for(= 0; j < len - i -1; j++) {
                // 相邻两个数比较
                if( arr[j] > arr[j+1] ) {
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
       }
}

int main(){
	int arr[] = { 9, 1,	5,	8,	3,	7};
	int len = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, len);
    int i;
    for (= 0; i < len; i++)
            printf("%d ", arr[i]);
    printf("\n arr size is %d, arr item size is %d", sizeof(arr), sizeof(arr[0]));       
	// return 1;
}

 初次接触冒泡排序的同学,难点可能是在里层冒泡次数j < len - 1 - i这里了,这行代码简单说就是,每次冒泡比较n个数,我们需要比较len -1次,由于我们冒泡一次就会有一个数在应该在的位置,冒泡i次,就有i个数在应该在的位置。这些已经在正确位置的数就不需要参与比较了,所以是 j < len -1 - i。以上就是冒泡排序算法的完整代码。

冒泡排序的优化

当某次冒泡已经没有数据交换时,说明数据已经是排好序的了,不用再继续冒泡了。优化版的冒泡排序代码如下:

void bubble_sort2 (int arr[], int len) {
     int i, j, temp;
       for (= 0; i < len - 1; i++) {
           int flag = 0;
           for(= 0; j < len - i -1; j++) {
                // 相邻两个数比较
                if( arr[j] > arr[j+1] ) {
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    flag = 1;
                }
            }
            if (!flag) {
                break;
            }
       }
}

排序的稳定性

排序的稳定性是说,如果待排序的序列中存在值相等的元素,经过排序之后,相等的元素之间原有的先后顺序不变。废话不多说,我们来举个栗子,假如待排序的序列22, 34, 3, 32, 82, 55 82 中有两个82,在排序之后,这两个82的先后顺序保持不变,那么这个排序算法就是稳定的排序算法,如果这两个82位置发生了变化,那么这个排序算法就是不稳定的排序算法。我们在选在排序算法的时候一定要注意排序算法的稳定性。

在我们的示例中,待排序的是一组数字,这组数字,值相等的数字谁在前,谁在后好像没什么影响。但是我们在实际的软件开发当中处理的数据可不是数字,而是实际业务中的数据。比如我们对一个年级的学生按照成绩大小进行排序。如果存在成绩相等的学生,则按照班级进行排序。那么我们可以先按照班级进行一次排序,这次排序之后,学生列表是按照班级一班,二班,三班这样的顺序进行排序。之后我们在按照成绩进行一次稳定的排序,即可做到,按照成绩排序,成绩相等的则班级号小的再前。假如我们按照成绩排序的算法是不稳定的,则有可能出现一班和二班有两个同学成绩相等,排序后,成绩相等的这两个同学,二班的同学排再一班的前边。

姓名

班级

成绩

同学

一班

97

同学

二班

86

同学

二班

97

同学

一班

86

外部排序和内部排序

内排序是在排序的过程中,待排序的所有记录全部放在内存中。比如我们上边的冒泡排序,排序数组中的数列。数组中的元素全部是在内存中的,这就是内部排序。外部排序是指排序的数据量大,不能同时放到内存中进行排序,整个排序过程需要内存和硬盘之间多次交换数据才能进行。比如我们内存4G,要排序的数据有8G,那我们就不能将这8G的数据一次性读入内存进行排序。对于这种情况,通常是将文件进行分割,排序分割后的数据,然后进行归并。比如我们将8G的数据文件分割成4份,每份就是2GB,然后我们将这2GB的数据一次读入内存,进行排序。重复4次,我们就有了4个内部有序的文件。然后对这4个文件再进行一次归并排序。归并排序雷老师后边会讲。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值