递归和排序算法的应用
创始人
2024-02-19 09:53:43

一、递归常见问题和注意事项

1. 堆栈溢出;
2. 警惕重复运算:
可以使用一个数据结构(散列表)将已经计算过的f(k)保存起来,每当调用到f(k)时,先产看下是否已经求结果,从而避免重复计算。
3. 将递归代码修改为非递归代码

二、冒泡、插入、选择排序

时间复杂度都是O(n^2);
**稳定性:**原序列中相同值得元素,经过排序后前后顺序不变;
**原地排序:**空间复杂度O(1);

冒泡排序:每次便利剩余的全部找出剩余最小的值;
插入排序:前面是有序的,从后面序列拿出最前面的元素插入到前面有序队列中合适的位置。分为已排序空间未排序空间
选择排序:分为已排序空间未排序空间,从未排序空间找出最小值放入已排序空间的末尾;

插入排序相对于冒泡排序的优势?


冒泡排序中数据的交换操作:
if (a[j] > a[j+1]) { // 交换int tmp = a[j];a[j] = a[j+1];a[j+1] = tmp;flag = true;
}插入排序中数据的移动操作:
if (a[j] > value) {a[j+1] = a[j];  // 数据移动
} else {break;
}

使用冒泡排序需要K次交换操作,每次交换需要3次赋值语句,所需时间为3*k,而插入排序只需要K个时间。

三、归并排序和快速排序

归并排序:先分解,再合并。将数组采用递归的思想从中间分解拆分,知道不能拆分,然后再将拆分的进行排序后合并,使用分治思想
归并排序可以使稳定排序
在这里插入图片描述


// 归并排序算法, A是数组,n表示数组大小
merge_sort(A, n) {merge_sort_c(A, 0, n-1)
}// 递归调用函数
merge_sort_c(A, p, r) {// 递归终止条件if p >= r  then return// 取p到r之间的中间位置qq = (p+r) / 2// 分治递归merge_sort_c(A, p, q)merge_sort_c(A, q+1, r)// 将A[p...q]和A[q+1...r]合并为A[p...r]merge(A[p...r], A[p...q], A[q+1...r])
}

merge()函数伪代码,merge()函数可以借用哨兵编程简化。


merge(A[p...r], A[p...q], A[q+1...r]) {var i := p,j := q+1,k := 0 // 初始化变量i, j, kvar tmp := new array[0...r-p] // 申请一个大小跟A[p...r]一样的临时数组while i<=q AND j<=r do {if A[i] <= A[j] {tmp[k++] = A[i++] // i++等于i:=i+1} else {tmp[k++] = A[j++]}}// 判断哪个子数组中有剩余的数据var start := i,end := qif j<=r then start := j, end:=r// 将剩余的数据拷贝到临时数组tmpwhile start <= end do {tmp[k++] = A[start++]}// 将tmp中的数组拷贝回A[p...r]for i:=0 to r-p do {A[p+i] = tmp[i]}
}

在merge()合并函数需要临时空间,所以空间复杂度为O(n)。

快速排序:
快速排序是由上到下处理问题,利用原地分区,所以空间复杂度是O(1),不是稳定的排序算法。快速排序重点是选择合适的pivot,否可有可能导致时间复杂度退化到O(n^2)
在这里插入图片描述


// 快速排序,A是数组,n表示数组的大小
quick_sort(A, n) {quick_sort_c(A, 0, n-1)
}
// 快速排序递归函数,p,r为下标
quick_sort_c(A, p, r) {if p >= r then returnq = partition(A, p, r) // 获取分区点quick_sort_c(A, p, q-1)quick_sort_c(A, q+1, r)
}

partition()分区函数函数


partition(A, p, r) {pivot := A[r]i := pfor j := p to r-1 do {if A[j] < pivot {swap A[i] with A[j]i := i+1}}swap A[i] with A[r]return i

四、排序的思考问题

1、现在有 10 个接口访问日志文件,每个日志文件大小约 300MB,每个文件里的日志都是按照时间戳从小到大排序的。希望将这 10 个较小的日志文件,合并为 1 个日志文件,合并之后的日志仍然按照时间戳从小到大排列。如果处理上述排序任务的机器内存只有 1GB,有什么好的解决思路,能“快速”地将这 10 个日志文件合并吗?

最大时间戳的最小值这一点很关键 保证了当前取出来的数据是未排序种全局最小的。
批量读取文件。
分阶段的快速排序。

先取得十个文件时间戳的最小值数组的最小值a,和最大值数组的最大值b。然后取mid=(a+b)/2,然后把每个文件按照mid分割,取所有前面部分之和,如果小于1g就可以读入内存快排生成中间文件,否则继续取时间戳的中间值分割文件,直到区间内文件之和小于1g。同理对所有区间都做同样处理。最终把生成的中间文件按照分割的时间区间的次序直接连起来即可。类似桶排序。

2、如何在O(n)时间复杂内查找无序数组第K大的元素?
利用快速排序的思想,数组下标和K进行比较。

3、如何根据年龄对100万用户进行排序?
利用桶排序。

五、空间复杂度为O(n)排序,桶排序、计数排序、基数排序

1、桶排序(Bucket sort)
在这里插入图片描述
适用于在外部排序,数据存储在磁盘中,数据量比较大,内存有限,无法将全部数据加载到内存进行排序。
重点是如何将数据均匀的划分到每个桶里面。

2、计数排序(Counting sort)
桶排序的特殊情况,当数据的范围较小时,例如高考成绩排序,有一组数据2,5,3,0,2,3,0,3,使用大小为6的桶C[6]:
在这里插入图片描述
在这里插入图片描述
3、基数排序(radix sort)
例如对十万个电话号码进行排序,借助与稳定的排序,从高位向低位开始进行排序,排序11次即可。但是有时候要排序的数据长度不是等长的,可以对位数不够的在后面补0。
基数排序对要排序的数据是有要求的,需要可以分割出独立的“位”来比较,且位之间有递进的关系,如果数据a的高位比数据b高位大,那剩下的就不用比较了。

六、如何实现一个通用、高效的排序算法?

快速排序如何优化:主要是找到合适的分区点,为了避免极端情况,可以采用三数取中,随机法

七、二分法

如何快速的定位出IP对应的省份地址?
如果IP和归属地的关系不经常更新,可以先按照IP大小关系进行排序,查找时根据二分法进行查找。

有重复值的有序序列中查找一地个大于某值的元素?

相关内容

热门资讯

北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...