信息学奥赛一本通 1235:输出前k大的数 | OpenJudge NOI 2.4 7617:输出前k大的数

【题目链接】

ybt 1235:输出前k大的数
OpenJudge NOI 2.4 7617:输出前k大的数

【题目考点】

1. 排序

【君义精讲】排序算法

【解题思路】

要输出前k大的数,需要对数字序列做降序排序。由于数据规模达到 1 0 5 10^5 105,所以必须选用复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)的排序方法。
可选的排序方法有归并排序、快速排序、堆排序、二叉树排序等。可以选择手写,或使用stl中已有的函数或容器。

【题解代码】

解法1:归并排序
  • 手写归并排序
#include <bits/stdc++.h>
using namespace std;
#define N 100005
int a[N], t[N], n, k;
void mergeSort(int l, int r)
{
    if(l >= r)
        return;
    int m = (l + r) / 2;
    mergeSort(l, m);
    mergeSort(m+1,r);
    int li = l, ri = m+1, ti = l;
    while(li <= m && ri <= r)
    {
        if(a[li] > a[ri])
            t[ti++] = a[li++];
        else
            t[ti++] = a[ri++];
    }
    while(li <= m)
        t[ti++] = a[li++];
    while(ri <= r)
        t[ti++] = a[ri++];
    for(int i = l; i <= r; ++i)
        a[i] = t[i];
}
int main()
{
    scanf("%d", &n); 
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    scanf("%d", &k);
    mergeSort(1, n);
    for(int i = 1; i <= k; ++i)
        printf("%d\n", a[i]);
    return 0;
}
  • 使用stable_sort函数
#include <bits/stdc++.h>
using namespace std;
#define N 100005
int a[N], n, k;
bool cmp(int x, int y)
{
    return x > y;
}
int main()
{
    scanf("%d", &n); 
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    scanf("%d", &k);
    stable_sort(a+1, a+1+n, cmp);
    for(int i = 1; i <= k; ++i)
        printf("%d\n", a[i]);
    return 0;
}
解法2:快速排序
  • 手写快速排序
#include <bits/stdc++.h>
using namespace std;
#define N 100005
int a[N], n, k;
void quickSort(int l, int r)
{  
    if(l >= r)
        return;
    int i = l, j = r;
    int mid = a[(l+r)/2];//将当前序列在中间位置的数定义为分隔数
    while(i <= j)//注意这里不能少了等号
    {
        while(a[i] > mid) 
            i++;  //在左半部分寻找小于等于中间数的数
        while(a[j] < mid)
            j--;    //在右半部分寻找大于等于中间数的数
        if(i <= j) //若找到一组与排序目标不一致的数对
        {                               
            swap(a[i], a[j]);//则交换它们 
            i++;
            j--;
        }
    }
    quickSort(l, j);//递归搜索左右区间
    quickSort(i, r);
}
int main()
{
    scanf("%d", &n); 
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    scanf("%d", &k);
    quickSort(1, n);
    for(int i = 1; i <= k; ++i)
        printf("%d\n", a[i]);
    return 0;
}
  • 使用sort函数
#include <bits/stdc++.h>
using namespace std;
#define N 100005
int a[N], n, k;
bool cmp(int x, int y)
{
    return x > y;
}
int main()
{
    scanf("%d", &n); 
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    scanf("%d", &k);
    sort(a+1, a+1+n, cmp);
    for(int i = 1; i <= k; ++i)
        printf("%d\n", a[i]);
    return 0;
}
解法3:堆排序
  • 手写堆
#include <bits/stdc++.h>
using namespace std;
#define N 100005
int heap[N], n, k;
//b是否比a高级。堆顶是最高级的元素 
bool isPrior(int a, int b)
{
    return a > b;//a > b:小顶堆, a < b:大顶堆 
} 
//第i结点上移 
void shiftUp(int i)
{
    if(i == 1)//p是根结点 
        return;
    if(isPrior(heap[i/2], heap[i]))
    {
        swap(heap[i], heap[i/2]);
        shiftUp(i/2);
    }
}
//第i结点下沉 
void shiftDown(int i)
{
    if(i > n/2)//如果i是叶子结点
        return; 
    int sel;//选择交换的结点位置 
    if(2*i+1 <= n && isPrior(heap[2*i],heap[2*i+1]))//有右孩子且右孩子值更大 
        sel = 2*i + 1;
    else//没有右孩子或左孩子值更大 
        sel = 2*i; 
    if(isPrior(heap[i],heap[sel]))
    {
        swap(heap[sel], heap[i]);
        shiftDown(sel); 
    }
}
//建堆 
void buildHeap()
{
    for(int i = n/2; i >= 1; --i)
        shiftDown(i); 
}
//插入元素 
void insert(int val)
{
    heap[++n] = val;
    shiftUp(n); 
}
//删除元素 
void del()
{
    swap(heap[1], heap[n]);
    n--;
    shiftDown(1); 
}
//获取堆顶 
int top()
{
    return heap[1];
}
//堆排序 这样做降序排列用小顶堆 
void heapSort()
{
    int tot = n;
    for(int i = 1; i <= tot - 1; ++i)
        del();
}
int main()
{
    scanf("%d", &n); 
    for(int i = 1; i <= n; ++i)
        scanf("%d", &heap[i]);
    scanf("%d", &k);
    buildHeap();
    heapSort();
    for(int i = 1; i <= k; ++i)
        printf("%d\n", heap[i]);
    return 0;
}
  • 使用stl的优先队列
#include <bits/stdc++.h>
using namespace std;
int n, k;
priority_queue<int, vector<int>, less<int> > pq;//less仿函数为:a<b,大顶堆 做降序排序 
int main()
{
    int a;
    scanf("%d", &n); 
    for(int i = 1; i <= n; ++i)
    {
        scanf("%d", &a);
        pq.push(a);
    }
    scanf("%d", &k);
    for(int i = 1; i <= k; ++i)
    {
        printf("%d\n", pq.top());
        pq.pop();
    }
    return 0;
}
解法4:二叉树排序

使用STL multiset

#include <bits/stdc++.h>
using namespace std;
int main()
{
   	multiset<int, greater<int> > ms;//添加greater<int>,返回a > b,这样可以使对ms的中序遍历可以得到降序排序 
   	int n, a, k, i;
   	cin >> n; 
   	for(int i = 1; i <= n; ++i)
   	{
   		cin >> a;
   		ms.insert(a);
	}
	cin >> k;
	i = 0;//下面输出的元素个数 
	for(int v : ms)
	{
		cout << v << endl;
		if(++i == k)
			break;
	}
    return 0;
}
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值