线性表的理解
当线性表使用连续的内存空间来存储时,就是顺序表。
顺序表使用物理内存地址表示线性表中元素的前驱和后继关系。
优点
访问时可以根据内存物理地址访问,时间复杂度为O(1)
可以随机存取表中任一元素
缺点
在插入、删除某一元素时,需要移动大量元素
空间需要预申请,浪费存储空间
属于静态存储形式,数据元素的个数不能自由扩充
实现(C语言)
声明配置
定义程序执行的常量、变量依赖环境。使程序调整更灵活,修改时不用一处处的修改
#include <stdio.h>
#include <stdlib.h>
// 函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status; // Status是函数的类型,也就是函数的返回值
typedef char ElemType;
#define MAXSIZE 5 // 定义宏表示线性表的长度
定义结构体表示顺序表
实现的思路是,结构体的实例表示一个线性表(这与链表不同),由一个指针指向存储线性表元素存储的内存空间。
后续的操作都是作用在这个结构体实例上
/*
定义结构,表示顺序表类型
*/
typedef struct {
ElemType *elem;
int length;
}SqList;
线性表初始化
对已有的一个线性表实例进行初始化。申请一块连续的空间,使线性表实例的指针成员指向这块空间,
并记录线性表的成员数量为0
// 构造一个空的顺序表L
Status InitList_Sq(SqList *L) {
L->elem = (ElemType *)malloc(MAXSIZE * sizeof(ElemType));
if(!L->elem){ // 分配空间失败
exit(OVERFLOW); // 退出程序
}
L->length = 0; // 空表长度为0
return OK;
}
销毁线性表
将主动申请的、用来存储线性表成员的内存空间主动回收,之后
// 销毁线性表L
void DestroyList(SqList *L) {
if (L->elem) {
free(L->elem);
}
L->length = 0;
}
清空线性表
在逻辑上将线性表实例已有的元素视作无效,则只需将线性表实例的表示长度的成员的值设置为0即可
// 清空线性表
void ClearList(SqList *L) {
L->length = 0;
}
线性表长度
// 求线性表长度
int GetLength(SqList L) {
return L.length;
}
线性表判空
// 判断线性表是否为空
int IsEmpty(SqList L) {
if (L.length == 0) {
return 1;
} else {
return 0;
}
}
线性表插入
将某值插入到线性表某个位置上,需要先将该位置以及后面的所有值依次往后移一位,操作的时间复杂度为O(n)。
当线性表保存大量数据,而插入位置比较靠前时,则比较耗费时间,这也是线性表的痛点之一
Status ListInsert_Sq(SqList *L, int i, ElemType e) {
int j;
if (i < 1 || i > L->length + 1) { // 值不合法
exit(ERROR);
}
if (L->length == MAXSIZE) { // 当前储存空间已满
exit(ERROR);
}
for (j = L->length - 1; j >= i - 1; j--) {
L->elem[j + 1] = L->elem[j]; // 插入位置及之后的元素后移
}
L->elem[i - 1] = e;
L->length++;
return OK;
}
线性表删除元素
删除某位置上的元素,将该位置之后的所有元素依次向前移一位,所以时间复杂度为O(n)
Status ListDelete_Sq(SqList *L, int i) {
int j;
if (i < 1 || i > L->length) { // i值不合法
exit(ERROR);
}
// printf("线性表的长度为:%d", L->length);
for ( j = i; j < L->length; j++) {
L->elem[j - 1] = L->elem[j]; // 被删除元素之后的元素前移
}
L->length--;
return OK;
}
线性表取值
int GetElem(SqList *L, int i, ElemType *e) {
if (i < 1 || i > L->length) {
exit(ERROR);
}
*e = *(L->elem + i - 1);
return OK;
}
线性表查值
查询线性表内某值第一次出现的位置
int LocateElem(SqList L, ElemType e) {
// 在线性表L中查找值为e的数据元素,返回其序号
int i;
for(i = 0; i < L.length; i++) {
if (L.elem[i] == e) {
return i + 1; // 查找成功,返回符号
}
}
return 0; // 查找失败,返回0
}
测试功能
int main(int argc, char *argv[]) {
int i;
ElemType e;
SqList list;
InitList_Sq(&list);
ListInsert_Sq(&list, 1, 'A');
ListInsert_Sq(&list, 2, 'B');
ListInsert_Sq(&list, 3, 'D');
ListInsert_Sq(&list, 2, 'c');
printf("长度为: %d\n", GetLength(list));
GetElem(&list, 2, &e);
printf("第%d位上的值为:%c\n", 2, e);
if (IsEmpty(list)) {
printf("线性表为空!\n");
} else {
printf("线性表不为空!\n");
}
ListDelete_Sq(&list, 3);
i = LocateElem(list, 'B');
printf("元素B的位置为: %d\n", i);
for (i = 0; i < list.length; i++) {
printf("%c", list.elem[i]); // []运算符返回的是元素值而不是地址
}
ClearList(&list);
DestroyList(&list);
}