算法基础(五):分治

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

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

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

算法基础(五):分治_第1张图片

实例:称假币

算法基础(五):分治_第2张图片

算法基础(五):分治_第3张图片

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

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

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

1、归并排序

算法基础(五):分治_第4张图片

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

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

通常使用递归实现

算法基础(五):分治_第5张图片

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

算法基础(五):分治_第6张图片


算法基础(五):分治_第7张图片

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

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

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

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


算法基础(五):分治_第8张图片

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

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

算法基础(五):分治_第9张图片

2、快速排序

最常用的排序算法

算法基础(五):分治_第10张图片

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

算法基础(五):分治_第11张图片

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

算法基础(五):分治_第12张图片

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

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

算法基础(五):分治_第13张图片

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

算法基础(五):分治_第14张图片

每次都进行偶数次交换

奇数次交换,i

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

再对左边和右边块排

算法基础(五):分治_第15张图片

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

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

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

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

3、输出前m大的数

算法基础(五):分治_第16张图片

算法基础(五):分治_第17张图片

算法基础(五):分治_第18张图片

算法基础(五):分治_第19张图片

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

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

a需要将左边的k-1移过去

每次只做前半或者后半,

算法基础(五):分治_第20张图片

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

只对前部或后部操作

4、求排列的逆序数

算法基础(五):分治_第21张图片

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

算法基础(五):分治_第22张图片

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

算法基础(五):分治_第23张图片

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

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



你可能感兴趣的:(算法)