PTA 数据结构与算法A实验八排序

7-1 统计工龄 (20 分)
给定公司N名员工的工龄,要求按工龄增序输出每个工龄段有多少员工。

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

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

输入样例:
8
10 2 0 5 7 2 5 2
结尾无空行
输出样例:
0:1
2:3
5:2
7:1
10:1

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 52
int main()
{
	int i,n;
	scanf("%d",&n);
	static int a[N];
	int x;
	for(i=0;i<n;i++)
	{
		scanf("%d",&x);
		a[x]++;
	}
	for(i=0;i<=N;i++)
	{
		if(a[i]!=0)
		{
			printf("%d:%d\n",i,a[i]);
		}
	}
	return 0;
}

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

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

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

输入样例:
8 3
8 12 7 3 20 9 5 18
结尾无空行
输出样例:
20 18 12
结尾无空行

#include <stdio.h>
int main()
{
    long int n,m;
    long int i,j,t;
    scanf("%ld%ld",&n,&m);
    if(n<m)
    {
        m=n;
    }
    long int a[n]; 
    for(i=0;i<n;i++)
    {
        scanf("%ld",&a[i]);
    }
    for(i=0;i<m;i++)
    {
        for(j=n-1;j>i;j--)
        {
            if(a[j]>a[j-1])
            {
                t=a[j];
                a[j]=a[j-1];
                a[j-1]=t;
            }
        }
    }
    for(i=0;i<m-1;i++)
    {
       printf("%ld ",a[i]);
    }
    printf("%ld",a[m-1]);
    return 0;
}

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

输入格式:
输入在第一行给出一个正整数N(≤100),是待统计的用户数。随后N行,每行列出一位用户的点赞标签。格式为“Name K F 1 ⋯F K ”,其中Name是不超过8个英文小写字母的非空用户名,1≤K≤1000,F i(i=1,⋯,K)是特性标签的编号,我们将所有特性标签从 1 到 10 7编号。数字间以空格分隔。
输出格式:
统计每个人点赞的不同标签的数量,找出数量最大的前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
结尾无空行

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct node{
	char name[11];
	int *expression;
	int count;
	int k;
}node;
node Like[101];
int main()
{
	int i,j,n,num,k,label;
	node snap;
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		scanf("%s %d",Like[i].name,&Like[i].k);
		Like[i].expression=(int *)malloc(sizeof(int)*Like[i].k);
		if(Like[i].expression==NULL)
			return -1;
		for(j=0;j<Like[i].k;j++)
		{
			scanf("%d",&num);
			label=0;
			for(k=0;k<Like[i].count;k++)
			{
				if(Like[i].expression[k]==num)
				{
					label++;
					break;
				}
			}
			if(!label)
			{
				Like[i].count++;
				Like[i].expression[k]=num;
			}
			label=0;
		}
	}
	for(i=0;i<n;i++){
		for(j=1;j<n-i;j++){
			if(Like[j-1].count<=Like[j].count){
				if(Like[j-1].count==Like[j].count){
					int num=Like[j-1].k>Like[j].k?j:j-1;
					snap=Like[num];
					Like[num]=Like[(num==j?j-1:j)];
					Like[(num==j?j-1:j)]=snap;
				}
				else{
					snap=Like[j-1];
					Like[j-1]=Like[j];
					Like[j]=snap;
				}
			}
		}
	}
	for(i=0;i<3;i++)
	{
		if(i>=n)
			printf(" -");
		else
		{
			if(i==0)
				printf("%s",Like[i].name);
			else
				printf(" %s",Like[i].name);
		}
	}
	return 0;
}

7-4 插入排序还是归并排序 (25 分)
根据维基百科的定义:

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

