参考博客:传送门
在上面的博客中介绍了求序列第K大的几种算法,感觉收益良多,其中最精巧的还是利用快速排序的思想O(n)
查询的算法。仔细学习以后我将其中的几个实现了一下。
解法 1:
将乱序数组从大到小进行排序然后取出前K大,总的时间复杂度为O(nlogn)
解法 2:
利用选择排序或交互排序,取出前K大,总的时间复杂度为O(nk)
解法 3:
借鉴快速排序的思想,复杂度近似为O(n)
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;int kth_number(int *a,int l,int r,int k)
{if(r-l == 1) return a[l];int key=a[l];int index=l;for(int i=l+1;i<r;++i){if(a[i]>=key) continue;else{++index;swap(a[i],a[index]);}}swap(a[index],a[l]);if(r-index == k) return a[index];if(r-index-1 >= k) return kth_number(a,index+1,r,k);else return kth_number(a,l,index,k-r+index);
}
测试程序
#include<cstdio>
#include"Kth_number.h"using namespace std;int main()
{int n,k;const int MAXN=1005;int a[MAXN];printf("n="); scanf("%d",&n);printf("k="); scanf("%d",&k);if(k>n) k=n;printf("please input %d number:\n",n);for(int i=0;i<n;++i)scanf("%d",&a[i]);printf("the %dth number of array is %d\n",k,kth_number(a,0,n,k));return 0;
}
运行结果
解法 4:
借助堆排序的思想,将前K个数字弹出,复杂度为建立堆的O(4n)
加上k次堆排序O(logn)
为O(4n+klogn)
实现程序
#include<cstdio>
#include<cstdlib>
#include<climits>
#include<algorithm>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<unistd.h>using namespace std;void Adjust(int *a, int n, int i)
{int x = a[i];for(int k = i<<1; k <= n; k = k<<1){if(k+1 <= n && a[k] < a[k+1])++k;if(a[k] > x){a[i] = a[k];i = k;}else{break;}}a[i] = x;
}void MakeHeap(int *a, int n)
{for(int i = n/2;i > 0;--i){Adjust(a, n, i);}
}void HeapSort(int *a,int n,int k,int *ans)
{int m=n-k;for(int i = n; i > m; i--){swap(a[1], a[i]);Adjust(a, i-1, 1);}*ans = a[m+1];
}int main(int argc, char* argv[])
{int n;const int MAXN = 1024;scanf("%d", &n);int a[MAXN] = {0};for(int i = 1; i <= n; ++i){scanf("%d", &a[i]);}int k;scanf("%d", &k);if(k > n) k = n;MakeHeap(a, n);int ans;HeapSort(a, n, k, &ans);printf("ans=%d\n", ans);return 0;
}
测试结果
解法 5:
维护一个大小为k的小顶堆,对于数组中的每一个元素判断与堆顶的大小,若堆顶较大,则不管,否则弹出堆顶,将当前值插入到堆中。时间复杂度O(4k+nlogk)
实现程序
#include<cstdio>
#include<cstring>using namespace std;void Adjust(int *a,int n,int i)
{int x=a[i];for(int k=i<<1;k<=n;k<<=1){if(k+1<=n && a[k]>a[k+1])++k;if(a[k]<x){a[i]=a[k];i=k;}else break;}a[i]=x;
}
void MakeHeap(int *a,int n)
{for(int i=n/2;i>0;--i){Adjust(a,n,i);}
}
int KthNumber(int *a,int n,int k)
{
// int *b=new int[k];int b[1024];for(int i=1;i<=k;++i){b[i]=a[i];}MakeHeap(b,k);for(int i=k+1;i<=n;++i){if(a[i]>b[1]){b[1]=a[i];Adjust(b,k,1);}}return b[1];
}int main()
{int n,k;printf("n="); scanf("%d",&n);printf("k="); scanf("%d",&k);
// int* a = new int[n];int a[1024]={0};for(int i=1;i<=n;++i)scanf("%d",&a[i]);printf("%d\n",KthNumber(a,n,k));
// delete a;return 0;
}
测试结果
解法 6:
利用Hash
保存数组中元素出现的次数,利用计数排序的思想,线性从大到小扫描中得到结果,时间复杂度为O(n)