03-顺序表
1. 顺序表概念
线性表: n 个具有相同特性的数据元素的有序序列。
顺序表: 顺序存储实现的线性表.
2. 静态顺序表的模拟实现
分类:
- 数组采用静态分配,此时的顺序表称为静态顺序表。
- 数组采用动态分配,此时的顺序表称为动态顺序表。
对比:
优点 | 缺点 | |
静态分配 |
| 过满溢出, 过少浪费 |
动态分配 | 支持扩容 |
|
#include <iostream>using namespace std;const int N = 1e6 + 10; // 根据实际情况而定// 创建顺序表
int a[N]; // 用足够大的数组来模拟顺序表
int n; // 标记顺序表里面有多少个元素// 需要多个顺序表,才能解决问题
// int a1[N], n1;
// int a2[N], n2;
// int a3[N], n3;// 打印顺序表
void print()
{for(int i = 1; i <= n; i++){cout << a[i] << " ";}cout << endl << endl;
}// 尾插
void push_back(int a[], int& n, int x)
{a[++n] = x;
}// 头插
void push_front(int x)
{// 1. 先把 [1, n] 的元素统一向后移动一位for(int i = n; i >= 1; i--){a[i + 1] = a[i];}// 2. 把 x 放在表头a[1] = x;n++; // 元素个数 +1
}// 在任意位置插入
void insert(int p, int x)
{// 1. 先把 [p, n] 的元素统一向后移动一位for(int i = n; i >= p; i--){a[i + 1] = a[i];}a[p] = x;n++;
}// 尾删
void pop_back()
{n--;
}// 头删
void pop_front()
{// 1. 先把 [2, n] 区间内的所有元素,统一左移一位for(int i = 2; i <= n; i++){a[i - 1] = a[i];}n--;
}// 任意位置删除
void erase(int p)
{// 把 [p + 1, n] 的元素,统一左移一位for(int i = p + 1; i <= n; i++){a[i - 1] = a[i];}n--;
}// 按值查找
int find(int x)
{for(int i = 1; i <= n; i++){if(a[i] == x) return i;}return 0;
}// 按位查找
int at(int p)
{return a[p];
}// 按位修改
int change(int p, int x)
{a[p] = x;
}// 清空操作
void clear()
{n = 0;
}
3. STL动态顺序表 -- vector
#include <iostream>
#include <vector>using namespace std;const int N = 10;struct node
{int a, b;string s;
};void print(vector<int>& a)
{// 利用 size 来遍历// for(int i = 0; i < a.size(); i++)// {// cout << a[i] << " ";// }// cout << endl;// 利用迭代器来遍历 - 迭代器类型 vector<int>::iterator// for(auto it = a.begin(); it != a.end(); it++)// {// cout << *it << " ";// }// cout << endl;// 使用语法糖 - 范围 forfor(auto x : a){cout << x << " ";}cout << endl;
}int main()
{// 1. 创建 vectorvector<int> a1; // 创建了一个名字为 a1 的空的可变长数组,里面都是 int 类型的数据vector<int> a2(N); // 创建了一个大小为 10 的可变长数组,里面的值默认都是 0vector<int> a3(N, 2); // 创建了一个大小为 10 的可变长数组,里面的值都初始化为 2vector<int> a4 = {1, 2, 3, 4, 5}; // 初始化列表的创建方式// <> 里面可以存放任意的数据类型,这就体现了模板的作用,也体现了模板的强大之处// 这样,vector里面就可以存放我们见过的所有的数据类型,甚至是 STL 本身vector<string> a5; // 存字符串vector<node> a6; // 存结构体vector<vector<int>> a7; // 创建了一个二维的可变长数组vector<int> a8[N]; // 创建了一个大小为 N 的 vector 数组// int a[N];// 2. size / empty// print// print(a2);// print(a3);// print(a4);// if(a2.empty()) cout << "空" << endl;// else cout << "不空" << endl;// 3. begin / end// print// print(a2);// print(a3);// print(a4);// 4. 尾插以及尾删// for(int i = 0; i < 5; i++)// {// a1.push_back(i);// print(a1);// }// while(!a1.empty())// {// print(a1);// a1.pop_back();// }// 5. front / back// cout << a4.front() << " " << a4.back() << endl;// 6. resizevector<int> aa(5, 1);print(aa);// 扩大成 10aa.resize(10);print(aa);// 缩小成 3aa.resize(3);print(aa);// 7. clearcout << aa.size() << endl;aa.clear();cout << aa.size() << endl;return 0;
}
4. 算法习题
4.1. 【深基15.例1】询问学号
P3156 【深基15.例1】询问学号 - 洛谷
#include <iostream>
#include <vector>using namespace std;const int N = 2e6 + 10;int n, m;
vector<int> a(N);int main()
{cin >> n >> m;for(int i = 1; i <= n; i++) cin >> a[i];while(m--){int x; cin >> x;cout << a[x] << endl;}return 0;
}
4.2. 【深基15.例2】寄包柜
P3613 【深基15.例2】寄包柜 - 洛谷
#include <iostream>
#include <vector>using namespace std;const int N = 1e5 + 10;int n, q;
vector<int> a[N]; // 创建 N 个柜子int main()
{cin >> n >> q;while(q--){int op, i, j, k;cin >> op >> i >> j;if(op == 1) // 存{cin >> k;if(a[i].size() <= j){// 扩容a[i].resize(j + 1);}a[i][j] = k;}else // 查询{cout << a[i][j] << endl;}}return 0;
}
4.3. 移动零
283. 移动零 - 力扣(LeetCode)
class Solution
{
public:void moveZeroes(vector<int>& nums) {for(int i = 0, cur = -1; i < nums.size(); i++){if(nums[i]) // 非0元素swap(nums[++cur], nums[i]);}}
};
4.4. 颜色分类
75. 颜色分类 - 力扣(LeetCode)
class Solution
{
public:void sortColors(vector<int>& nums) {int left = -1, i = 0, right = nums.size();while(i < right){if(nums[i] == 0) swap(nums[++left], nums[i++]);else if(nums[i] == 1) i++;else swap(nums[--right], nums[i]); // 这个地方不能i++, 因为换过来的数是未判断的, 因此需要再次判断这个数}}
};
4.5. 合并两个有序数组
88. 合并两个有序数组 - 力扣(LeetCode)
class Solution
{
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {// 解法一:利用辅助数组vector<int> tmp(m + n);int cur = 0, cur1 = 0, cur2 = 0;while(cur1 < m && cur2 < n){if(nums1[cur1] <= nums2[cur2]) tmp[cur++] = nums1[cur1++];else tmp[cur++] = nums2[cur2++];}while(cur1 < m) tmp[cur++] = nums1[cur1++];while(cur2 < n) tmp[cur++] = nums2[cur2++];for(int i = 0; i < n + m; i++) nums1[i] = tmp[i];}
};class Solution
{
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {// 解法二:原地合并int cur1 = m - 1, cur2 = n - 1, cur = m + n - 1;while(cur1 >= 0 && cur2 >= 0){if(nums1[cur1] >= nums2[cur2]) nums1[cur--] = nums1[cur1--];else nums1[cur--] = nums2[cur2--];}while(cur2 >= 0) nums1[cur--] = nums2[cur2--];}
};
4.6. UVA101 The Blocks Problem
UVA101 The Blocks Problem - 洛谷
思路: 用vector数组模拟, pair存储下标, 将题目操作拆分为归为 + 放置即可.
#include <iostream>
#include <vector>using namespace std;const int N = 30;
typedef pair<int, int> PII;int n;
vector<int> p[N]; // 创建 n 个放木块的槽PII find(int x)
{for(int i = 0; i < n; i++){for(int j = 0; j < p[i].size(); j++){if(p[i][j] == x){return {i, j};}}}
}void clean(int x, int y)
{// 把 [x, y] 以上的木块归位for(int j = y + 1; j < p[x].size(); j++){int t = p[x][j];p[t].push_back(t);}p[x].resize(y + 1);
}void move(int x1, int y1, int x2)
{// 把 [x1, y1] 及其以上的木块放在 x2 上面for(int j = y1; j < p[x1].size(); j++){p[x2].push_back(p[x1][j]);}p[x1].resize(y1);
}int main()
{cin >> n;// 初始化for(int i = 0; i < n; i++){p[i].push_back(i);}string op1, op2;int a, b;while(cin >> op1 >> a >> op2 >> b){// 查找 a 和 b 的位置PII pa = find(a);int x1 = pa.first, y1 = pa.second;PII pb = find(b);int x2 = pb.first, y2 = pb.second;if(x1 == x2) continue; // 处理不合法的操作if(op1 == "move") // 把 a 上方归位{clean(x1, y1);}if(op2 == "onto") // 把 b 上方归位{clean(x2, y2);}move(x1, y1, x2);}// 打印for(int i = 0; i < n; i++){cout << i << ":";for(int j = 0; j < p[i].size(); j++){cout << " " << p[i][j];}cout << endl;}return 0;
}