归并排序进行如下迭代操作:首先将原始序列看成 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
结尾无空行

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n, pos, i, j, range = 2;
    int a[105], b[105];
    cin >> n;
    for (i = 0; i < n; i++)
        scanf("%d", &a[i]);
    for (i = 0; i < n; i++)
        scanf("%d", &b[i]);
    for (i = 1; i < n; i++)
    {
        if (b[i] < b[i - 1])
            break;
    }
    for (j = i; j < n; j++)
    {
        if (a[j] != b[j])
            break;
    }
    if (j == n)
    {
        printf("Insertion Sort\n");
        sort(b, b + i + 1);
    }
    else
    {
        printf("Merge Sort\n");
        while (1)
        {
            for (i = 0; i < n / range; i++)
                sort(a + i * range, a + (i + 1) * range);
            sort(a + i * range, a + n);
            for (i = 0; i < n; i++)
            {
                if (a[i] != b[i])
                    break;
            }
            if (i == n)
            {
                range *= 2;
                for (i = 0; i < n / range; i++)
                    sort(b + i * range, b + (i + 1) * range);
                sort(b + i * range, b + n);
                break;
            }
            range *= 2;
        }
    }
    printf("%d", b[0]);
    for (int i = 1; i < n; i++)
        printf(" %d", b[i]);
    printf("\n");
    return 0;
}

7-5 逆序对 (15 分)
给定一个长度为n的整数数列,请你计算数列中的逆序对的数量。

逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i < j 且 a[i] > a[j],则其为一个逆序对;否则不是。

输入格式:
第一行包含整数n,表示数列的长度;第二行包含 n 个整数,表示整个数列。(1≤n≤100000)

输出格式:
输出一个整数,表示逆序对的个数。

输入样例:
6
2 3 4 5 6 1
结尾无空行
输出样例:
5
结尾无空行

#include <stdio.h>
#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 堆排序 (10 分)
给定一个整数序列,请按非递减序输出采用堆排序的各趟排序后的结果。

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

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

输入样例:
4
8 7 2 1
输出样例:
7 1 2 8
2 1 7 8
1 2 7 8

#include <stdio.h>
#include <stdlib.h>
int a[105], n;
void swap(int k[],int i,int j)
{
	int temp=k[i];
	k[i]=k[j];
	k[j]=temp;
}
void print()
{
    printf("%d", a[1]);
    for (int i = 2; i <= n; i++)
        printf(" %d", a[i]);
    printf("\n");
}
void sift(int k, int end)
{
    int i = k, j = 2 * i;
    while (j <= end)
    {
        if (j < end && a[j] < a[j + 1])
            j++;
        if (a[i] < a[j])
            swap(a,i,j);
        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 < n; k++)
    {
        swap(a,1,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);
    }
    return 0;
}

7-8 快速排序 (10 分)
给定一个整数序列,请按非递减序输出采用快速排序(递归法)的各趟排序后的结果。注意:每趟排序以排序区间的首元素为枢轴(支点)。

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

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

输入样例:
4
8 7 2 1
输出样例:
1 7 2 8
1 7 2 8
1 2 7 8

#include <stdio.h>
#include <stdlib.h>
void swap(int k[],int i,int j)
{
	int temp=k[i];
	k[i]=k[j];
	k[j]=temp;
}
int n;
int a[105];

void print()
{
    for (int i = 0; i < n; i++)
    {
        printf("%d", a[i]);
        if (i == n - 1)
            printf("\n");
        else
            printf(" ");
    }
}

int cut(int l, int r)
{
    int i, j, t;
    i = l;
    j = r;
    while (i < j)
    {
        while (i < j && a[i] <= a[j])
            j--;
        if (i < j)
        {
            swap(a,i,j);
            i++;
        }
        while (i < j && a[i] <= a[j])
            i++;
        if (i < j)
        {
            swap(a,i,j);
            j--;
        }
    }
    return i;
}

void quicksort(int l, int r)
{
    int k;
    if (l < r)
    {
        k = cut(l, r);
        print();
        quicksort(l, k - 1);
        quicksort(k + 1, r);
    }
}

