数据结构-线性表顺序表示
线性表的类型定义
基本操作:
InitList(&L)
操作结果:构造一个空的线性表L
DestroyList(&L)
初始条件:线性表L已经存在
操作结果:销毁线性表L
ClearList(&L)
初始条件:线性表L已经存在
操作结果:线性表L重置为空表
ListEmpty(L)
初始条件:线性表L已经存在
ListLength(L)
返回个数
GetElem(L,i,&e)
用e返回线性表L中第i个数据元素的值
LocateElem(L,e,compare())
返回L中第1个与e满足compare()的数据元素的位序,如果这样的数据元素不存在则返回值为0
PriorElem(L,cur_e,&pre_e)
如果cur_e是L的数据元素,且不是第一个,则就用pre_e返回它的前驱,否则操作失败,pre_e无意义
NextElem(L, cur_e, &next_
e)
初始条件
线性表L
已经存在。
操作结果
若cur_e
是L
的数据元素,且不是最后一个,则用next_e
返回它的后继,否则操作失败,next_e
无意义
- ListInsert(&L, i, e)
- 初始条件: 线性表L已经存在,1 <= i <= ListLength(L) + 1。
- 操作结果: 在L的第i个位置之前插入新的数据元素e,L的长度加一。
ListDelete(&L, i, &e)
- 初始条件:线性表 L 已经存在,1 <= i <= ListLength(L)。
- 操作结果:删除 L 的第 i 个数据元素,并用 e 返回其值,L 的长度减一。
- 删除前(长度为 n):(a₁, a₂, …, aᵢ₋₁, aᵢ, aᵢ₊₁, …, aₙ)
- 删除后(长度为 n - 1):(a₁, a₂, …, aᵢ₋₁, aᵢ₊₁, …, aₙ)
ListTraverse(&L, visited())
- 初始条件:线性表 L 已经存在。
- 操作结果:依次对线性表中每个元素调用 visited()。
其中,多项式的顺序存储结构类型
静态分配与动态分配
一个为提供整体数组,一个为指针形式
最基本的c语言的动态内存分配
那么对于c++来说呢?
#include <iostream>
using namespace std;
int main() {
int* p = new int; // 动态分配一个int
*p = 42;
cout << "p指向的值是:" << *p << endl;
delete p; // 释放内存
return 0;
}
C++
动态分配数组
#include <iostream>
using namespace std;
int main() {
int n;
cout << "请输入数组大小:";
cin >> n;
int* arr = new int[n]; // 分配一个整型数组
for (int i = 0; i < n; i++) {
arr[i] = i * 2;
}
cout << "数组内容为:";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
delete[] arr; // 释放数组内存
return 0;
}
C++
分配二维数组
#include <iostream>
using namespace std;
int main() {
int rows = 3, cols = 4;
int** matrix = new int*[rows]; // 分配行指针
for (int i = 0; i < rows; ++i) {
matrix[i] = new int[cols]; // 为每一行分配列
}
// 赋值并输出
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
matrix[i][j] = i + j;
cout << matrix[i][j] << " ";
}
cout << endl;
}
// 释放内存
for (int i = 0; i < rows; ++i) {
delete[] matrix[i];
}
delete[] matrix;
return 0;
}
C++
- 用 new 分配的内存必须用 delete 释放。
- new[] 对应 delete[],不要搞混。
- 不释放会导致 内存泄漏。
c++中的参数传递
一、值传递(Pass by Value)
函数收到的是实参的 一份拷贝,在函数中修改参数不会影响原始变量。
#include <iostream>
using namespace std;
void change(int x) {
x = 10;
}
int main() {
int a = 5;
change(a);
cout << "a = " << a << endl; // 输出:a = 5(没变)
return 0;
}
C++
二、指针传递(Pass by Pointer)
通过指针传递地址,可以直接修改实参变量的值。
#include <iostream>
using namespace std;
void change(int* x) {
*x = 10;
}
int main() {
int a = 5;
change(&a);
cout << "a = " << a << endl; // 输出:a = 10
return 0;
}
C++
三、引用传递(Pass by Reference)
C++ 特有,用变量的 别名来传递参数,既高效又安全。
#include <iostream>
using namespace std;
void change(int& x) {
x = 10;
}
int main() {
int a = 5;
change(a);
cout << "a = " << a << endl; // 输出:a = 10
return 0;
}
C++
顺序表的查找
按值查找(给定一个值e,查找他在表中的位置)
#include <iostream>
using namespace std;
const int MAX_SIZE = 100;
struct SqList {
int data[MAX_SIZE]; // 存储元素
int length; // 当前表长
};
C++
int LocateElem(SqList L, int e) {
for (int i = 0; i < L.length; i++) {
if (L.data[i] == e)
return i + 1; // 返回逻辑位序(从1开始)
}
return 0; // 没找到返回0
}
C++
顺序表的插入
顺序表的删除
时间复杂度都是O(n),空间复杂度都是O(1)
顺序表(基于数组实现的线性表)的优缺点如下:
优点:
随机访问高效 通过下标可直接访问元素(时间复杂度 O(1)),适合频繁查询的场景。
存储密度高 只需存储数据元素,无需额外空间维护逻辑关系(如指针),内存利用率高。
尾部操作高效 在表尾插入或删除元素时时间复杂度为 O(1)(若无需扩容)。
缓存友好 数据连续存储,预读特性使得CPU缓存命中率高,访问速度快。
缺点:
插入/删除效率低 在非尾部位置操作时,需移动大量元素(平均时间复杂度 O(n))。
固定容量问题 静态分配需预先指定大小,可能浪费空间或不足;动态分配虽可扩容(如2倍扩容),但扩容操作耗时(O(n))。
内存要求高 需要连续的物理内存空间,数据量大时可能难以分配足够内存。
适用场景
频繁随机访问、查询操作。
元素数量可预估或变化较小。
对内存使用效率要求高。
不适用场景
频繁在非尾部位置插入/删除。
元素数量变化大且难以预估。 (此时链式结构更合适)