21级数据结构与算法实验8——排序
迪丽瓦拉
2024-03-04 16:14:44
0

目录

7-1 统计工龄

7-2 寻找大富翁

7-3 点赞狂魔

7-4 插入排序还是归并排序

7-5 插入排序还是堆排序

7-6 逆序对

7-7 堆排序

7-8 石子合并

7-9 第k小

7-10 快速排序的过程


7-1 统计工龄

作者 陈越

单位 浙江大学

给定公司N名员工的工龄,要求按工龄增序输出每个工龄段有多少员工。

输入格式:

输入首先给出正整数N(≤105),即员工总人数;随后给出N个整数,即每个员工的工龄,范围在[0, 50]。

输出格式:

按工龄的递增顺序输出每个工龄的员工个数,格式为:“工龄:人数”。每项占一行。如果人数为0则不输出该项。

输入样例:

8

10 2 0 5 7 2 5 2

输出样例:

0:1

2:3

5:2

7:1

10:1

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

参考代码:C++(g++)

#include 
using namespace std;
int main(){map mp;int n;cin>>n;while(n--){int x;cin>>x;mp[x]++;}for(auto i:mp)printf("%d:%d\n", i.first, i.second);
}

7-2 寻找大富翁

作者 陈越

单位 浙江大学

胡润研究院的调查显示,截至2017年底,中国个人资产超过1亿元的高净值人群达15万人。假设给出N个人的个人资产值,请快速找出资产排前M位的大富翁。

输入格式:

输入首先给出两个正整数N(≤106)和M(≤10),其中N为总人数,M为需要找出的大富翁数;接下来一行给出N个人的个人资产值,以百万元为单位,为不超过长整型范围的整数。数字间以空格分隔。

输出格式:

在一行内按非递增顺序输出资产排前M位的大富翁的个人资产值。数字间以空格分隔,但结尾不得有多余空格。

输入样例:

8 3

8 12 7 3 20 9 5 18

输出样例:

20 18 12

代码长度限制

16 KB

时间限制

500 ms

内存限制

64 MB

参考代码:C++(g++)

