算法-优先队列与堆排序
我们自己每天使用的电脑能同时运行多个应用程序,没有感觉到卡顿,电脑为每个应用程序的事件分配了一个优先级,移动端的手机也是,通常不管我们是在看电影,发短信只要有电话,电话绝对是优先级最高的。这个时候我们需要一种合理的数据结构删除最大元素和插入元素,我们可以称之为优先队列。实现这种优先队列最合适的数据结构可以通过经典的二叉堆来实现,相对于其他数据结构更高效。
优先队列
开始撸代码之前我们需要明白几个概念:
1.当一棵二叉树的每个节点都大于等于等于它的两个子节点时,它称之为堆有序。
2.二叉堆是一组能够用堆有序的完全二叉树排序的元素,并在数组中按照层级存储。
在一个堆中,索引为index的节点的父节点的位置是index/2,子节点的位置为2*index和2*index+1,用数组实现一个完全二叉树的插入元素和删除最大元素是非常简洁的。
核心代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | -( void )insert:( NSString *)value{ [ self .dataSource addObject:value]; self .maxIndex= self .maxIndex+1; [ self swimUp: self .maxIndex]; } -( void )deleteMax{ [ self swap:1 secondIndex: self .maxIndex]; //第一个节点和最后一个节点进行交换 [ self .dataSource removeObjectAtIndex: self .maxIndex--]; //删除最后的节点 [ self sinkDown:1]; //恢复堆的有序性 } -( void )swimUp:( NSInteger )index{ //父节点小于当前的子节点 while (index>1&&[ self lessCompare:index/2 secondIndex:index]) { [ self swap:index/2 secondIndex:index]; index=index/2; } } -( void )sinkDown:( NSInteger )index{ while (2*index<= self .maxIndex) { NSInteger i=2*index; //左右节点大小判断 if (i< self .maxIndex&&[ self lessCompare:i secondIndex:i+1]) { i++; } if (![ self lessCompare:index secondIndex:i]) break ; [ self swap:index secondIndex:i]; index=i; } } -( BOOL )lessCompare:( NSInteger )firstIndex secondIndex:( NSInteger )secondIndex{ return [[ self .dataSource objectAtIndex:firstIndex] integerValue]<[[ self .dataSource objectAtIndex:secondIndex] integerValue]; } -( void )swap:( NSInteger )firstIndex secondIndex:( NSInteger )secondIndex{ NSString *temp=[ self .dataSource objectAtIndex:firstIndex]; self .dataSource[firstIndex]=[ self .dataSource objectAtIndex:secondIndex]; self .dataSource[secondIndex]=temp; } |
插入元素调用insert,删除最大元素调用deleteMax即可,注意数组是从1开始的为了方便的使用二叉树的性质,第一个0位不使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | PriorityQueue *queue=[[PriorityQueue alloc]init]; NSMutableArray *arr=[[ NSMutableArray alloc]initWithCapacity:10]; [arr addObject:[ NSNull null]]; [arr addObject:@ "8" ]; [arr addObject:@ "5" ]; [arr addObject:@ "6" ]; [arr addObject:@ "2" ]; [arr addObject:@ "3" ]; [arr addObject:@ "4" ]; queue.dataSource=arr; queue.maxIndex=[arr count]-1; [queue insert:@ "7" ]; // [queue deleteMax]; for ( NSInteger i=1; i<[queue.dataSource count]; i++) { NSLog (@ "数值:%@" ,queue.dataSource[i]); } NSLog (@ "iOS技术交流群:228407086" ); NSLog (@ "原文地址:http://www.cnblogs.com/xiaofeixiang" ); |
测试结果:
堆有序
上面的Demo中从最开始就是堆有序的,但是很多情况我们是一个无序的堆,需要自己重新构造排序,分为两步:
1.首先将堆变成一个大根堆,也就是最大堆。
2. 重复删除最大元素,最后的元素和第一个进行交换,然后进行下沉操作(和有序堆中删除元素的方式一样)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | -( void )sort{ NSInteger count=[ self .dataSource count]-1; for ( NSInteger k=count/2; k>=1; k--) { [ self sinkSort:k count:count]; } while (count>1) { [ self swap:1 secondIndex:count--]; [ self sinkSort:1 count:count]; } } -( void )sinkSort:( NSInteger )index count:( NSInteger )count{ while (2*index<=count) { NSInteger i=2*index; //左右节点大小判断 if (i<count&&[ self lessCompare:i secondIndex:i+1]) { i++; } if (![ self lessCompare:index secondIndex:i]) break ; [ self swap:index secondIndex:i]; index=i; } } |
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | PriorityQueue *queue=[[PriorityQueue alloc]init]; NSMutableArray *arr=[[ NSMutableArray alloc]initWithCapacity:10]; [arr addObject:[ NSNull null]]; [arr addObject:@ "1" ]; [arr addObject:@ "2" ]; [arr addObject:@ "3" ]; [arr addObject:@ "4" ]; [arr addObject:@ "5" ]; [arr addObject:@ "6" ]; [arr addObject:@ "7" ]; queue.dataSource=arr; queue.maxIndex=[arr count]-1; [queue sort]; for ( NSInteger i=1; i<[queue.dataSource count]; i++) { NSLog (@ "数值:%@" ,queue.dataSource[i]); } NSLog (@ "iOS技术交流群:228407086" ); NSLog (@ "原文地址:http://www.cnblogs.com/xiaofeixiang" ); |
上面的测试是最坏的情况的比较,看下效果:
周一好心情,欢迎探讨~
作者:FlyElephant
出处:http://www.cnblogs.com/xiaofeixiang
说明:博客经个人辛苦努力所得,如有转载会特别申明,博客不求技惊四座,但求与有缘人分享个人学习知识,生活学习提高之用,博客所有权归本人和博客园所有,如有转载请在显著位置给出博文链接和作者姓名,否则本人将付诸法律。
出处:http://www.cnblogs.com/xiaofeixiang
说明:博客经个人辛苦努力所得,如有转载会特别申明,博客不求技惊四座,但求与有缘人分享个人学习知识,生活学习提高之用,博客所有权归本人和博客园所有,如有转载请在显著位置给出博文链接和作者姓名,否则本人将付诸法律。
标签:
算法
, Objective-C
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述