算法基础(五):分治

慕课:程序设计与算法(二)算法基础 郭玮老师课程的学习笔记

1、归并排序
2、快速排序
3、输出前m大的数
4、求排列的逆序数

分治:讲一个任务分成规模更小的多个任务分别处理,最后再处理这些任务的结果,实现整个任务的完成


实例:称假币



这个问题的解决方法有点类似于二分求解,将假币每次分成两份分别称量,

分治经常使用递归来实现,将币分一半,再分一半,直到无法分,是递归的思想

实际上很多算法都有相似之处,我们可以将算法放到一起去记忆,可能更有利于学习

1、归并排序


排序的复杂度是O(nlogn),每个归并排序都是一半一半,即将数组分为一半排序后,再分为一半,直到只有一个元素就无需再分,然后将这些排好序的有序数组进行合并

这种将问题每次分成两部分直到无法分的思想就是分治,即将问题拆成一个个的小问题,然后再将结果归并

通常使用递归实现


归并排序需要额外存储空间同样大小的另外一个数组空间,即提高时间牺牲空间




分治:如果s=e则返回,即此时排序的数据只有一个无需再分

按照分治的思想先把前一半排序,再把后一半排序,所以递归实现分成前半部分和后半部分

对数组s到e排序,先分成s到中点m,再分成m+1到结尾e,一直分成两半,最后再归并,然后结果就是从s到e有序

归并merge方法,利用额外存储空间tmp减少了时间



归并:时间复杂度为线性复杂度,即O(n)。因为合并的两个数组有序,所以只需要从头到尾扫一遍两个数组即可,指针一开始指向开头,两个比较则小放进tmp暂时空间里,然后小的指针后挪,大的指针不动,以后每次都比较指针指着的元素,若小则移进空间中,并后移指针,大的则不动。

最后将tmp中的数组移到结果数组中


2、快速排序

最常用的排序算法


前提:k比较恰巧即左边和右边数差不多,处于中间的位置,此时使用快速排序的方法比较好


i和j指针会交换,如果a[j]>=k时,j前移,交换a[i]和a[j];如果a[i]<=k,i后移,交换a[i]和a[j]


2次交换,通过交换,使得大于k的在右边,小于k的在左边

i和j分到一块则结束,数组分成两半


交换方法,参数引用,改变形参则实参也改变


每次都进行偶数次交换

奇数次交换,i<j,a[i]<=k,每次都swap

循环结束后,a[i]=k

再对左边和右边块排


当k在中间差不多的话,也是O(nlogn)

但是k不确保在中间,即左边和右边一样多,k为中点

运气不太坏的情况,相当于分治,两边数量差不多,每次都分一半

运气最坏的情况O(n^2),例如k是最小的,前一半元素0个,后一半元素剩下的,这时候我们可以先随机打乱

3、输出前m大的数





a==k则最大的都在右边

a>k则,最大的k个数肯定在右边但是不一定全在右边

a<k,说明左边还有大的没有在右边还需要将左边的k-1移过去

每次只做前半或者后半,


a*n就是把数组分两半的工作,

只对前部或后部操作

4、求排列的逆序数


递归求左半边和右半边逆序数,然后再求左半边取一个和右半边取一个组成逆序数,两者求和


枚举每一个作为左边,都要考察右边的所有数一旦发现一个少的则是


如果第一个i小于等于j,则左边所有的都无法与右边第一个形成

直到找到左边小于等于右边时,且j右边所有数都可以与i构成逆序



阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页