C语言-走进数据结构的简单排序算法(直接插入排序、冒泡排序、简单选择排序)(一)

简单排序算法

  数据结构是科班同学们必学的课程,当然这门课程并不是那么好学,有些同学一点就透,有些同学就需要一段比较长的积累时间,当你在一个点被卡住以后,你没有其他的思路,那么你就会被卡很久,这点相信大家都身有体会,如此就体现出了遇见一篇好文章的重要性。本文主要为三种简单排序做一些比较详细的介绍,后续再对其他排序算法进行介绍。

一、直接插入排序

 直接插入排序是一种简单的排序算法,当然有些同学刚刚接触到它会显得尤为复杂。
简单插入排序的具体做法是:在插入第i个记录时,R1、R2……Ri-1已经排好序,这时将关键字ki-1、ki-2等进行比较,从而找到应该插入的位置并将Ri插入,插入位置及其后记录依次向后移动.
 当然这是一个比较官方的说法,可能不是特别好理解。我们画一个图以后会比较好理解一些。
这里以升序为例,如下所示
用我的话来简要叙述就是,当第i-1个数大于第i个数,那么我们将第i个数拿出来,将第i个数移动到i-1数的位置上,然后将i-2与第i个数继续比较,如果第i-2个数大于第i个数,那么i继续向下比较,直到大于为止,可能你还觉得不太好理解,那么我们直接上图:
我们以五个数为例子:
第一轮排序:因为我们以升序为例,所以如图,8>7、i>i-1。于是此步骤不做调整
在这里插入图片描述
第二轮排序:要记住的是不要自作聪明去比较i-1和i-2,在简单插入排序算法中最重要的是tmp,是临时取出来的值,算法的核心在于把它插入合适的地方。

在这里插入图片描述
第三轮排序:25784
在这里插入图片描述
第四轮排序:第四轮排序同理,于是结果为降序。

升序代码示例:

基本算法理解了之后我们试着将它转化为代码:

//这是用来输出数组的,照顾一下小白同学
void print_arr(int *arr, int len)
{
  for (int i = 0; i < len; i++)
  {
    printf("%d\t", arr[i]);
  }
  printf("\n");
}
//传入参数数组,和排序的个数n
void Insertsort(int arr[], int n)
{
  int tmp;
  int i,j;
  for (i = 0; i < n; i++) //外层循环
  {
    if (arr[i] < arr[i-1])  
    {
      tmp = arr[i]; //当后一个数大于前一个数的时候,保存当前这个数
      //arr[i] = arr[i-1];  //这句代码属于优化的一部分,作用在于,当i只用交换一次就可以完成这一轮的循环的时候,
      //那么我们就可以避免这一次使用下面这层循环,从而降低一定的时间复杂度,从而进行一定的优化
      for (j = i - 1; j >= 0 && tmp < arr[j]; j--) arr[j+1] = arr[j]; 
      //这层循环的作用是比较拿出来的tmp和之前排好序的数组中的数做比较,顺序是从后往前,
      //里层循环执行完毕以后,j还进行了一次减一,所以最后tmp插入的位置应该是arr[j+1];
      arr[j+1] = tmp;
    }
  }
}

降序代码示例:

在这里插入图片描述
改变一下符号的方向这个很简单,我就直接截图了。
 直接插入排序是一种稳定的排序方法,因为用了两层循环,所以时间复杂度为O(n)。在排序过程中只需要一个元素的辅助空间用于元素的交换,空间复杂度为O(1);

二、冒泡排序

void bubbleSort(int arr[], int n)
{
  int i, j, tmp;
  for (i = 0; i < n - 1; i++) //外层循环控制循环冒泡次数
  {
    for (j = 0; j < n - i - 1; j++) //内层循环两两冒泡
    {
      if (arr[j] > arr[j + 1]) //冒出的两个泡相互比较
      {
        // 交换两个值
        tmp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = tmp;
      }
    }
  }
}

冒泡排序是大家比较熟知的排序了,所以这边也就直接给代码了。
还是简单说一下如何执行的。
冒泡排序顾名思义需要冒泡,这里的冒泡概念在于冒了两个数出来作比较。

在这里插入图片描述
 以升序为例,第几轮排序,也就是外层循环i的数值。内层循环也就是j,控制每层冒泡的个数,也就是椭圆的数量,当有五个数的时候每层需要冒泡四次,因此就比较好理解了。
 以第一轮排序为例:
5和7比较,5<7,位置不变;
7和8比较,7<8,位置不变;
8和2比较,8>2,交换位置;
因为上一轮8、2交换了位置,因此应当是
8和4比较,8>4,交换位置;
所以第一轮排序结果为:5、7、2、4、8
依次类推:
第二轮排序结果为:5、2、4、7、8
第三轮排序结果为:2、4、5、7、8
 这边进行到第三次循环就全部排序成功,因此不需要第四轮排序,所以这里浪费了一次循环的时间复杂度,因为n是最多循环次数,所以这个时间浪费是不可避免的,基于现在的硬件条件来说,这个浪费也可以忽略不计。
 冒泡排序是一种稳定的排序方法,因为用了两层循环,所以时间复杂度为O(n)。在排序过程中只需要一个元素的辅助空间用于元素的交换,空间复杂度为O(1);

三、简单选择排序

 简单选择排序,主要在于在选择一个合适的数,一个合适的下标。当我们选择升序排列的时候,我们需要选择一个数组中最小的数,将它和第一个数交换,依次类推。当我们选择升序排列的时候,我们需要选择最大的数排在最前方。

思路很简单,如何实现需要详细看代码,如下所示:

void SelectSort(int arr[], int n)
{
  int i, j, tmp, k;
  for (i = 0; i < n - 1; i++)
  {
    k = i; //记录最小值
    for (j = i + 1; j < n; j++)
    {
      if (arr[k] > arr[j]) k = j; //因为是升序,所以要选择出最小值
    }
    
    if (k != i)
    //如果k下标的值改变了,证明k下标这个值被替换为了最小值,于是需要交换两个数的位置
    //当然也可以不写这个if条件,但是如果k值未改变,那么依然会进行值交换,
    //那么当数据量过大就会影响性能
    {
      tmp = arr[i];
      arr[i] = arr[k];
      arr[k] = tmp;
    }
  }
}

 简单选择排序的核心思想在于,里层循环执行完毕以后才会进行一次值交换,这也是它的优势,里层循环的作用便在于找出最值,最大值或者最小值,找出以后再进行交换。
 k值在每一次外层循环开始的时候都会重新进行赋值,每次的k值都是i+1,找到最值之后k值被重新赋值,因此最后的值交换直接和k下标的值交换即可。
 如果每个算法都画图的话内容量太大,如果还不能理解的话,建议大家去视频网站上去看看教程,教程中一般情况下都会有动态的排序演示,这样便于理解。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值