【C语言督学训练营 第十六天】考研中常考的排序大题(上)---- 冒泡排序、插入排序、快速排序

前言

今天要介绍的部分是排序算法,在很久很久之前学习过十大排序,当时自我感觉非常良好,知道今天才知道我认为的大错特错。有些排序算法会考代码题,有些只会考小题只需要理解思想即可,目前介绍的几种排序算法均是喜欢考代码题的。
在这里插入图片描述

经典的冒泡

冒泡排序的基本思想是:从后往前(或从前往后)两两比较相邻元素的值,(若A[j-1]>A[j]),则交换它们,直到序列比较完。我们称它为第一趟冒泡,结果是将最小的元素交换到待排序列的第一个位置。关键字最小的元素如气泡一般逐渐往上“漂浮”直至“水面”。下一趟冒泡时,前一趟确定的最小元素不再参与比较,每趟冒泡的结果是把序列中的最小元素放到了序列的最终位置…这样最多做n–1趟冒泡就能把所有元素排好序。
在这里插入图片描述

冒泡排序很经典,在刚步入大学的时候学习的排序方法就是冒泡排序,它的排序过程就像气泡一样,每一次冒出一个当前无序部分最大的值如果有n个元素的话,需要冒泡n-1次;具体实现过程如下:
在这里插入图片描述
正是重复这个过程,最终使得序列有序。冒泡排序的实战代码如下:

//冒泡
//针对循环条件有下列解释
//一个数据一个数据向后冒泡(外层循环是一共需要排序的元素个数剩一个的时候就不用循环了)
//内层循环是两两相邻元素进行比较(后面已经排好i个元素了),当循环到倒数第二个元素时,整个数组都扫描过了
//冒泡思想:
//每次对比相邻两个元素,大的向后移,每循环一轮将会冒出当前最大元素。
//如此循环n-1轮便可以将整个序列变的有序。
void BubbleSort(int *p){
    
    
    for(int i=0;i<maxSize-1;i++){
    
    
        for (int j=0;j<maxSize-i-1;j++){
    
    
            if(p[j]>p[j+1]){
    
    
                int temp=p[j];
                p[j]=p[j+1];
                p[j+1]=temp;
            }
        }
    }
}

跟冒泡容易混淆的是选择排序(并不是指思想上混淆,而是代码上混淆,要多多注意!)

插入排序

插入排序分为三种

  • 直接插入排序
  • 折半插入排序
  • 希尔排序

以上3种插入类型的排序,考研都是考选择题,考大题概率很低,因此我们仅讲解直接插人排序的原理与代码实战,折半插入排序与希尔排序原理可以在后面的408课程中进行学习。
在这里插入图片描述

如果看文字有点吃力的话,可以看一看动画加深理解:记住一个事,就是将当前选择的元素插入到前面有序序列中的合适位置。
在这里插入图片描述

//插入
//针对插入排序循环条件
//外层是因为有可能第一个元素就是最大的,需要插入n-1次才能完成有序
//内层循环是因为要向前寻找可插入的位置,插入之前要先移动元素腾出位置
//当腾出位置之后在腾出的位置插入当前元素p[j+1]=temp;这么写的原因是
//p[j]不需要移动,而p[j+1]=p[j+2],p[j+1]就是我们要插入的位置
//针对算法思想:
//插入排序每一次选出一个元素,然后向序列头部方向寻找插入位置,因为要插入元素
//所以数组的话需要先移动元素,当找到合适的位置时将选出的元素插入,插入之后
//形成一个新的有序序列,然后寻找下一个元素可插入的位置,当有n-1个元素插入成功
//之后序列整体就变的有序了。
void InsertSort(int *p){
    
    
    for(int i=1;i<maxSize;i++){
    
    
        int temp=p[i];
        int j=i-1;
        while (j>=0&&p[j]>temp){
    
    
            p[j+1]=p[j];
            j--;
        }
        p[j+1]=temp;
    }
}

快速排序

快速排序的核心是分治思想:假设我们的目标依然是按从小到大的顺序排列,我们找到数组中的一个分割值,把比分割值小的数都放在数组的左边,把比分割值大的数都放在数组的右边,这样分割值的位置就被确定。数组一分为二,我们只需排前一半数组和后一半数组,复杂度直接减半。采用这种思想,不断地进行递归,最终分割得只剩一个元素时,整个序列自然就是有序的。


通俗点来说就是:每一次选一个元素,以这个元素为标准将序列分为两段,大的站一边,小的站一边,此时选中的元素在有序序列中位置已确定,剩余要做的工作就是划分生成的两段,直到将序列划分的只有一个元素,那么整体就是有序的(因为每一个元素都占到了有序情况下的合适位置)。

扫描二维码关注公众号,回复: 15644392 查看本文章

如果文字有些枯燥可以看一看动画:
在这里插入图片描述
下面是实战代码:
initFastSort是找到当前序列首元素在有序情况下的合适位置,遍历一遍序列即可,将元素拆分到两边。

//快速排序
//函数说明
//initFastSort函数负责将该段元素根据首元素划分为两段,并将首元素放在合适的位置
//使得首元素左边比其小右边比其大。(遍历一遍找出序列中一个元素的有序位置)
//FastSort函数的作用是将序列分而治之,每划分一次排序的次数就减半,当划分到只有一个元素在一组时
//排序顺势完成。
//算法思想
//解决掉要想让整体有序,需要先让每一段有序,当每一段有序之后整体就有序了。
int initFastSort(int *p,int l,int r){
    
    
    int temp=p[l];
    while(l<r){
    
    
        while (l<r&&p[r]>=temp)
            --r;
        p[l]=p[r];
        while (l<r&&p[l]<=temp)
            ++l;
        p[r]=p[l];
    }
    p[l]=temp;
    return l;
}
void FastSort(int *p,int l,int r){
    
    
    if(l<r){
    
    
        int mid=initFastSort(p,l,r);
        FastSort(p,l,mid-1);
        FastSort(p,mid+1,r);
    }
}
void StartFastSort(int *p){
    
    
    FastSort(p,0,maxSize-1);
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/apple_51931783/article/details/129208489