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;
}