线性表
定义:具有相同数据类型的n个数据元素的有限序列
顺序表
注意这里的定义:顺序表是线性表的顺序存储
特点:
- 可以随机存储
- 存储密度较高,无额外的指针开销,适合频繁访问元素,较少插入、删除操作的场景
顺序表的存储结构
假定线性表的数据元素类型为ElemType,静态分配方式:
c
#define MaxSize 50
typedef struct{
ElemType data[MaxSize];
int length; // 顺序表当前长度
}SqList;
动态分配:
c
#define MaxSize 50
typedef struct{
ElemType *data; // 动态分配内存的基地址
int length; // 实际长度(当前顺序表中已存储的数据元素个数)
int MaxSize; // 数组的最大容量
}SqList;
// C初始动态分配语句
L.data = (ElemType *)malloc(sizeof(ElemType) * InitSize)
动态内存分配和静态内存分配
静态分配 | 动态分配 |
---|---|
在程序编译时就已经确定了内存大小和位置,不占用CPU资源 | 在程序运行时根据需要动态地分配和释放内存,需要占用CPU资源 |
用于:全局变量、静态变量、常量 | C:malloc, free |
其内存由编译器自动管理 | 由程序员手动管理,包括分配和释放。 |
内存大小和生命周期都是固定的 | 内存大小和生命周期可以在运行时动态改变 |
通常在栈段或.data段中分配 | 通常在堆(heap)中分配,函数调用时传递的是指针 |
引用符&和地址无关
c
SqList list; // 原变量 list
SqList &L = list; // L 是 list 的引用(别名)
你操作 L.data
,就等同于操作 list.data
,完全不需要关心 "地址"------ 编译器会自动关联到原变量,不需要你手动处理地址
顺序表的初始化
静态:
c
SqList L;
void InitSqList(SqList &L)
{
L.length = 0;
}
动态:
c
void InitSqList(SqList &L)
{
L.data = (Elemtype *)malloc(sizeof(Elemtype) * InitSize)
L.length = 0; // 初始长度=0
L.MaxSize = InitSize; // 初始存储容量
}
顺序表的插入
c
int InsertSqList(SqList &L, int i, int e)
{
// 检查i的值是否合法
if (i < 1 || i > L.length + 1)
return false;
// 检查顺序表是否已满
if (L.length == MaxSize)
{
return false;
}
// L.data[j]已经是当前最后一个值的后一位了
for(j = L.length; j >= i; j--)
{
L.data[j] = L.data[j-1];
}
L.data[i-1] = e;
// 顺序表当前长度加1
L.length++;
return e;
}
顺序表的删除
c
bool DeleteSqList(SqList& L, int i, int* e)
// 如果使用 int e 作为参数,函数内部对 e 的修改只会在函数内部生效(属于局部变量),无法将删除的元素值传递到函数外部
{
// 检查i的值是否合法
if (i < 1 || i > L.length)
return false;
*e = L.data[i - 1]; // 使用指针接收删除的元素
for (int j = i; j < L.length; j++)
{
L.data[j - 1] = L.data[j];
}
L.length--;
return true;
}
顺序表的查找
- 按值查找
c
// 时间复杂度为O(n)
int GetItem(SqList &L, int e)
{
for(int j = 0; j < L.length; j++)
{
if (L.data[j] == e)
return j + 1;
}
return 0;
}
- 按序号查找
c
int GetItem(SqList& L, int i, int e)
{
// 检查i的值是否合法
if (i < 1 || i > L.length)
return false;
e = L.data[i - 1];
return e;
}
完整代码
c
// 这里的代码是用C实现的,因为C并不支持引用的方式,这里把引用都改为指针
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define ElemType int
#define MaxSize 50
typedef struct {
ElemType data[MaxSize];
int length; // 顺序表当前长度
} SqList;
// 初始化顺序表
void InitSqList(SqList* L) {
L->length = 0;
}
// 在顺序表第i个位置插入元素e(i从1开始)
bool InsertSqList(SqList* L, int i, int e) {
// 检查i的值是否合法
if (i < 1 || i > L->length + 1)
return false;
// 检查顺序表是否已满
if (L->length == MaxSize)
return false;
int j;
for (j = L->length; j >= i; j--) {
L->data[j] = L->data[j - 1];
}
L->data[i - 1] = e;
L->length++;
return true;
}
// 删除顺序表第i个位置的元素,并通过指针e返回该元素
bool DeleteSqList(SqList* L, int i, int* e) {
// 检查i的值是否合法
if (i < 1 || i > L->length)
return false;
*e = L->data[i - 1]; // 保存要删除的元素
// 移动元素覆盖被删除的位置
for (int j = i; j < L->length; j++) {
L->data[j - 1] = L->data[j];
}
L->length--;
return true;
}
// 按值查找,返回元素e在顺序表中的位置(1开始),未找到返回0
int LocateElem(SqList* L, int e) {
for (int j = 0; j < L->length; j++) {
if (L->data[j] == e)
return j + 1; // 返回位序(从1开始)
}
return 0; // 未找到
}
// 按位置查找,返回顺序表第i个位置的元素
ElemType GetElemByIndex(SqList* L, int i) {
// 检查i的值是否合法
if (i < 1 || i > L->length) {
printf("位置不合法\n");
return -1; // 假设-1不是合法数据
}
return L->data[i - 1];
}
// 打印顺序表所有元素
void PrintSqList(SqList* L) {
printf("顺序表内容: ");
for (int i = 0; i < L->length; i++) {
printf("%d ", L->data[i]);
}
printf("(长度: %d)\n", L->length);
}
int main() {
SqList L;
InitSqList(&L);
// 测试插入操作
InsertSqList(&L, 1, 10);
InsertSqList(&L, 2, 20);
InsertSqList(&L, 3, 30);
InsertSqList(&L, 2, 15); // 在位置2插入15
PrintSqList(&L);
// 测试查找操作
int pos = LocateElem(&L, 20);
if (pos != 0)
printf("元素20的位置是: %d\n", pos);
else
printf("未找到元素20\n");
ElemType val = GetElemByIndex(&L, 3);
printf("位置3的元素是: %d\n", val);
// 测试删除操作
int delVal;
if (DeleteSqList(&L, 2, &delVal))
printf("删除的元素是: %d\n", delVal);
PrintSqList(&L);
return 0;
}
//顺序表内容: 10 15 20 30 (长度: 4)
//元素20的位置是: 3
//位置3的元素是: 20
//删除的元素是: 15
//顺序表内容: 10 20 30 (长度: 3)