算法-优先队列与堆排序

简介:

我们自己每天使用的电脑能同时运行多个应用程序,没有感觉到卡顿,电脑为每个应用程序的事件分配了一个优先级,移动端的手机也是,通常不管我们是在看电影,发短信只要有电话,电话绝对是优先级最高的。这个时候我们需要一种合理的数据结构删除最大元素和插入元素,我们可以称之为优先队列。实现这种优先队列最合适的数据结构可以通过经典的二叉堆来实现,相对于其他数据结构更高效。

优先队列

开始撸代码之前我们需要明白几个概念:

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" );

上面的测试是最坏的情况的比较,看下效果:

周一好心情,欢迎探讨~ 

本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4606332.html,如需转载请自行联系原作者

相关文章
|
3月前
|
存储 人工智能 算法
深入浅出堆排序: 高效算法背后的原理与性能
深入浅出堆排序: 高效算法背后的原理与性能
47 1
|
5月前
|
算法 搜索推荐 Python
Python算法——堆排序
Python算法——堆排序
45 2
|
5月前
|
算法 搜索推荐 C#
C#堆排序算法
C#堆排序算法
|
7天前
|
算法
堆排序+TopK问题——“数据结构与算法”
堆排序+TopK问题——“数据结构与算法”
|
27天前
|
搜索推荐 算法
【八大经典排序算法】堆排序
【八大经典排序算法】堆排序
12 0
|
1月前
|
搜索推荐 C语言
排序算法-选择/堆排序(C语言)
排序算法-选择/堆排序(C语言)
11 0
|
2月前
|
搜索推荐 算法 Java
【数据结构排序算法篇】----堆排序【实战演练】
【数据结构排序算法篇】----堆排序【实战演练】
25 2
|
2月前
|
算法 搜索推荐
堆排序算法
堆排序算法
17 0
|
3月前
|
存储 搜索推荐
常见排序算法原理及实现——第二部分(归并排序、快速排序、堆排序)
常见排序算法原理及实现——第二部分(归并排序、快速排序、堆排序)
|
4月前
|
搜索推荐 算法 调度
堆排序:高效而稳定的排序算法
在计算机科学中,排序算法是一项基本而重要的任务。堆排序作为一种经典的排序算法,以其高效性和稳定性而受到广泛关注。本文将介绍堆排序的原理、实现方法以及其在实际应用中的优势。

热门文章

最新文章