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

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

冒泡排序

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

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

冒泡排序代码实现


#include <stdlib.h>
#include <stdio.h>

// 采用两层循环实现的方法。
// 参数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);
}

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

冒泡排序算法的优化


#include <stdlib.h>
#include <stdio.h>

// 采用两层循环实现的方法。
// 参数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);

}

选择排序

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

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

选择排序代码实现

#include <stdlib.h>
#include <stdio.h>

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);
}


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

选择排序的优化

// 优化后的选择排序,作者:C语言技术网(www.freecplus.net)码农有道。
#include <stdlib.h>
#include <stdio.h>

// 交换两个变量的值。
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);
}

插入排序

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

直接插入排序是插入排序算法中的一种,采用的方法是:在添加新的记录时,使用顺序查找的方式找到其要插入的位置,然后将新记录插入。
很多初学者所说的插入排序,实际上指的就是直接插入排序算法,插入排序算法还包括折半插入排序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. 移动元素

优化方案:

  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. 结合插入排序,区间在10个元素之内采用插入排序,效率更高。

归并排序

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

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

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

归并排序代码实现

#include<bits/stdc++.h>
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]<<" ";
   }
}
  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jie3606

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值