vector 对某个下标排序_请收下!十五分钟带你过C++的两个排序算法

    这些是非常经典的、非常基础的两个算法,属于数组的知识点,既有可能考编程题又有可能考选择题,问问你,这个比较了几次,某个数变换了几次,最后j是多少,这种问题。因此为了帮助大家巩固这些知识,专门做了这样一个推送。愿各位喜欢。

两个排序算法讲解

冒泡排序算法

        先来讲讲基本思想吧,为了把一个无序数组排成升序,我们想的是把小的往前挪,但是不能挪到比它小的前面,大的同理。那么我们就应该依次比较相邻的两个数,把小的调到前面。

        具体的过程如下,我将会演示第一轮的排序:


   1.我们现在拥有了一个待排序数组{12,36,76,29,8,45}!过会我会用一个记号来表示当前在处理的那个位置,我们不妨叫它 j 。j应该先指向a[0],因为我们会从那里开始。

    2.先比较前面两个,很好,12比36小,不用交换,直接把 j 推到下一个位置,也就是a[1]

e16ca81b603f8d40eaa8fb4128aef119.png

    3.太好了!36还是比76小,不用交换,我们的运气就这么好吗!j 继续向后走,赶紧看看后面要比较什么。

495e45451e9f8729625053d246c6dc9f.png

    4.不巧,这次76比29大,因此29应该在76前面。那么我们应该把29和76交换,然后j移到 a[3] 的位置

b4be89b13df2be7c2590066ce16ea448.png c2e3e7b82538e30ed3ce31d6cf58e044.png

    5.现在 j 指向了 a[3] ,76比8大多了,那必然要交换。同样地,j  还要向后走。

a6d74e0dbd4b5555d48db34cabf80e80.png

 6.j到了倒数第二个位置,76比45大,那就交换

aa4b994873bb0bc70976fcc5e191f7a7.png

    7.现在 j 还要往后挪吗?不用了,再挪就最后一位了,上哪比较去?j应当回到0,准备下一轮比较

294e50500732d3af91fb1473a27c34b3.png

    在了解了思想和过程后,就可以考虑程序实现了

请允许我归纳一下这个算法的实现要求:

  1. 要实现依次比较,但一次比较不可能排好序,还要实现多轮比较;

  2. 要实现元素的交换;

  3. 为了保证效率,不用去比较已经确定排好序的位置,而应直接进入下一轮。

9cc86f47042d75fa4eb7140e4932287e.png

        对于第一个要求,我们需要两层循环,内层循环负责一个一个比较过去,就像上面的 j 一样,外层循环实现一轮一轮地比较。对于外层循环,每次比较都会在末尾增加一个“确定的”位置,下一轮不需比较这些位置了,因此有n个数,应当有n-1轮比较,i∈[0,n-1)

        第二个要求很容易实现,三段式交换就行了。

        对于第三个要求,每完成一轮循环,就能确定一个位置上的数(从最后一个位置向前积累),直至完成排序。例如有n=6个数,第2轮排序完成后会确定两个位置(第5个和第6个),那么我们最后比较的两个位置应该是第3个(a[2])和第4个,j 到2即可。因此第三轮 j∈ [0,3]。容易推得,有n个数,编号是i的那一轮,j∈[0,n - ( i + 1 ))

        代码是不是呼之欲出了呢!

选择排序算法

        冒泡排序算法要比较的次数太多了,选择排序算法可以减少排序时比较的次数,快来看看吧!

        基本思想:把这个无序的数组看作一群候选人,而你要给他们安排位置,而且有个顺序。那么很自然的,如果是升序,第一个位置必然给最小的,那就喊出最小的那个坐进来,接着安排第二个,次小的,然后是第三个......直到完成排序。

        选择排序算法可以这样表述,依次假设某个位置的数是未排序里最小的,然后去后面找有没有更小的,有的话就交换。

6c607b21923270b34d917da29b05c548.png

请旋转手机

查看代码与注释

Press

void Bubble_sort(int a[ ], int n){            //数组名做函数形参       

    int  i , j ,t ;                                     //定义三个变量            

    for(i = 0 ; i < n-1; i++){                    //外层循环                 

         for(j = 0 ; j < n-(i+1) ; j++){             //内层循环

                if(a [j] > a[j+1])

                {t = a[j] ;a[j] = a[j+1] ;a[j+1] = t}    //三段式交换           

          }

    }

}

47bcb5c6e747a0fee2e0226f451fd2fc.png

    那么,接下来我会具体展示一下它的大致过程:

    1.还是上面那个数组,这次这个 j 表示目前我们要把unsorted中最小数放置的位置。(注意,后面程序里用的是i来实现这个功能,不要弄混了)

661ed98f4411e5fe6f368accffe507cb.png

    2.在a[0]~a[5]间逐个比较,找到最小的那个放到第一位,看到了,是8,交换!然后 j 后移,开始找a[1]

00f62f1f3b2057123d580829723ce80c.png

    3.此时,a[0]的位置铁定比a[1]小了,我们的搜索范围也要进一步缩小,从a[1]~a[5]间可以很方便地找到12是最小的,然后交换

3f9e6854e6e1fbed8a818dcc32eee5a0.png

    4.后面就是这个过程的重复了,就不再赘述,直接开始分析怎么实现吧。

请允许我归纳一下这个算法的实现要求:

  1. 要逐个处理数组,需要一个变量来控制;要有另一个数负责比较大小。

  2. 要实现元素的交换;

  3. 要有一种高效率的办法,如果在找那个“最小“的时候频繁交换会造成资源浪费

       第一个要求很方便,弄个变量i ,用for循环即可,显然, i ∈[0,n-1],再弄个变量i,从i指向的那个数后面一路比较到n即可

         第二个要求更方便,不多讲了。

        第三个要求则应该好好分析分析:我们可以采用两种策略,第一种简单粗暴,找到一个比现在那个数小的就马上替换(比如a[0]上是17,我们在后面找到了6,那就马上替换),但是如果有这样一个数组:

                {  17  ,   6  ,  5  ,  4  ,  3  ,  2  ,  1  }

那就麻烦了!为了找到最小的数放在a[0]上,我们将要交换6次!效率够低。

    我们还有一种方案,就是记录下最小数的下标p,最后再统一进入三段式交换一次,如果发现比a[p]更小的值就更新p。例如刚刚提到的那个数列,定义一个变量p,先记下第一个比17小的数(6)的下标1,然后发现5比6还小,就把p=2。交换数据要三个语句,而赋值只要一句,大大提高了效率。

        按照这个思路,代码可以这样写:

6c607b21923270b34d917da29b05c548.png

请旋转手机

查看代码与注释

Press

   void select_sort(int a[],int n){  

      int i,j,p,t;           //定义四个变量,其中p负责记录最小数的下标

      for(i = 0;i //外层循环,一个一个位处理过

           p = i;                                //用当前位的下标初始化

            for(j = 0;j < n; j++)                

                if(a[i] < a[p])    p=j;          //寻找更小数的下标 

                  if(p != i)  {t = a[j] ;a[j] = a[j+1] ;a[j+1] = t}  

              //如果找到了更小的就执行三段式交换,这样设计提高效率  

          }

    }

    以上就是对两个算法讲解的全部内容,里面有有一些我个人的表达和理解,如果你不太适应,请见谅,也欢迎通过学支对我提出批评。希望这样的讲解风格能够让大家喜欢,谢谢。

3317239307955a832c51fbaee82a1b7d.png

END

文字:宣企部

制作:教员李嘉毅

图片:教员部

责任编辑:宣企部

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值