PTA 21级数据结构与算法实验8—排序
7-1 统计工龄
代码 :
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[N], d[110];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
for (int i = 0; i < n; i++) d[a[i]] ++;
for (int i = 0; i <= 50; i++) {
if (d[i]) printf("%d:%d\n", i, d[i]);
}
return 0;
}
7-2 寻找大富翁
代码 :
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int a[N];
// 快排
void qsort(int l, int r){
if (l >= r) return;
int i = l - 1, j = r + 1;
int x = a[l + r >> 1];
while (i < j){
do i++; while (a[i] > x);
do j--; while (a[j] < x);
if (i < j) swap(a[i], a[j]);
}
qsort(l, j);
qsort(j + 1, r);
}
int main() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
qsort(1, n);
// m 有可能小于 n, 取个最小值
for (int i = 1; i <= min(m, n); i++) {
if (i == 1) printf("%d", a[i]);
else printf(" %d", a[i]);
}
return 0;
}
7-3 点赞狂魔
题意 :
给 N 个用户, 每个用户有个 Name 和 K 个特性编号 Fi ; 找出每个人点赞不同编号的数量, 并输出数量最大的前三名; 如果有并列, 就输出标签出现次数平均值最小的那个, 若不足3人,则用-补齐缺失
代码:
#include <bits/stdc++.h>
using namespace std;
struct Node {
char name[10];
int cnt, k; // cnt 存不同标签数量, k 存所有标签数量
} p[110];
set<int> s; // set 去重
// 排序规则
bool cmp(Node a, Node b) {
if (a.cnt != b.cnt) return a.cnt > b.cnt;
return a.k < b.k;
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> p[i].name >> p[i].k;
s.clear();
int x;
for (int j = 0; j < p[i].k; j++) {
scanf("%d", &x);
s.insert(x);
}
p[i].cnt = s.size();
}
// 根据题目规则排序
sort(p + 1, p + n + 1, cmp);
if (n == 0) printf("- - -\n");
else if (n == 1) printf("%s - -\n", p[1].name);
else if (n == 2) printf("%s %s -\n", p[1].name, p[2].name);
else printf("%s %s %s\n", p[1].name, p[2].name, p[3].name);
return 0;
}
7-4 插入排序还是归并排序
题意:
给出两个长度为 N 的序列, 第一行代表初始状态, 第二行代表插入排序 (归并排序) 的中间序列; 判断是用的插入排序还是归并排序, 并输出用该排序算法再迭代一轮的结果序列
思路 :
对于插入排序, 因为每次都是从序列头中拿出一个, 插入到排好的序列中, 所以对于一个长度为 n 的序列, 如果是插入排序, 前 k 个数应该是排好序的, 而后 n - k 个数中 a[i] == b[i], 这样就能找到 k, 并排序前 k + 1 的长度
对于归并排序, 因为它每次都是取半递归排序, 所以要找到最小的已经排好序的子段长度 len, 然后再按照 2 * len 的子段长度归并排序
代码参考博客地址: 博客园 kingwzun
代码 :
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int a[N], b[N];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n; i++) cin >> b[i];
// 先判断是不是插入排序
int flag = 0;
int k = 0;
for (int i = 1; i < n; i++) {
if (flag == 0 && b[i] < b[i - 1]) k = i, flag = 1; // 看前面排好序的递增序列
// 如果 k 到 n 间 a[i], b[i] 不全相等, 说明不是插入排序
if (flag == 1 && b[i] != a[i]) {
flag = 2;
break;
}
}
if (flag == 1) {
cout << "Insertion Sort" << endl;
sort(a, a + k + 1);
for (int i = 0; i < n; i++) {
if (i) cout << " " << a[i];
else cout << a[i];
}
} else {
cout << "Merge Sort" << endl;
// 找到最小的排好序的子段
int len = 0x3f3f3f3f;
int cnt = 1;
for (int i = 0; i < n - 1; i ++) {
if (b[i] < b[i + 1]) cnt++;
else len = min(len, cnt), cnt = 1;
}
len *= 2;
for (int i = 0; i < n; i += len)
sort(a + i, a + min(i + len, n)); // 这里和 n 取min值, 防止越界
for (int i = 0; i < n; i++) {
if (i) cout << " " << a[i];
else cout << a[i];
}
}
return 0;
}
7-5 插入排序还是堆排序
题意:
同 7-4, 判断是插入排序还是堆排序, 并输出用该排序算法再迭代一轮的结果序列
思路
插入排序同 7-4, 或者因为数据很小, 可以每次都排序判断
对于堆排序, 题目是从长度为 n 开始, 每次对前 k 个序列取大根堆, 并将长度为 k 的序列里的第一个和最后一个交换, 直到 k == 0; 完整的一步迭代是 : 形成前 k 个数的大根堆, 并 swap(a[1], a[k]), 并且形成前 k - 1 个数的大根堆
代码参考博客地址 : CSDN 摺耳喵
代码 1 :
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int a[N], b[N], tmp[N];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n; i++) cin >> b[i];
memcpy(tmp, a, sizeof (tmp));
bool flag = 0;
// 这里 i 一定要从 2 开始, 不然会被卡
for (int i = 2; i <= n; i++) {
sort(a, a + i);
if (flag) {
cout << "Insertion Sort" << endl;
for (int j = 0; j < n; j++) {
if (j) cout << " " << a[j];
else cout << a[j];
}
break;
}
if (equal(a, a + n, b)) flag = 1;
}
if (!flag) {
memcpy(a, tmp, sizeof (a));
for (int i = n; i >= 1; i--) {
make_heap(a, a + i);
if (flag) {
cout << "Heap Sort" << endl;
for (int j = 0; j < n; j++) {
if (j) cout << " " << a[j];
else cout << a[j];
}
break;
}
if (equal(a, a + n, b)) flag = 1;
swap(a[0], a[i - 1]);
}
}
return 0;
}
代码 2 : 手写堆排序实现
// 注意 : 这里数组的下标是从 1 开始的
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int a[N], b[N], tmp[N];
int len;
// 大根堆
void down(int u) {
int t = u;
if (u * 2 <= len && a[t] < a[u * 2]) t = u * 2;
if (u * 2 + 1 <= len && a[t] < a[u * 2 + 1]) t = u * 2 + 1;
if (u != t) {
swap(a[t], a[u]);
down(t);
}
}
void init() {
for (int i = len / 2; i; i--) down(i);
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) cin >> b[i];
memcpy(tmp, a, sizeof (a));
bool flag = 0;
for (int i = 2; i <= n; i++) {
sort(a + 1, a + i + 1);
if (flag) {
cout << "Insertion Sort" << endl;
for (int j = 1; j <= n; j++) {
if (j != 1) cout << " " << a[j];
else cout << a[j];
}
break;
}
if (equal(a, a + n, b)) flag = 1;
}
if (!flag) {
memcpy(a, tmp, sizeof (a));
flag = 0;
for (int i = n; i >= 1; i--) {
len = i;
init();
if (flag) {
cout << "Heap Sort" << endl;
for (int j = 1; j <= n; j++) {
if (j != 1) cout << " " << a[j];
else cout << a[j];
}
break;
}
if (equal(a, a + n, b)) flag = 1;
swap(a[1], a[i]);
}
}
return 0;
}
7-6 逆序对
思路 : 归并排序 求 逆序对
代码 :
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int a[N], tmp[N];
long long int sum = 0;
// 归并排序
void merge_sort(int l, int r) {
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(l, mid), merge_sort(mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r) {
if (a[i] <= a[j]) tmp[k++] = a[i++];
else // 这里 a[i] > a[j] 就说明 a[i] 到 a[mid] 间的数都大于 a[j] 并形成逆序对
tmp[k++] = a[j++], sum += mid - i + 1;
}
while (i <= mid) tmp[k++] = a[i++];
while (j <= r) tmp[k++] = a[j++];
for (int i = l, j = 0; i <= r; i++, j++) a[i] = tmp[j];
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
merge_sort(1, n);
cout << sum << endl;
return 0;
}
7-7 堆排序
代码 :
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int h[N], len;
// 这里是大根堆
void down(int u) {
int t = u;
if (u * 2 <= len && h[t] < h[u * 2]) t = u * 2;
if (u * 2 + 1 <= len && h[t] < h[u * 2 + 1]) t = u * 2 + 1;
if (t != u) {
swap(h[t], h[u]);
down(t);
}
}
void init() {
for (int i = len / 2; i; i--) down(i);
}
int main() {
int n;
while (cin >> n) {
for (int i = 1; i <= n; i++) cin >> h[i];
len = n;
init();
for (int i = n; i > 1; i--) {
swap(h[1], h[i]);
len = i - 1;
down(1);
for (int j = 1; j <= n; j++) {
if (j == 1)
printf("%d", h[j]);
else
printf(" %d", h[j]);
}
printf("\n");
}
}
return 0;
}
7-8 石子合并
代码参考博客地址 :
CSDN ACdreamers
星辰阁
代码 :
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int a[N], d[N];
int dp[N][N];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
d[i] = d[i - 1] + a[i];
}
for (int h = 1; h <= n; h++) {
for (int i = 1; i <= n; i++) {
int j = i + h;
if (j > n) continue;
dp[i][j] = 0x3f3f3f3f;
for (int k = i; k <= j; k++) {
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
}
dp[i][j] += d[j] - d[i - 1];
}
}
cout << dp[1][n] << endl;
return 0;
}
7-9 第k小
代码参考地址 : acwing
代码1 : 快排实现
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int a[N];
int quick_sort(int l, int r, int k) {
if (l >= r) return a[k];
int x = a[(l + r) >> 1], i = l - 1, j = r + 1;
while (i < j) {
do i++; while (a[i] < x);
do j--; while (a[j] > x);
if (i < j) swap(a[i], a[j]);
}
if (k <= j) quick_sort(l, j, k);
else quick_sort(j + 1, r, k);
}
int main() {
int n, k;
scanf("%d %d", &n, &k);
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
cout << quick_sort(0, n - 1, k - 1) << endl;
return 0;
}
代码2 : 堆排序实现
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int h[N], len;
// 小根堆
void down(int u) {
int t = u;
if (u * 2 <= len && h[t] > h[u * 2]) t = u * 2;
if (u * 2 + 1 <= len && h[t] > h[u * 2 + 1]) t = u * 2 + 1;
if (u != t) {
swap(h[u], h[t]);
down(t);
}
}
void init() {
for (int i = len / 2; i; i--) down(i);
}
int main() {
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++) scanf("%d", &h[i]);
len = n;
init();
for (int i = 1; i < k; i++) {
swap(h[1], h[len]);
len--;
down(1);
}
cout << h[1] << endl;
return 0;
}
7-10 快速排序的过程
代码 : 快速排序的模板很多, 但是这道题好像只能用这个模板 ( 不是很确定 )
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int a[N];
int n;
void quick_sort(int l, int r) {
if (l > r) return;
int x = a[l], i = l, j = r;
while (i < j) {
while (i < j && a[j] >= x) j--;
while (i < j && a[i] <= x) i++;
if (i < j) swap(a[i], a[j]);
}
swap(a[l], a[j]);
for (int k = 1; k <= n; k++) {
cout << a[k] << " ";
}
cout << endl;
quick_sort(l, j - 1);
quick_sort(j + 1, r);
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
quick_sort(1, n);
return 0;
}
PTA 21级数据结构与算法实验8—排序的更多相关文章
- 数据结构与算法实验题 6.1 s_sin’s bonus
数据结构与算法实验题 6.1 s_sin's bonus ★实验任务 正如你所知道的 s_sin 是一个非常贪玩的人 QAQ(如果你非常讨厌他请直接从第二段开 始看),并且令人感到非常遗憾的是,他是一 ...
- 数据结构与算法实验题 9.1 K 歌 DFS+剪枝
数据结构与算法实验题 K 歌 ★实验任务 3* n 个人(标号1~ 3 * n )分成 n 组 K 歌.有 m 个 3 人组合,每个组合都对应一个分数,你能算出最大能够得到的总分数么? ★数据输入 输 ...
- 数据结构与算法实验题 4.2 Who is the strongest
数据结构与算法实验题 4.2 Who is the strongest ★实验任务 在神奇的魔法世界,召唤师召唤了一群的魁偶.这些魁偶排成一排,每个魁偶都有一个 战斗值.现在该召唤师有一个技能,该技能 ...
- HDU 3791 二叉搜索树 (数据结构与算法实验题 10.2 小明) BST
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=3791 中文题不说题意. 建立完二叉搜索树后进行前序遍历或者后序遍历判断是否一样就可以了. 跟这次的作业第 ...
- Java数据结构和算法(五)--希尔排序和快速排序
在前面复习了三个简单排序Java数据结构和算法(三)--三大排序--冒泡.选择.插入排序,属于算法的基础,但是效率是偏低的,所以现在 学习高级排序 插入排序存在的问题: 插入排序在逻辑把数据分为两部分 ...
- 数据结构与算法之--高级排序:shell排序和快速排序
高级排序比简单排序要快的多,简单排序的时间复杂度是O(N^2),希尔(shell)排序大约是O(N*(logN)^2),而快速排序是O(N*logN). 说明:下面以int数组的从小到大排序为例. 希 ...
- 数据结构与算法之PHP排序算法(堆排序)
一.堆的定义 堆通常是一个可以被看做一棵树的数组对象,其任一非叶节点满足以下性质: 1)堆中某个节点的值总是不大于或不小于其父节点的值: 每个节点的值都大于或等于其左右子节点的值,称为大顶堆.即:ar ...
- Java数据结构和算法(三)--三大排序--冒泡、选择、插入排序
三大排序在我们刚开始学习编程的时候就接触过,也是刚开始工作笔试会遇到的,后续也会学习希尔.快速排序,这里顺便复习一下 冒泡排序: 步骤: 1.从首位开始,比较首位和右边的索引 2.如果当前位置比右边的 ...
- 数据结构与算法之PHP排序算法(希尔排序)
一.基本思想 希尔排序算法是希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本. 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接 ...
- 数据结构与算法实验题6.1 s_sin’s bonus byFZuer
玩家从n 个点n-1 条边的图,从节点1 丢下一个小球,小球将由于重力作用向下落,而从小球所在点延伸出的每一条边有一个值pi 为小球通过该条边的概率(注意从同一个节点向下延伸的所有边的pi 的和可以小 ...
随机推荐
- 简单的了解下 Fetch API 的工作原理
一.简介 Fetch API是一种现代的Web API,提供了一种异步获取网络资源的方法.由于其简单性.灵活性和一致性,它已经成为Web应用程序中获取数据和资源的流行选择.在本文中,我们将深入探讨Fe ...
- Semantic Kernel 入门系列:📅 Planner 计划管理
Semantic Kernel 的一个核心能力就是实现"目标导向"的AI应用. 目标导向 "目标导向"听起来是一个比较高大的词,但是却是实际生活中我们处理问题的 ...
- GraphQL渗透测试详解
GraphQL介绍 GraphQL概述 GraphQL 是一种查询语言,用于 API 设计和数据交互.它是由 Facebook 发布的一款新型的数据查询和操作语言,自 2012 年起在内部使用,自 2 ...
- MySQL相关操作(实用函数和sql语法)
1.时间函数 当前时间 select current_timestamp(); 当前时间戳 select UNIX_TIMESTAMP(NOW()); 当前时间戳精确到毫秒 select REPLAC ...
- Python_13 接口测试openpyxl和表操作
一.openpyxl 安装 pip install openpyxl 在Terminal中输入 excel操作步骤 找到目标excel 打开 读取数据.编辑excel单元格 保存 关闭 open ...
- Consistency Models终结扩散模型
最近看到一篇论文,觉得特别有意思,并且在学术界引起了不小的动静,他就是一致性模型,据说图像生成效果快.质量高,并且还可以实现零样本图像编辑,即不进行一些视觉任务训练,可以实现图像超分.修复.上色等功能 ...
- Azure DevOps(二)Azure Pipeline 集成 SonarQube 维护代码质量和安全性
一,引言 对于今天所分析的 SonarQube,首先我们得了解什么是 SonarQube ? SonarQube 又能帮我们做什么?我们是否在项目开发的过程中遇到人为 Review 代码审核规范?带着 ...
- Python OOP之继承封装多态
面向对象的三大特征 继承 封装 多态 继承 子类可以使用父类定义的内容或者行为 继承的实现 父类,基类,超类,被继承的类,Base Class,Super Class 子类:有继承行为的类 所有类都必 ...
- NC19427 换个角度思考
题目链接 题目 题目描述 给定一个序列,有多次询问,每次查询区间里小于等于某个数的元素的个数 即对于询问 \((l,r,x)\) ,你需要输出 \(\sum_{i=l}^{r}[a_i \le x]\ ...
- 【GiraKoo】夜神模拟器提示“当前设备未开启VT”
[解决]夜神模拟器提示"当前设备未开启VT" 环境 Windows 11 夜神模拟器64位 现象 启动夜神模拟器时,提示"检测到当前设备未开启VT,请先开启VT后再运行6 ...