十大经典排序算法(代码实现),建议收藏

兜兜转转,一晃年关将至。时间证明了一个道理,学啥忘啥,学的越快忘得越快,还不如踏踏实实写点笔记心得来的实在。

编程初学期间,排序算法是让人抓头最多的一块。为什么我连最简单的冒泡排序都理解不了,我是不是不选错专业了,很多人会有这样的疑问,然后就有人做gif冒泡懵逼排序,别说,还挺形象的。

其实排序算法这块,着急不得,这个排序算法不会就换一个排序算法来学,总有一种排序算法你能够理解的,等需要用到排序的时候,你只要会一种就可以了。

在这里我列举了7中常见的排序算法并用C语言实现,你们可能就要问了,不是十种吗?怎么还能缺斤短两,不是我不会写啊,是写起来麻烦,你们也用不到后面那几种,跟别说去研究了,能看懂常见的七种排序算法你就能在学校里横着走了。

后台回复【排序算法】可以拿到全部代码

目录

一、冒泡排序

二、选择排序

三、插入排序

四、快速排序

五、希尔排序

六、归并排序

七、桶(基数)排序

01

冒泡排序

相信大家最熟悉的就是冒泡排序了,这个我就不多说

直接上动图演示原理,外加代码实现冒泡排序:

C语言代码实现:​​​​​​​

void BubbleSort(int arr[], int n){  //从小到大排序 相邻来两个数比较,将大的数字往后放  for (int i = 0; i < n - 1; i++)      //n-1是因为数组下标最大为n-1 要进行10轮比较  {    //n-1是因为数组下标最大为n-1 要进行10次比较,再减i是因为每最后的i个元素已经有序不需要继续排序    for (int j = 0; j < n - 1 - i; j++)    {      if (arr[j] > arr[j + 1])      //两两比较,将小的数据放前面      {        swap(arr, j + 1, j);        //交换arr数组arr[j+1]和arr[j]的值      }    }  }}//交换函数后面就不列举了,凡是swap都是下面代码实现的void swap(int arr[], int x, int y){  int temp = arr[x];  arr[x] = arr[y];  arr[y] = temp;}

02

选择排序

首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾,重复操作。

动图演示原理,外加代码实现选择排序:

C语言代码实现:​​​​​​​

void SelectSort(int arr[], int n){  for (int i = 0; i < n - 1; i++)  {    for (int j = i + 1; j < n; j++)    {      if (arr[i] > arr[j])      {        swap(arr, i, j);  //交换arr数组arr[i]和arr[j]的值      }    }  }}

03

插入排序

插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的,就是将未排序的数字插入到已排序的数列中

动图演示原理,外加代码实现插入排序:

C语言代码实现:​​​​​​​

void InsertSort(int arr[], int n){  int tempVal;  for (int i = 1, j; i < n; i++)  {    tempVal = arr[i];  //保存要插入的值    for (j = i - 1; tempVal < arr[j] && j >= 0; --j)  //数据往后移动,给要插入的值腾位    {      arr[j + 1] = arr[j];    }    arr[j + 1] = tempVal;  //插入数据  }}

希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。插入排序是将未排序的数字插入到已排序数列中,而希尔排序是将一个已排序的数列插入到另一个已排序的数列中。

示意图演示原理,外加代码实现希尔排序:

C语言代码实现:​​​​​​​

void ShellSort(int arr[], int n){  int tempVal, j;  int jump = n >> 2;      //步长值  while (jump != 0)  {    for (int i = jump; i < n; i++)    {      tempVal = arr[i];  //保存待排序的第一个数,也就是待插入的数      for (j = i - jump; j >= 0 && tempVal < arr[j]; j -= jump)      {        arr[j + jump] = arr[j];      }      arr[j + jump] = tempVal;    }    jump = jump >> 1;    //步长值减半  }}

06

归并排序

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。

示意图演示原理,外加代码实现归并排序:

C语言代码实现:

void MergeSort(int arr[], int left, int right){  if (left >= right)//递归的终止条件,left == right证明这个区间只有一个元素,不需要再拆了    return;  int mid = ((right - left) >> 1) + left;//求中点  MergeSort(arr, left, mid);    //拆分左  MergeSort(arr, mid + 1, right);  //拆分右  //并操作  _merge_in_arr(arr, left, mid, right);}
void _merge_in_arr(int arr[], int left, int mid, int right){  int length = right - left + 1;          //定义一个辅助的空间的长度  int *pData = (int*)malloc(sizeof(int)*length);//分配一个动态内存来调整元素的位置  memset(pData, 0, sizeof(int)* length);
  //合并  int low = left;    //左边区间的起始下标  int hig = mid + 1;  //右边区间的起始下标  int index = 0;    //辅助数组的下标
  while (hig <= right)//右区间没有合并完  {    while (low <= mid && arr[low] <= arr[hig])//证明左区间没有合并完,且左区间的值小于右区间的值    {      pData[index] = arr[low];      //把左边的值放进辅助数组      low++;                //左边往高位移,下一次需要判断左边的新下标      index++;              //下一次放进辅助数组的新下标    }    if (low > mid)  //证明左区间已经放完      break;
    while (hig <= right && arr[low] > arr[hig])//证明右区间没有合并完,且左区间的值大于右区间的值    {      pData[index] = arr[hig];      //把右边的值放进辅助数组      hig++;                //右边往高位移,下一次需要判断右边的新下标      index++;              //下一次放进辅助数组的新下标    }  }
  //到这一步,证明起码有一个区间已经合并完成  if (hig <= right)  //证明右边没有完成    memmove(&pData[index], &arr[hig], sizeof(int)* (right - hig + 1));  if (low <= mid)    //证明左边没有完成    memmove(&pData[index], &arr[low], sizeof(int)* (mid - low + 1));
  //把所有区间都合并到了辅助区间  memmove(&arr[left], pData, sizeof(int)* length);  free(pData);  //释放空间}

07

桶排序

桶排序是典型的空间换时间,在对整数排序中,没有什么算法能比它还快,但是在空间浪费上,它是祖宗。

示意图演示原理,外加代码实现桶排序:

C语言代码实现:​​​​​​​

void radix_sort(int arr[], size_t len){  int**temp = (int **)malloc(sizeof(int) * 10);  //10行  //申请动态内存   辅助数组temp[10][];  for (int i = 0; i < 10; i++)  {    temp[i] = (int *)malloc(sizeof(int)*len);  }
  for (int i = 1; i <= 100; i *= 10)//循环数值可能有的位数  {    for (int x = 0; x < 10; ++x)//辅助数组行循环    {      for (int y = 0; y < len; ++y)//辅助数组列循环      {        temp[x][y] = -1;//辅助数组的初始化赋值,-1表示在arr里面不可能出现的数值       }    }    //arr数组中的元素放入辅助数组    for (int m = 0; m < len; ++m)    {      int index = (arr[m] / i) % 10;      temp[index][m] = arr[m];    }    //把辅助数组的内容放回待排序数组    int k = 0;//待排序的下标    for (int x = 0; x < 10; x++)    {      for (int y = 0; y < len; ++y)      {        if (temp[x][y] != -1)          arr[k++] = temp[x][y];      }    }  }  //释放内存  for (int i = 0; i < 10; i++)  {    free(temp[i]);  }  free(temp);}

算法复杂度

这个算法的复杂度纯理论,我就放到最后来讲

一个时间复杂度,一个空间复杂度

一个稳定,一个不稳定

稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面

不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面

时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律

空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。

附录:

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值