PAT-2021年秋季考试 甲级 7-1 Arrays and Linked Lists (C++)

该博客讨论了一种数据结构设计,它结合了数组和链表的特点,以处理用户对超出当前数组范围的访问请求。系统会动态创建新的数组来扩展存储空间,并返回相应的内存地址。当用户尝试访问超出所有数组范围的元素时,系统将输出"IllegalAccess"。文章还提供了具体实现的代码示例,并分享了作者在解决此问题时遇到的常见错误和解决方案。
摘要由CSDN通过智能技术生成

Let’s design a data structure A A A that combines arrays and linked lists as the following:
At the very beginning, an integer array A 0 A_0 A0 of length L 0 L_0 L0 is initialized for the user. When the user tries to access the i i ith element A [ i ] A[i] A[i], if 0 ≤ i < L 0 0≤i<L_0 0i<L0, then A [ i ] A[i] A[i] is just A 0 [ i ] A_0[i] A0[i]. Now our system is supposed to return h 0 + i × s i z e o f ( i n t ) h_0+i×sizeof(int) h0+i×sizeof(int) as the accessed address, where h 0 h_0 h0 is the initial address of A 0 A_0 A0, and s i z e o f ( i n t ) sizeof(int) sizeof(int) is the size of the array element, which is simply int, taking 4 bytes.

In case there is an overflow of the user’s access (that is, i ≥ L 0 i≥L_0 iL0), our system will declare another array A 1 A_1 A1 of length L 1 L_1 L1. Now A [ i ] A[i] A[i] corresponds to A 1 [ j ] A_1[j] A1[j] (It’s your job to figure out the relationship between i i i and j j j). If 0 ≤ j < L 1 0≤j<L_1 0j<L1, then h 1 + j × s i z e o f ( i n t ) h_1+j×sizeof(int) h1+j×sizeof(int) is returned as the accessed address, where h 1 h_1 h1 is the initial address of A 1 A_1 A1.

And if there is yet another overflow of the user’s access to A 1 [ j ] A_1[j] A1[j], our system will declare another array A 2 A_2 A2 of length L 2 L_2 L2, and so on so forth.

Your job is to implement this data structure and to return the address of any access.

Input Specification:

Each input file contains one test case. For each case, the first line gives 2 positive integers N ( ≤ 1 0 4 ) N (≤10^4) N(104) and K ( ≤ 1 0 3 ) K (≤10^3) K(103) which are the number of arrays that can be used, and the number of user queries, respectively.
Then N N N lines follow, each gives 2 positive integers, which are the initial address ( ≤ 1 0 7 ≤10^7 107) and the length ( ≤ 100 ≤100 100) of an array, respectively. The numbers are separated by spaces. It is guaranteed that there is no overlap of the spaces occupied by these arrays.

Finally, K K K indices of the elements queried by users are given in the last line. Each index is an integer in the range [ 0 , 2 20 ] [0,2^{20}] [0,220].

Output Specification:

For each query, print in a line the accessed address. If the queried index exceeds the range of all the N N N arrays, output Illegal Access instead, and this query must NOT be processed.

Print in the last line the total number of arrays that have been declared for the whole process.

Sample Input:

6 7
2048 5
128 6
4016 10
1024 7
3072 12
9332 10
2 12 25 50 28 8 39

Sample Output:

2056
4020
1040
Illegal Access
3072
140
3116
5

Hint

A [ 2 ] A[2] A[2] is just A 0 [ 2 ] A_0[2] A0[2], so the accessed address is 2048 + 2 × 4 = 2056 2048+2×4=2056 2048+2×4=2056.
In order to access A [ 12 ] A[12] A[12], declaring A 1 A_1 A1 is not enough, we need A 2 A_2 A2 with initial address h 2 = 4016 h_2=4016 h2=4016. Since A [ 12 ] = A 2 [ 1 ] A[12]=A_2[1] A[12]=A2[1], the accessed address is 4016 + 1 × 4 = 4020 4016+1×4=4020 4016+1×4=4020.
In order to access A [ 25 ] A[25] A[25], we need A 3 A_3 A3 with initial address h 3 = 1024 h_3=1024 h3=1024. Since A [ 25 ] = A 3 [ 4 ] A[25]=A_3[4] A[25]=A3[4], the accessed address is 1024 + 4 × 4 = 1040 1024+4×4=1040 1024+4×4=1040.
The access of A [ 50 ] A[50] A[50] exceeds the maximum boundary of all the arrays, and hence an illegal access. There is no extra array declared.
In order to access A [ 28 ] A[28] A[28], we need A 4 A_4 A4 with initial address h 4 = 3072 h_4=3072 h4=3072. Since A [ 28 ] = A 4 [ 0 ] A[28]=A_4[0] A[28]=A4[0], the accessed address is just 3072 3072 3072.
It is clear to see that A [ 8 ] = A 1 [ 3 ] A[8]=A_1[3] A[8]=A1[3] and hence the accessed address is 128 + 3 × 4 = 140 128+3×4=140 128+3×4=140; and A [ 39 ] = A 4 [ 11 ] A[39]=A_4[11] A[39]=A4[11] so the accessed address is 3072 + 11 × 4 = 3116 3072+11×4=3116 3072+11×4=3116.
All together there are 5 arrays used for the above queries.

