博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
优先队列的应用:求序列第 k 个最大的元素
阅读量:6041 次
发布时间:2019-06-20

本文共 2808 字,大约阅读时间需要 9 分钟。

hot3.png

优先队列【堆】的应用:

    选择问题:输入时N 个元素以及一个整数k ,这N 个元素的集可以是全序的。该选择问题是要找出第 k 个最大的元素。。。

    有多种解决方案:

1A算法:把这些元素读入数组,并对其进行排序,返回适当的元素。假设使用的是简单排序算法,时间复杂度是O(N^2)。

1B算法:将k 个元素读入一个数组,并对其进行排序。这些元素的最小者在第k 个位置上,一个一个的处理其余的元素。当一个元素开始被处理时,它先与第k 个元素进行比较,如果该元素大,则将第k 个元素出去,该元素放在其余k - 1 个排好序的元素中的正确位置。当算法结束时,第k 个位置上的元素就是该问题的解答。该算法的运行时间为O(N*k),如果k = N / 2(上取整),则运行时间为O(N^2)【此时的 k 为中位数】。

2A算法:将N个元素读入一个数组,然后对该数组建立一个大顶堆。最后,执行k 次删除最大值的操作。从该堆最后提取的元素就是我们的答案。如果使用 BuildHeap 算法构造堆的最坏情况是 O(N) 【具体分析参见文章()】,每次删除操作用时O(logN),由于k 次删除,因此,得到总的运行时间是O(N + k * logN), 若k = N / 2(上取整),那么运行时间为O(NlogN) 【堆排序】。

2A-改进:在任意时刻都维持k 个最大元素结合S, 在前 k 个元素读入以后,当再读入一个新的元素时,该元素将与第 k 个最大的元素进行比较,记这第k 大的元素为 Sk,注意 Sk 是 S 中的最小元素。如果新元素更大,则用新元素替代这个 Sk 。此时 S 中将有一个新的最小元。这里,我们使用一个堆来实现 S 。前 k 个元素通过堆的建立过程,建立一个堆,总时间为 O(k),处理其余的每个元素的时间为 O(1) (检测元素是否进入堆),在加上时间O(log k)(在必要时删除 Sk, 并插入新元素)。因此,总的时间是O(k + (N - k) * log K) = O(N log k)。若 k 为中位数,则时间为 O(NlogN)。【代码如下:】

//利用堆寻找某一序列中第k大的元素(从小到大)即第k大的元素

#include<iostream>
#define MINHEAPSIZE 1
#define MINVALUE 0.0001
using namespace std;

typedef int ElemType;

typedef struct HeapStruct
{
 ElemType *elem;
 int Size;
 int Capasity;
}Heap, *PriorityQueue;

PriorityQueue InitializeHeap(int MaxSize)    //堆的初始化

{
 if(MaxSize < MINHEAPSIZE)
  throw exception("The priority queue is too small!");
 PriorityQueue H;
 H = new HeapStruct();
 H->Size = 0;
 H->Capasity = MaxSize;
 H->elem = new ElemType[MaxSize + 1];
 H->elem[0] = MINVALUE;
 return H;
}

void InsertHeap(PriorityQueue H, ElemType key)   //上滤过程

{
 if(H->Size == H->Capasity)
  throw exception("The priority queue is full!");
 int i;
 for(i = ++H->Size; H->elem[i / 2] > key; i /= 2)
 {
  H->elem[i] = H->elem[i / 2];
 }
 H->elem[i] = key;
}

int DeleteMin(PriorityQueue H)  //下滤过程

{
 int i, child;
 ElemType MinElem, LastElem;
 if(H->Size == 0)
 {
  cout << "The priority queue is empty!" << endl;
  return H->elem[0];
 }
 MinElem = H->elem[1];   //此时根节点可以看做是一个空穴
 LastElem = H->elem[H->Size--];
 for(i = 1; i * 2 <= H->Size; i = child)   //比较空穴i的两个孩子,child指向最小的孩子
 {
  child = i * 2;
  if(child != H->Size && H->elem[child] > H->elem[child + 1])
   child++;
  if(LastElem > H->elem[child])  //最小的孩子与最后一个元素比较,若最后一个元素小于该节点的最小孩子,

                                                    //则将最后的元素填入空穴中

   H->elem[i] = H->elem[child];
  else
   break;
 }
 H->elem[i] = LastElem;  //填补空穴
 return MinElem;
}

int SearchKElem(ElemType arr[], int length, int k)

{
 if(length < k || length <MINHEAPSIZE)
  throw exception("Invalidate input!");
 PriorityQueue H;
 H = InitializeHeap(k);
 for(int i = 0; i < k; i++)
  InsertHeap(H, arr[i]);
 for(int j = k; j < length; j++)
 {
  if(arr[j] > H->elem[1])
  {
   DeleteMin(H);
   InsertHeap(H, arr[j]);
  }
 }
 ElemType kMax = H->elem[1];
 return kMax;
}

int main()

{
 int arr[10] = {5, 2, 8, 1, 3, 9, 7, 4, 6,10};
 int k;
 cout << "请输入k值:" ;
 cin >> k;
 int result = SearchKElem(arr, 10, k);
 cout <<"倒数第k大的元素为:" << result << endl;

 system("pause");

 return 0;
}

 

 

转载于:https://my.oschina.net/u/2260265/blog/339950

你可能感兴趣的文章
设计模式
查看>>
ios开发中的基本设计模式
查看>>
Python wordcloud 库安装
查看>>
数学书籍备忘
查看>>
JAVA NIO 管道Pipe
查看>>
LINUX修改IP以及修改eth0、eth1顺序的方法
查看>>
Apache Nutch源码工程在Linux和Windows平台换行符差异问题处理
查看>>
TDDL、Amoeba、Cobar、MyCAT架构比较
查看>>
Lucene 3.6 contrib 学习总结
查看>>
SFB 项目经验-35-分配公网证书 For Exchange Server 2016(图解)
查看>>
tomcat调优
查看>>
CentOS 6.5编译安装MySQL 5.6.16
查看>>
httpd-2.4的编译安装
查看>>
IOS OC的消息结构 和 运行期组件
查看>>
Python第五天(集合)
查看>>
关于iocp 与epoll
查看>>
我的core文件去哪了
查看>>
eclipse 之初探
查看>>
选择微服务部署策略
查看>>
【重磅】大众点评运维架构图文详解 @马哥教育联合创始人张冠宇
查看>>