Loading

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 个用户, 每个用户有个 NameK 个特性编号 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;
}
posted @ 2022-11-28 21:08  Oneway`  阅读(221)  评论(0编辑  收藏  举报