int main()
{
    while (~scanf("%d", &n))
    {
        for (int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        quicksort(0, n - 1);
    }
    return 0;
}

7-9 归并排序 (20 分)
知识点:归并排序

给定你一个长度为 n 的整数数列。

请你使用归并排序对这个数列按照从小到大进行排序。

并将排好序的数列按顺序输出。

输入格式:
输入共两行,第一行包含整数 n(1≤n≤100000)。

第二行包含 n 个整数(所有整数均在 1∼10^9 范围内),表示整个数列。

输出格式:
输出共一行,包含 n 个整数,表示排好序的数列。

输入样例:
5
3 1 2 4 5
结尾无空行
输出样例:
1 2 3 4 5
结尾无空行

#include<stdio.h>
#include<stdio.h>

void merge(int num1[],int num2[],int start,int mid,int end )
{
    int i=start,j=mid+1,k=start;
    while(i!=mid+1 && j!=end+1)
    {
        if(num1[i]>=num1[j])
            num2[k++]=num1[j++];
        else 
            num2[k++]=num1[i++];
    }
    while(i!=mid+1)
    {
        num2[k++]=num1[i++];
    }
     while(j!=end+1)
    {
        num2[k++]=num1[j++];
    }
    
    for(i=start; i<=end; i++)
        num1[i] = num2[i];
}

void mergeSort(int num1[],int num2[],int start,int end)
{
    int mid;
    if(start<end)
    {
        mid=(start+end)/2;
        mergeSort( num1, num2, start, mid);
        mergeSort( num1, num2,mid+1, end);
        merge(num1,num2,start,mid,end);
    }
}

int main()
{ 
	int i,n;
    scanf("%d",&n);
    int num1[n];
    int num2[n];
   for(i=0; i<n; i++)
   {
   	 scanf("%d", &num1[i]);
   }
    mergeSort(num1,num2,0,n-1 );
    for(i=0; i<n; i++)
        printf("%d ", num1[i]);
    printf("\n");
    return 0;
}

7-10 逆序对的数量 (20 分)
知识点:归并排序

给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。

逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。

输入格式:
第一行包含整数 n(1≤n≤100000),表示数列的长度。

第二行包含 n 个整数,表示整个数列,数列中的元素的取值范围 [1~10^9]。

输出格式:
请在这里描述输出格式。例如:对每一组输入,在一行中输出A+B的值。

输入样例:
6
2 3 4 5 6 1
结尾无空行
输出样例:
5
作者 陆泓宇
单位 韩山师范学院
代码长度限制 16 KB
时间限制 1000 ms
内存限制 64MB

#include <stdio.h>
#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-11 寻找第k小的数 (10 分)
给定若干整数,请设计一个高效的算法,确定第k小的数。

输入格式:
测试数据有多组,处理到文件尾。每组测试数据的第1行输入2个整数n,k(1≤k≤n≤1000000)。第2行输入n个整数,每个数据的取值范围在0到1000000之间。

输出格式:
对于每组测试,输出第k小的数。

输入样例:
5 3
1 2 2 2 1
9 3
1 2 3 4 5 6 9 8 7
输出样例:
2
3
提示:
如果提交后超时,请注意需要设计的是高效的算法!如果你初学《数据结构》,暂时设计不出来,请学完相关知识再回头来做。 也可以使用STL之sort、nth_element函数求解。 另外,由于输入数据特别多,为减少输入数据的耗时,建议使用以下的输入外挂函数:

void scan_d(int &num)
{
char in;
in=getchar();
while(in<‘0’||in>‘9’) in=getchar();
num=in-‘0’;
while(in=getchar(),in>=‘0’&&in<=‘9’){num*=10,num+=in-‘0’;}
}
调用方法如下:

int n;
scan_d(n);
作者 usx程序设计类课程组
单位 绍兴文理学院
代码长度限制 16 KB
时间限制 400 ms
内存限制 64MB

#include <stdio.h>
#include <stdlib.h>
int a[1000005];
int cmp(const void *a,const void *b)
{
	return *(int*)a-*(int*)b;
}
int main()
{
    int n, k;
    while (~scanf("%d %d", &n, &k))
    {
        for (int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        qsort(a,n,sizeof(int),cmp);
        printf("%d\n", a[k - 1]);
    }
    return 0;
}
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值