PTA 实验1-1 有序数组的插入(C++版)

实验1-1 有序数组的插入(C++版)

分数 20

作者 刘凯源

单位 华东师范大学

给定存储了n个从大到小排好序的整数,试将任一给定整数x 插入数组中合适的位置,以保持结果依然有序。分析算法在最坏、最好情况下的时间、空间复杂度。具体来说,不妨假设整数序列存储为一个序列 array,这个序列的结构定义在下面给出,数据存放在数组 data中。因为数组长度是有限的,我们在此假设 data数组的最大长度为 kMaxSize。如果在执行插入之前,数组已经满了,则插入失败,返回 false;如果待插入的元素 x 已经在data中,则不要重复插入,返回false;如果插入成功,则返回 true

函数接口定义:

1
bool DecrSeqInsert(ArrNode& array, int x);

其中ArrNode定义如下:

1
2
3
4
5
6
class ArrNode {
public:
vector<int> data_; // 使用vector来动态管理数组大小
int size_; // 数组的大小
explicit ArrNode(int n) : size_(0), data_(vector<int>(n)) {}
};

这里题目保证传入的数据是递减有序的。

裁判测试程序样例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main() {
int n, x;
cin >> n;
ArrNode array(kMaxSize);
array.size_ = n;
for (int i = 0; i < n; i++) {
cin >> array.data_[i];
}
cin >> x;
if (!DecrSeqInsert(array, x)) {
cout << "Insertion failed." << endl;
}
for (int i = 0; i < array.size_; i++) {
if (i > 0) cout << " ";
cout << array.data_[i];
}
cout << endl;
cout << "Array size = " << array.size_ << endl;
return 0;
}

输入样例1:

1
2
3
5
35 12 8 7 3
10

输出样例1:

1
2
35 12 10 8 7 3
Array size = 6

输入样例2:

1
2
3
6
35 12 10 8 7 3
8

输出样例2:

1
2
3
Insertion failed.
35 12 10 8 7 3
Array size = 6

函数代码(题目要求提交的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 向递减递减序列(Decreasing Sequence)中插入元素
bool DecrSeqInsert(ArrNode& array, int x) {
// 数组已经满了,则插入失败,返回 false
if (array.size_ == kMaxSize) {
return false;
}
// 避免重复插入
for (int i = 0; i < array.size_; ++i) {
if (array.data_[i] == x) {
return false;
}
}
//找到插入位置i
int i; // 这里先定义插入位置i,方便后续把插入的x放入array.data_[i+1]中
for (i = 0; i < array.size_; i++) {
// 找到第一个比x小的元素
if (array.data_[i] < x) {
break;
}
}
// 把比x小的元素往后挪
for (int j = array.size_-1; j >= i; j--) {
array.data_[j+1] = array.data_[j];
}
// 将x插入规定位置
array.data_[i] = x;
// 表长++
array.size_++;
return true;
}

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <vector>

using namespace std;

const int kMaxSize = 1000;

class ArrNode {
public:
vector<int> data_; // 使用vector来动态管理数组大小
int size_; // 数组的大小
explicit ArrNode(int n) : size_(0), data_(vector<int>(n)) {}
};
// 向递减递减序列(Decreasing Sequence)中插入元素
bool DecrSeqInsert(ArrNode& array, int x) {
// 数组已经满了,则插入失败,返回 false
if (array.size_ == kMaxSize) {
return false;
}
// 避免重复插入
for (int i = 0; i < array.size_; ++i) {
if (array.data_[i] == x) {
return false;
}
}
//找到插入位置i
int i; // 这里先定义插入位置i,方便后续把插入的x放入array.data_[i+1]中
for (i = 0; i < array.size_; i++) {
// 找到第一个比x小的元素
if (array.data_[i] < x) {
break;
}
}
// 把比x小的元素往后挪
for (int j = array.size_-1; j >= i; j--) {
array.data_[j+1] = array.data_[j];
}
// 将x插入规定位置
array.data_[i] = x;
// 表长++
array.size_++;
return true;
}

int main() {
int n, x;
cin >> n;
ArrNode array(kMaxSize);
array.size_ = n;
for (int i = 0; i < n; i++) {
cin >> array.data_[i];
}
cin >> x;
if (!DecrSeqInsert(array, x)) {
cout << "Insertion failed." << endl;
}
for (int i = 0; i < array.size_; i++) {
if (i > 0) cout << " ";
cout << array.data_[i];
}
cout << endl;
cout << "Array size = " << array.size_ << endl;
return 0;
}

Summary

1.易错:

  • 如果这样写会有个错误:

  • // 向递减递减序列(Decreasing Sequence)中插入元素
    bool DecrSeqInsert(ArrNode& array, int x) {
        // 数组已经满了,则插入失败,返回 false
        if (array.size_ == kMaxSize) {
            return false;
        }
        // 避免重复插入,并把符合条件的x插入
        for (int i = 0; i < array.size_; ++i) {
            if (array.data_[i] == x) {
                return false;
            } else if (array.data_[i] > x && array.data_[i + 1] < x) {
                // 把比x小的元素往后挪
                for (int j = array.size_-1; j > i; j--) {
                    array.data_[j+1] = array.data_[j];
                }
                // 把x插到规定位置
                array.data_[i + 1] = x;
                // 插入了一个元素表长++
                array.size_++;
                return true;
            }
        }
    }
    <!--code9-->
    

情况 1:构造函数有explicit(你的代码当前状态)

1
2
3
4
5
6
// 正确写法:显式创建ArrNode对象
ArrNode array(kMaxSize);
printArray(array); // 正确

// 错误写法:试图直接传整数
printArray(kMaxSize); // 编译报错!无法隐式转换

这时候编译器会报错,因为explicit禁止了 “整数→ArrNode” 的隐式转换,你必须明确传递ArrNode对象。

情况 2:如果去掉explicit

1
2
// 构造函数没有explicit修饰
ArrNode(int n) : size_(0), data_(vector<int>(n)) {}

这时再调用printArray(kMaxSize),编译器会自动做一件事

  1. kMaxSize作为参数,隐式创建一个临时ArrNode对象(相当于ArrNode(kMaxSize)
  2. 把这个临时对象传给printArray函数

这就导致了 “意外转换”:你本来想传一个整数,结果编译器偷偷帮你创建了一个ArrNode对象,而这很可能不符合你的意图。

总结:

  • explicit 只用于修饰单个参数的构造函数(或除第一个参数外其余参数都有默认值的构造函数)。
  • 你的 ArrNode 是一个管理数组的类,它的构造函数需要一个 int 参数(n)来指定内部 vector 的初始容量。加上 explicit 可以:
  1. 避免有人误写 ArrNode array = kMaxSize; 这种不直观的代码
  2. 防止在函数传参时,把 int 类型的 kMaxSize 或其他整数意外转换ArrNode 对象
  3. 让代码意图更清晰:创建 ArrNode 对象必须明确调用构造函数,而不是通过隐式转换