• 十大经典排序算法(冒泡排序、选择排序、插入排序、快速排序、归并排序)


    十大经典排序算法二(希尔排序、堆排序、计数排序、桶排序和基数排序)

    冒泡排序

    起泡排序,别名“冒泡排序”,该算法的核心思想是将无序表中的所有记录,通过两两比较关键字,得出升序序列或者降序序列。

    例如,对无序表{49,38,65,97,76,13,27,49}进行升序排序的具体实现过程如图 1 所示:
    在这里插入图片描述
    通过一趟趟的比较,一个个的“最大值”被找到并移动到相应位置,直到检测到表中数据已经有序,或者比较次数等同于表中含有记录的个数,排序结束,这就是起泡排序。

    冒泡排序代码实现

    
    #include 
    #include 
    
    // 采用两层循环实现的方法。
    // 参数arr是待排序数组的首地址,len是数组元素的个数。
    void swap1(int* a,int* b){
        int c = *a;
        *a = *b;
        *b = c;
    }
    void bubblesort1(int *arr,unsigned int len)
    {
        if(len < 2) return; 
        for(int i = len-1;i>0;i--){
            for (int j = 0; j < i; ++j) {
                if(arr[j]>arr[j+1]){
                    swap1(&(arr[j]),&(arr[j+1]));
                }
            }
        }
    }// 采用递归实现的方法。
    // 参数arr是待排序数组的首地址,len是数组元素的个数。
    void bubblesort2(int *arr,unsigned int len)
    {
        if(len < 2) return ;
        for(int i = 0;i<len - 1;i++){
            if(arr[i]>arr[i+1]){
                swap1(&(arr[i]),&(arr[i+1]));
            }
        }
        bubblesort2(arr,--len);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    观察上面的冒泡排序算法可知,通过么len - 1趟排序完成,每一趟排序将排好一个数,当排到一定程度时,序列已经有序的情况下,还会完成对有序序列的排序。

    冒泡排序算法的优化

    
    #include 
    #include 
    
    // 采用两层循环实现的方法。
    // 参数arr是待排序数组的首地址,len是数组元素的个数。
    void swap1(int* a,int* b){
        int c = *a;
        *a = *b;
        *b = c;
    }
    void bubblesort1(int *arr,unsigned int len)
    {
        int swap ;
        if(len < 2) return ;
        for(int i = len - 1;i>0;i--){
            swap = 0;
            for(int j = 0;j < i;j++) {
                if (arr[j] > arr[j + 1]){
                    swap1(&(arr[j]), &(arr[j + 1]));
                    swap = 1;
                }
            }
            printf("i = %d\n",i);
            if(swap == 0) return ;
        }
    }
    
    // 采用递归实现的方法。
    // 参数arr是待排序数组的首地址,len是数组元素的个数。
    void bubblesort2(int *arr,unsigned int len)
    {
        if(len < 2) return ;
        int tmp = 0;
        for(int i = 0;i<len - 1;i++){
            if(arr[i]>arr[i+1]){
                swap1(&(arr[i]),&(arr[i+1]));
                tmp = 1;
            }
        }
        if(tmp == 0) return ;
        printf("len = %d\n",len);
        bubblesort2(arr,--len);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    选择排序

    该算法的实现思想为:对于具有 n 个记录的无序表遍历 n-1 次,第 i 次从无序表中第 i 个记录开始,找出后序关键字中最小的记录,然后放置在第 i 的位置上。

    例如对无序表{56,12,80,91,20}采用简单选择排序算法进行排序,具体过程为:
    在这里插入图片描述

    选择排序代码实现

    #include 
    #include 
    
    void swap(int *x,int *y)
    {
        int itmp=*x;
        *x=*y;
        *y=itmp;
    }
    // 采用两层循环实现的方法。
    // 参数arr是待排序数组的首地址,len是数组元素的个数。
    void selectsort1(int *arr,unsigned int len)
    {
        int npos;
        if(len < 2) return ;
        for(int i = 0;i < len - 1;i++){
            npos = i;
            for (int j = i+1; j < len; ++j) {
                if(arr[npos]>arr[j]) npos = j;
            }
            if(i!=npos) swap(&(arr[i]),&(arr[npos]));
        }
    }
    
    // 采用递归实现的方法。
    // 参数arr是待排序数组的首地址,len是数组元素的个数。
    void selectsort2(int *arr,unsigned int len)
    {
        if(len < 2) return ;
        int npos = 0;
        for(int i = 0;i<len;i++){
            if(arr[npos]>arr[i]) npos = i;
        }
        if(npos != 0) swap(&(arr[0]),&(arr[npos]));
        selectsort2(arr+1,--len);
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    由以上的选择排序算法可知,每一趟选择都会选出最小的和第一个交换(第一个就最小除外),需要进行n次选择,可以优化为每一趟选择出两个(一个最大和一个最小的)分别个第一个与最后一个交换。只需要进行n/2次选择。

    选择排序的优化

    // 优化后的选择排序,作者:C语言技术网(www.freecplus.net)码农有道。
    #include 
    #include 
    
    // 交换两个变量的值。
    void swap(int *x,int *y)
    {
        int itmp=*x;
        *x=*y;
        *y=itmp;
    }
    
    // 采用两层循环实现的方法。
    // 参数arr是待排序数组的首地址,len是数组元素的个数。
    void selectsort1(int *arr,unsigned int len)
    {
        if(len < 2) return ;
        int minPos;
        int maxPos;
        int lift = 0,right = len -1;
        while (lift < right){
            minPos = maxPos = lift;
            for(int i = lift ;i<right;i++){
                if(arr[minPos] > arr[i]) minPos = i;
                if(arr[maxPos] < arr[i]) maxPos = i;
            }
            if(lift != minPos) swap(&(arr[lift]),&(arr[minPos]));
            if(lift == right) maxPos = minPos;
            if(maxPos != right)  swap(&(arr[right]),&(arr[maxPos]));
            lift ++;
            right --;
        }
    }
    // 采用递归实现的方法。
    // 参数arr是待排序数组的首地址,len是数组元素的个数。
    void selectsort2(int *arr,unsigned int len)
    {
      if(len < 2) return;
      int minPos = 0;
      int maxPos = 0;
      int lift = 0,right = len - 1;
      for(int i = lift;i<right;i++) {
          if (arr[minPos] > arr[i]) minPos = i;
          if (arr[maxPos] < arr[i]) maxPos = i;
      }
          if (lift != minPos) swap(&(arr[lift]), &(arr[minPos]));
          if (lift == right) maxPos = minPos;
          if (maxPos != right) swap(&(arr[right]), &(arr[maxPos]));
          len-=2;
          selectsort2(++arr,len);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    插入排序

    插入排序算法是所有排序方法中最简单的一种算法,其主要的实现思想是将数据按照一定的顺序一个一个的插入到有序的表中,最终得到的序列就是已经排序好的数据。

    直接插入排序是插入排序算法中的一种,采用的方法是:在添加新的记录时,使用顺序查找的方式找到其要插入的位置,然后将新记录插入。
    很多初学者所说的插入排序,实际上指的就是直接插入排序算法,插入排序算法还包括折半插入排序2-路插入排序表插入排序希尔排序等,后序文章都会一一讲到。

    想象我们打扑克摸排的时候每摸到一张牌时我们都会按照该牌面的大小插入到合适的位置。

    例如采用直接插入排序算法将无序表{3,1,7,5,2,4,9,6}进行升序排序的过程为:
    在这里插入图片描述

    // 参数arr是待排序数组的首地址,len是数组元素的个数。
    void insertsort(int *arr,unsigned int len)
    {
        int tmp;
        for (int i = 1; i < len; ++i) {
            tmp = arr[i];
            int j;
            for ( j = i - 1 ; (j>=0&&arr[j]>tmp); j--) {
                arr[j+1] = arr[j];
            }
            arr[j+1] = tmp;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    插入排序的不足,与优化

    不足:

    1. 寻找插入位置;
    2. 移动元素

    优化方案:

    1. 对已排好的序列,采用二分查找方法;
    2. 携带多个元素
    3. 数据链表化;
    4. 希尔排序

    快速排序

    快速排序基本思想

    1. 先从数列中取出一个元素作为基准数;
    2. 扫描数列,将比基准数小的元素全部放到它的左边,大于或等于基准数的元素全部放到它的右边,得到左右两个区间;
    3. 在对左右区间重复第二步,直达区间少于两个元素;

    快速排序代码实现

    void swap(int *x,int *y)
    {
        int itmp=*x;
        *x=*y;
        *y=itmp;
    }
    void quicksort(int *arr,unsigned int len)
    {
        if(len<2) return ;
        int tmp = arr[0];
        int left = 0,right = len - 1;
        while(left<right) {
            while (arr[right] >= tmp && left < right) right--;
            swap(&(arr[left]),&(arr[right]));
            while (arr[left]<tmp&&left<right) left++;
            swap(&(arr[right]),&(arr[left]));
        }
        arr[left] = tmp;
        quicksort(arr,left);
        quicksort(arr+right+1,len - right -1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    快速排序的优化

    1. 采用更合理的基准数(中心轴),减少递归的深度。从数列中选取多个数,取中间数
    2. 结合插入排序,区间在10个元素之内采用插入排序,效率更高。

    归并排序

    本节介绍一种不同于插入排序和选择排序的排序方法——归并排序,其排序的实现思想是先将所有的记录完全分开,然后两两合并,在合并的过程中将其排好序,最终能够得到一个完整的有序表。

    例如对于含有 n 个记录的无序表,首先默认表中每个记录各为一个有序表(只不过表的长度都为 1),然后进行两两合并,使 n 个有序表变为 ⌈n/2⌉ 个长度为 2 或者 1 的有序表(例如 4 个小有序表合并为 2 个大的有序表),通过不断地进行两两合并,直到得到一个长度为 n 的有序表为止。这种归并排序方法称为:2-路归并排序。

    例如对无序表{49,38,65,97,76,13,27}进行 2-路归并排序的过程如图 1 所示:
    在这里插入图片描述

    归并排序代码实现

    #include
    using namespace std;
    const int MAX = 100005;
    typedef long long ll;
    ll a[MAX] = {5,4,4,7,4,3,2,1,1},b[MAX];
    
    void merge(ll l,ll mid,ll r){
        int i = l,j = mid + 1;
        int tmp = 0;
        while (i<=mid&&j<=r){
            if(a[i]>a[j]) b[tmp++] = a[j++];
            else b[tmp++] = a[i++];
        }
        while (i<=mid) b[tmp++] = a[i++];
        while (j<=r)b[tmp++] = a[j++];
        for( i = 0 ;i< tmp ;i++){
            a[l+i] = b[i];
        }
    }
    void mergeSort(ll l,ll r){
        if(l<r){
            int mid = (l + r) / 2;
            mergeSort(l,mid);
            mergeSort(mid+1,r);
            merge(l,mid,r);
        }
    }
    int main(){
        mergeSort(0,8);
        for(int i = 0;i<9;i++){
            cout<<a[i]<<" ";
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
  • 相关阅读:
    GORM学习笔记
    Spring Boot+Vue3前后端分离实战wiki知识库系统之后端架构完善与接口开发
    Java双列集合Map
    从零到一,教你搭建「以文搜图」搜索服务(一)
    【计算机基础知识7】垃圾回收机制与内存泄漏
    nginx
    sql行转列三个方法
    算法day30|复习
    全球数字经济-全球AI大数据竞赛,全球数字经济大会-黑客马拉松大赛,国家级大学生创新创业训练计划项目-立项-经费20000,据金社区创业先锋
    JVS-rules规则引擎,解决大数据风控的自动化决策利器
  • 原文地址:https://blog.csdn.net/weixin_59803490/article/details/126268262