#C27. 华为OD机试统一考试D卷C卷 - 内存冷热标记

华为OD机试统一考试D卷C卷 - 内存冷热标记

题目链接

华为OD机试统一考试D卷C卷 - 内存冷热标记(C++ Java JavaScript Python)

https://blog.csdn.net/banxia_frontend/article/details/134699504

题目描述

现代计算机系统中通常存在多级的存储设备,针对海量 workload 的优化的一种思路是将热点内存页优先放到快速存储层级,这就需要对内存页进行冷热标记。

一种典型的方案是基于内存页的访问频次进行标记,如果统计窗口内访问次数大于等于设定阈值,则认为是热内存页,否则是冷内存页。

对于统计窗口内跟踪到的访存序列和阈值,现在需要实现基于频次的冷热标记。内存页使用页框号作为标识。

输入描述

第一行输入为 N,表示访存序列的记录条数,0 < N ≤ 10000

第二行为访存序列,空格分隔的 N 个内存页框号

第三行为阈值

输出描述

第一行输出标记为热内存的内存页个数,如果没有被标记的热内存页,则输出 0 。

如果第一行 > 0,则接下来按照访问频次降序输出内存页框号,一行一个,频次一样的页框号,页框号小的排前面。

用例1

输入 10
1 2 1 2 1 2 1 2 1 2
5
输出 2
1
2
说明 在这个例子中,内存页框号 1 和 2 都被访问了 5 次,达到了阈值,因此它们被标记为热内存页。输出首先是热内存页的数量 2,然后是按照访问频次降序排列的页框号 1 和 2(频次一样的页框号,页框号小的排前面)。

用例2

输入 5
1 2 3 4 5
3
输出 0
说明 在这个例子中,没有任何内存页的访问次数达到阈值 3,因此没有热内存页,输出为 0。

C++

#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <string>
#include <sstream>

using namespace std;
int main() {
    // 用于存储输入行的字符串
    string line;
    // 用于存储页面访问序列
    vector<int> pageAccessSequence;
    // 页面访问次数
    int pageAccessCount;
    // 热门页面的阈值
    int hotThreshold;

    // 读取页面访问次数
    getline(cin, line);
    pageAccessCount = stoi(line);

    // 读取页面访问序列
    getline(cin, line);
    istringstream iss(line);
    int page;
    while (iss >> page) {
        pageAccessSequence.push_back(page);
    }

    // 读取热门页面的阈值
    getline(cin, line);
    hotThreshold = stoi(line);

    // 统计每个页面的访问频率
    unordered_map<int, int> pageFrequency;
    for (int page : pageAccessSequence) {
        pageFrequency[page]++;
    }

    // 过滤出热门页面
    vector<int> hotPages;
    for (const auto& kv : pageFrequency) {
        if (kv.second >= hotThreshold) {
            hotPages.push_back(kv.first);
        }
    }

    // 输出热门页面的数量
    cout << hotPages.size() << endl;

    // 如果存在热门页面
    if (!hotPages.empty()) {
        // 对热门页面进行排序
        sort(hotPages.begin(), hotPages.end(), [&pageFrequency](int a, int b) {
            if (pageFrequency[a] == pageFrequency[b]) return a < b;
            return pageFrequency[a] > pageFrequency[b];
        });

        // 输出排序后的热门页面
        for (int page : hotPages) {
            cout << page << endl;
        }
    }

    return 0;
}

Java

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int N = Integer.parseInt(scanner.nextLine());
        String[] accesses = scanner.nextLine().split(" ");
        int threshold = Integer.parseInt(scanner.nextLine());
        scanner.close();

        // 使用 TreeMap 来存储内存页框号和对应的访问次数
        // TreeMap 默认按照 key 升序排列,这里我们需要按照访问次数降序,页框号升序排列
        Map<Integer, Integer> frequencyMap = new TreeMap<>();
        for (String access : accesses) {
            int pageFrame = Integer.parseInt(access);
            frequencyMap.put(pageFrame, frequencyMap.getOrDefault(pageFrame, 0) + 1);
        }

        // 使用 PriorityQueue 来对内存页框号进行排序
        PriorityQueue<Integer> hotPages = new PriorityQueue<>((a, b) -> {
            int freqCompare = frequencyMap.get(b).compareTo(frequencyMap.get(a));
            if (freqCompare == 0) {
                return a.compareTo(b);
            }
            return freqCompare;
        });

        // 将达到阈值的热内存页加入到优先队列中
        for (Map.Entry<Integer, Integer> entry : frequencyMap.entrySet()) {
            if (entry.getValue() >= threshold) {
                hotPages.offer(entry.getKey());
            }
        }

        // 输出结果
        int hotCount = hotPages.size();
        System.out.println(hotCount);
        while (!hotPages.isEmpty()) {
            System.out.println(hotPages.poll());
        }
    }
}

javaScript

// 引入 readline 模块用于读取命令行输入
const readline = require('readline');

// 创建 readline 接口实例
const rl = readline.createInterface({
  input: process.stdin, // 标准输入流
  output: process.stdout // 标准输出流
});

// 用于存储输入行的数组
let inputLines = [];