Caution:

这次考试说实话不难,不过第一题就是通过率最低的题,当时我写完后只对了两个测试点,退出去后看四个题的通过率,好家伙,后三个题都是 0.5 左右,只有第一题 0.0 几(到结束的时候,这道题通过率也只有0.04),于是信心一下子上来了,去写后面三个题的时候都是一遍 AC。

这道题我觉得有两个容易错的,第一个就是绊倒很多人——默认开的数组个数是 1 不是 0,因为题目中有这样一句话:

At the very beginning, an integer array A 0 A_0 A0 of length L 0 L_0 L0 is initialized for the user.

所以就算一次有效查询也没有,开的数组个数也是 1 而不是 0。

第二个容易理解错的是这个开的数组个数 tmpCnt 的更新规则不是当开了一个新的数组的话 tmpCnt 就加 1,而是假如你第一次查询就查到了第 5 个数组(这里数组下标从 1 开始记),那么你的 cnt 就是 5 而不是 2,因为你查到第 5 个数组的过程是:首先看到超过了第一个数组的范围,然后开第 2 个数组,一看仍然超了,然后开第 3 个,以此类推,而不是一看是在第五个数组范围内,所以就直接开辟第五个数组,因此 tmpCnt 的更新规则是:

tmpCnt = max(tmpCnt, l + 1);
// l 是通过二分确定的访问元素所在数组的位置

代码思路就是 arrayAddress 存放每个数组的起始地址,jieshuweizhi 存放每个数组的最后一个元素在整个数据结构里对应的下标,然后输入一个访问位置后首先看是不是在合法范围内,然后在 jieshuweizhi 里二分找到第一个大于这个访问位置的元素,得到就是访问的元素所在数组的位置,然后计算相应地址并输出。

附上其他三道题的解答:7-27-37-4

Solution:

// Talk is cheap, show me the code
// Created by Misdirection 2021-09-11 13:32:51
// All rights reserved.

#include <iostream>
#include <vector>

using namespace std;

int arrayAddress[10010];
int jieshuweizhi[10010];
bool flag[10010];

int main(){
    int n, k;
    // n - the number of arrays that can be used
    // k - the number of user queries

    scanf("%d %d", &n, &k);

    for(int i = 0; i < n; ++i){
        int address, cnt;
        scanf("%d %d", &address, &cnt);

        arrayAddress[i] = address;

        if(i == 0) jieshuweizhi[i] = cnt - 1;
        else jieshuweizhi[i] = jieshuweizhi[i - 1] + cnt;
    }

    int tmpCnt = 1;
    flag[0] = true;

    for(int i = 0; i < k; ++i){
        int tmp;
        scanf("%d", &tmp);
        
        if(tmp > jieshuweizhi[n - 1]){
            printf("Illegal Access\n");
            continue;
        }

        int l = 0, r = n - 1;
        while(l < r){
            int mid = l + r >> 1;
            if(jieshuweizhi[mid] >= tmp) r = mid;
            else l = mid + 1;
        }

        if(l == 0) printf("%d\n", arrayAddress[l] + tmp * 4);
        else printf("%d\n", arrayAddress[l] + 4 * (tmp - jieshuweizhi[l - 1] - 1));
        
        if(!flag[l]){
            tmpCnt = max(tmpCnt, l + 1);
            flag[l] = true;
        }
    }

    printf("%d\n", tmpCnt);

    return 0;
}

在这里插入图片描述

在实现队列(Queue)的数据结构时,可以使用链表(Linked Lists)和数组(Arrays)这两种常见的数据结构。 a. 使用链接列表(Linked List)实现队列: ```python class Node: def __init__(self, data): self.data = data self.next = None class QueueLL: def __init__(self): self.head = None self.tail = None # 入队操作(enqueue) def enqueue(self, data): new_node = Node(data) if not self.is_empty(): self.tail.next = new_node else: self.head = new_node self.tail = new_node # 出队操作(dequeue) def dequeue(self): if self.is_empty(): return None temp_data = self.head.data self.head = self.head.next if self.is_empty(): self.tail = None return temp_data # 检查队列是否为空 def is_empty(self): return self.head is None # 显示队列元素 def display(self): current = self.head while current: print(current.data, end=" -> ") current = current.next print("None") ``` b. 使用数组实现队列(Array-Based Queue): ```python class QueueArray: def __init__(self, capacity): self.queue = [None] * capacity self.front = -1 self.rear = -1 def is_empty(self): return self.front == self.rear def enqueue(self, data): if (self.rear + 1) % len(self.queue) == self.front: raise Exception("Queue full") if self.is_empty(): self.front = self.rear = 0 else: self.rear = (self.rear + 1) % len(self.queue) self.queue[self.rear] = data def dequeue(self): if self.is_empty(): raise Exception("Queue empty") value = self.queue[self.front] if self.front == self.rear: self.front = self.rear = -1 else: self.front = (self.front + 1) % len(self.queue) return value def display(self): if self.is_empty(): print("Queue is empty") else: index = self.front while True: try: print(self.queue[index], end=" -> ") index = (index + 1) % len(self.queue) except IndexError: break print("None") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

负反馈循环

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值