#include 
using namespace std;
using ll=long long;
vector a;
bool cmp(ll a, ll b){return a>b;
}
int main(){int n,m;cin>>n>>m;m=min(m,n);for(int i=0;i>x;a.push_back(x);}sort(a.begin(), a.end(), cmp);cout<

7-3 点赞狂魔

作者 陈越

单位 浙江大学

微博上有个“点赞”功能,你可以为你喜欢的博文点个赞表示支持。每篇博文都有一些刻画其特性的标签,而你点赞的博文的类型,也间接刻画了你的特性。然而有这么一种人,他们会通过给自己看到的一切内容点赞来狂刷存在感,这种人就被称为“点赞狂魔”。他们点赞的标签非常分散,无法体现出明显的特性。本题就要求你写个程序,通过统计每个人点赞的不同标签的数量,找出前3名点赞狂魔。

输入格式:

输入在第一行给出一个正整数N(≤100),是待统计的用户数。随后N行,每行列出一位用户的点赞标签。格式为“Name K F1​⋯FK​”,其中Name是不超过8个英文小写字母的非空用户名,1≤K≤1000,Fi​(i=1,⋯,K)是特性标签的编号,我们将所有特性标签从 1 到 107 编号。数字间以空格分隔。

输出格式:

统计每个人点赞的不同标签的数量,找出数量最大的前3名,在一行中顺序输出他们的用户名,其间以1个空格分隔,且行末不得有多余空格。如果有并列,则输出标签出现次数平均值最小的那个,题目保证这样的用户没有并列。若不足3人,则用-补齐缺失,例如mike jenny -就表示只有2人。

输入样例:

5

bob 11 101 102 103 104 105 106 107 108 108 107 107

peter 8 1 2 3 4 3 2 5 1

chris 12 1 2 3 4 5 6 7 8 9 1 2 3

john 10 8 7 6 5 4 3 2 1 7 5

jack 9 6 7 8 9 10 11 12 13 14

输出样例:

jack chris john

代码长度限制

16 KB

时间限制

200 ms

内存限制

64 MB

参考代码:C++(g++)

#include 
using namespace std;
struct user{string name;int num;int sum;double ave;
} s[105]; //name:用户名 num:点赞的不同标签的数量 sum:点赞总数 ave:标签出现次数平均值
bool cmp(user a, user b){if (a.num==b.num)return a.ave>b.ave;return a.num>b.num;
}
int main(){int n;cin>>n;for(int i=0;imp;cin>>s[i].name>>s[i].sum;for (int j=0;j>x;mp[x]++;}s[i].num=mp.size();s[i].ave=1.0*s[i].num/s[i].sum;}sort(s,s+n,cmp);if(n==1)cout<

7-4 插入排序还是归并排序

作者 陈越

单位 浙江大学

根据维基百科的定义:

插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。

归并排序进行如下迭代操作:首先将原始序列看成 N 个只包含 1 个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下 1 个有序的序列。

现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?

输入格式:

输入在第一行给出正整数 N (≤100);随后一行给出原始序列的 N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。

输出格式:

首先在第 1 行中输出Insertion Sort表示插入排序、或Merge Sort表示归并排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。

输入样例 1:

10

3 1 2 8 7 5 9 4 6 0

1 2 3 7 8 5 9 4 6 0

输出样例 1:

Insertion Sort

1 2 3 5 7 8 9 4 6 0

输入样例 2:

10

3 1 2 8 7 5 9 4 0 6

1 3 2 8 5 7 4 9 0 6

输出样例 2:

Merge Sort

1 2 3 8 4 5 7 9 0 6

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

参考代码:C++(g++)

#include 
using namespace std;
int main(){int n,pos,i,j,range=2,a[105],b[105];cin>>n;for(i=0;i>a[i];for(i=0;i>b[i];for(i=1;i

7-5 插入排序还是堆排序

作者 陈越

单位 浙江大学

根据维基百科的定义:

插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。

堆排序也是将输入分为有序和无序两部分,迭代地从无序部分找出最大元素放入有序部分。它利用了大根堆的堆顶元素最大这一特征,使得在当前无序区中选取最大元素变得简单。

现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?

输入格式:

输入在第一行给出正整数 N (≤100);随后一行给出原始序列的 N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。

输出格式:

首先在第 1 行中输出Insertion Sort表示插入排序、或Heap Sort表示堆排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。

输入样例 1:

10

3 1 2 8 7 5 9 4 6 0

1 2 3 7 8 5 9 4 6 0

输出样例 1:

Insertion Sort

1 2 3 5 7 8 9 4 6 0

输入样例 2:

10

3 1 2 8 7 5 9 4 6 0

6 4 5 1 0 3 2 7 8 9

输出样例 2:

Heap Sort

5 4 3 1 0 2 6 7 8 9

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

参考代码C++(g++)

#include
using namespace std;
int main(){int array[128],answer[128],i,number,r;scanf("%d",&number);for(i=1;i<=number;i++)scanf("%d",array+i);for(i=1;i<=number;i++)scanf("%d",answer+i);for(i=2;ianswer[1])break;answer[0]=answer[i-1];answer[i-1]=answer[1];for(r=2;ranswer[r]&&r+11)cout<<" ";cout<

7-6 逆序对

作者 c++课程组

单位 湖州师范学院

求逆序对。

输入格式:

第一行是一个整数n,(n<=1000,000)表示输入序列的长度,接下来一行是n个整数(每个数的绝对值小于109)。

输出格式:

一个数,表示逆序对个数(逆序即任意一对数前面的数比后面的数大即为一对逆序对)。

输入样例:

10

1 3 5 7 9 8 4 2 6 10

输出样例:

逆序对对数可能很大,计数器要用long long:

14

说明:样例中如1和3不是逆序对,而3和2是1对逆序对,例子中共有14对逆序对。题目中可能有某些数字出现多次的情况。

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

参考代码C(gcc)

#include 
#define N 1000000
int n,a[N],b[N];
long long  cnt=0;
void f(int L,int R){if(L==R) return;int m=(L+R)/2;int k1=L,k2=m+1,k=L;f(L,m);f(m+1,R);while(k1<=m&&k2<=R){if(a[k1]<=a[k2]){b[k]=a[k1];k++,k1++;}else{b[k]=a[k2];k++,k2++;cnt=cnt+m-k1+1;}}while(k1<=m){b[k]=a[k1];k++,k1++;}while(k2<=R){b[k]=a[k2];k++,k2++;}for(int i=L;i<=R;i++)a[i]=b[i];
}
int main(){int i ;scanf("%d",&n);for(i=1;i<=n;i++)scanf("%d",&a[i]);f(1,n);printf("%lld",cnt);return 0;
}

7-7 堆排序

作者 黄龙军

单位 绍兴文理学院

给定一个整数序列,请按非递减序输出采用堆排序的各趟排序后的结果。

输入格式:

测试数据有多组,处理到文件尾。每组测试数据第一行输入一个整数n(1≤n≤100),第二行输入n个整数。

输出格式:

对于每组测试,输出若干行,每行是一趟排序后的结果,每行的每两个数据之间留一个空格。

输入样例:

4

8 7 2 1

输出样例:

7 1 2 8

2 1 7 8

1 2 7 8

来源:

[1] 黄龙军, 等. 数据结构与算法, 上海:上海交通大学出版社, 2022.7. ISBN: 9787313269881
[2] 黄龙军, 等. 数据结构与算法(Python版), 上海: 上海交通大学出版社, 2023. (In Press)

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

参考代码:C++(g++)

#include

using namespace std;

int a[105], n;

void print(){

    cout<

    for (int i=2;i<=n;i++)

        cout<<" "<

    cout<

}

void sift(int k, int end){

    int i=k,j=2*i;

    while(j<=end){

        if(j

        if(a[i]

        i=j;

        j=2*i;

    }

}

void heapsort(int n){

    for(int k=n/2;k>=1;k--)

        sift(k,n);

    for(int k=1;k

        swap(a[1],a[n-k+1]);

        sift(1,n-k);

        print();

    }

}

int main(){

    while (~scanf("%d", &n)){

        for (int i = 1; i <= n; i++)

            scanf("%d", &a[i]);

        heapsort(n);

    }

}

7-8 石子合并

作者 杜祥军

单位 青岛大学

由n堆石子排成一排,其编号为1,2,3……,n。每堆石子有一定的质量mi(mi<=1000),现在要将这n堆石子合并成一堆。每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻,由于合并顺序的不同,导致合并成一堆石子的总代价也不同,请求出最少的代价将所有石子合并为一堆。

输入格式:

第一行输入n。
第二行输入n个mi。

输出格式:

输出一个整数,表示石子合并的最小代价。

输入样例:

4

2 5 3 1

输出样例:

22

代码长度限制

16 KB

时间限制

1000 ms

内存限制

64 MB

参考代码:C++(g++)

#include
using namespace std;
const int INF = 100000;
const int N = 205;
int Min[N][N], Max[N][N], s[N][N];//求最小、最大值
int sum[N];//计算前i堆石子的数量总和,sum[0]=0,w(i,j)=sum[j]-sum[i-1]
int a[N];//记录各堆石子的数量
int minn, maxx;
void get_Min(int n) {for (int v = 2; v <= n; v++) {//枚举合并的堆数规模for (int i = 1; i <= n - v + 1; i++) {int j = i + v - 1;int tmp = sum[j] - sum[i - 1];int i1 = s[i][j - 1] > i ? s[i][j - 1] : i;int j1 = s[i + 1][j] < j ? s[i + 1][j] : j;Min[i][j] = Min[i][i1] + Min[i1 + 1][j];s[i][j] = i1;for (int k = i1 + 1; k <= j1; k++) {if (Min[i][k] + Min[k + 1][j] < Min[i][j]) {Min[i][j] = Min[i][k] + Min[k + 1][j];s[i][j] = k;}}Min[i][j] += tmp;}}
}
void straight(int a[], int n) {for (int i = 1; i <= n; i++) {//初始化Min[i][i] = 0, Max[i][i] = 0, s[i][i] = 0;}sum[0] = 0;for (int i = 1; i <= n; i++) {sum[i] = sum[i - 1] + a[i];}get_Min(n);
}
int main(){int n;cin >> n;for (int i = 1; i <= n; i++){cin >> a[i];}straight(a, n);cout << Min[1][n];return 0;
}

7-9 第k小

作者 严华云

单位 湖州师范学院

有n个数,求第k小的数。例如在数:{1 3 5 7 9 8 4 2 6 10}中,第3小的数是3 。

输入格式:

第一行输入两个数,n和k(n<=1000000),分别表示总的n个数和求第k小的数。第二行输入n个数( 最大数<10^7)。

输出格式:

一个数,表示第k小的数。

输入样例:

在这里给出一组输入。例如:

10 3

1 3 5 7 9 8 4 2 6 10

输出样例:

在这里给出相应的输出。例如:

3

代码长度限制

16 KB

时间限制

300 ms

内存限制

64 MB

参考代码:c++(g++)

#include 
using namespace std;
int a[1000005];
int main(){int n,k;while(~scanf("%d %d",&n,&k)){for (int i=0;i

7-10 快速排序的过程

作者 张志梅

单位 青岛大学

给定n个整型元素,利用快速排序算法对其进行非递减排序,请输出每一趟Partition的结果。每次选择所处理的区间的第一个元素作为基准元素。

输入格式:

输入为两行,第一行为一个整数n(1

输出格式:

输出为若干行,每行依次输出Partition后的结果,每个元素后一个空格。

输入样例:

5

4 5 3 2 1

输出样例:

2 1 3 4 5

1 2 3 4 5

1 2 3 4 5

1 2 3 4 5

1 2 3 4 5

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

参考代码:C++(g++)

#include 
using namespace std;
int n;
void print(int *arr){for(int i=0;i right)return;  //首先判断一下传递进来的left和right合不合理int i = left,j = right;    //把left和right赋值给i,j作为他们的初始状态int pivot = arr[left];  //让最左边的元素作为支点pivot//不是0开始,要递归调用,比如pivot右边的子数组初始下标就不是0,所以不是arr[0]while (i < j){  //i与j碰到时,结束一次排序,所以i= pivot && i < j)j--;  //j(R)要找的是小于pivot的数,所以当arr[j]>=pivot时,此数不用操作,j向左移动(别忘了i>n;int arr[n]; for(int i=0;i

相关内容