// 监听 'line' 事件,每次输入后触发
rl.on('line', (line) => {
  // 将输入的每一行添加到 inputLines 数组
  inputLines.push(line);
  // 当输入行数达到 3 行时,关闭 readline 接口
  if (inputLines.length === 3) {
    rl.close();
  }
}).on('close', () => {
  // 解析输入的第一行为页面访问次数
  const pageAccessCount = parseInt(inputLines[0].trim(), 10);
  // 解析输入的第二行为页面访问序列,转换为数字数组
  const pageAccessSequence = inputLines[1].trim().split(' ').map(Number);
  // 解析输入的第三行为热门页面的阈值
  const hotThreshold = parseInt(inputLines[2].trim(), 10);

  // 使用 reduce 方法统计每个页面的访问频率
  const pageFrequency = pageAccessSequence.reduce((acc, page) => {
    acc[page] = (acc[page] || 0) + 1; // 如果页面已存在则增加计数,否则初始化为 1
    return acc;
  }, {});

  // 根据阈值过滤出热门页面,并转换为数字数组
  const hotPages = Object.entries(pageFrequency)
    .filter(([page, freq]) => freq >= hotThreshold)
    .map(([page]) => parseInt(page, 10));

  // 输出热门页面的数量
  console.log(hotPages.length);

  // 如果存在热门页面
  if (hotPages.length > 0) {
    // 对热门页面进行排序,先按访问频率降序,频率相同则按页面号升序
    hotPages.sort((a, b) => {
      return pageFrequency[b] - pageFrequency[a] || a - b;
    });

    // 输出排序后的热门页面
    hotPages.forEach((page) => {
      console.log(page);
    });
  }

 
});

Python

# 获取输入
page_access_count = int(input().strip())
page_access_sequence = map(int, input().strip().split())
hot_threshold = int(input().strip())

# 统计内存页框号出现的次数
from collections import Counter
page_frequency = Counter(page_access_sequence)

# 确定热内存页
hot_pages = [page for page, freq in page_frequency.items() if freq >= hot_threshold]

# 输出热内存页数量
print(len(hot_pages))

# 如果存在热内存页,按照要求排序并输出
if hot_pages:
    hot_pages.sort(key=lambda page: (-page_frequency[page], page))
    for page in hot_pages:
        print(page)

C语言

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

#define MAX_NUM 10000

// 定义一个结构体,用于存储页面和对应的访问频率
typedef struct {
    int page;
    int frequency;
} PageFrequency;

// 定义一个比较函数,用于 qsort 函数
int cmp(const void *a, const void *b) {
    PageFrequency *pf1 = (PageFrequency *)a;
    PageFrequency *pf2 = (PageFrequency *)b;
    if (pf1->frequency == pf2->frequency)
        return pf1->page - pf2->page;
    return pf2->frequency - pf1->frequency;
}

int main() {
    // 页面访问次数
    int pageAccessCount;
    // 热门页面的阈值
    int hotThreshold;

    // 读取页面访问次数
    scanf("%d", &pageAccessCount);

    // 创建一个数组存储页面访问序列
    int pageAccessSequence[MAX_NUM];
    // 循环读取每个页面的访问序列
    for (int i = 0; i < pageAccessCount; ++i) {
        scanf("%d", &pageAccessSequence[i]);
    }

    // 读取热门页面的阈值
    scanf("%d", &hotThreshold);

    // 创建一个结构体数组,用于存储每个页面的访问频率
    PageFrequency pageFrequency[MAX_NUM] = {0};
    for (int i = 0; i < pageAccessCount; ++i) {
        pageFrequency[pageAccessSequence[i]].page = pageAccessSequence[i];
        pageFrequency[pageAccessSequence[i]].frequency++;
    }

    // 过滤出热门页面
    PageFrequency hotPages[MAX_NUM];
    int hotPagesCount = 0;
    for (int i = 0; i < MAX_NUM; ++i) {
        if (pageFrequency[i].frequency >= hotThreshold) {
            hotPages[hotPagesCount++] = pageFrequency[i];
        }
    }

    // 输出热门页面的数量
    printf("%d\n", hotPagesCount);

    // 如果存在热门页面
    if (hotPagesCount > 0) {
        // 对热门页面进行排序
        qsort(hotPages, hotPagesCount, sizeof(PageFrequency), cmp);

        // 输出排序后的热门页面
        for (int i = 0; i < hotPagesCount; ++i) {
            printf("%d\n", hotPages[i].page);
        }
    }

    return 0;
}

完整用例

用例1

10
1 1 2 2 3 3 4 4 5 5
2

用例2

10
1 1 1 1 1 1 1 1 1 2
3

用例3

10
1 2 3 4 5 6 7 8 9 10
11

用例4

10
1 2 2 3 3 3 4 4 4 4
3

用例5

10
1 1 1 1 2 2 2 3 3 4
3

用例6

10
100 200 300 100 200 100 400 500 100 200
3

用例7

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

用例8

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

用例9

10
65535 65535 65535 65535 65535 1 1 1 1 1
5

用例10

10
1 2 1 2 1 2 1 2 1 2
5

@[TOC]

fengmian