数据结构基础篇-线性结构的顺序存储

576 阅读4分钟

数据结构系列篇章-可以参照如下顺序阅读

0.非空线性表和线性结构特征

对于非空的线性表和线性结构,其特点如下:

  • 存在唯一的一个被称作"第一个"的数据元素;
  • 存在唯一的一个被称作"最后一个"的数据元素;
  • 除了第一个之外,结构中的每个数据元素均有⼀个前驱;
  • 除了最后一个之外,结构中的每个数据元素都有一个后继;

1.顺序表的设计

顺序表按照顺序存储结构存储,即最开始分配的内存空间大小固定,无法修改

#define MAXSIZE 100
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int Status; // 状态码
/* ElemType类型根据实际情况而定,这里假设为int */
typedef int ElemType;

//顺序表结构设计
typedef struct {
    ElemType *data; // 顺序表的内存空间
    int length; // 顺序表的长度
}OrderList;

2. 顺序表的初始化

2.1 分析

  • 分配固定大小的内存空间
  • 空表长度初始化为0

2.2 代码实现

// 顺序表的初始化
Status InitOrderList(OrderList *L){
    //  分配大小为 100 * 数据类型的数组空间
    L->data = malloc(sizeof(ElemType) * MAXSIZE);
    // 如果分配失败,就返回错误
    if (L->data == NULL) {
        exit(ERROR);
    }
    // 数组空间初始长度为0
    L->length = 0;
    return OK;
}

3.顺序表的插入操作

3.1 分析

  • 处理超界情况
  • 处理溢出情况
  • 如果不是尾部,那么区间n到尾部的数据都要后移一位
  • 给n位置赋值
  • 顺序表长度+1

3.2 代码实现

// 线性表的插入
// n为插入的位置,e为插入的元素
Status InsertOrderList(OrderList *L, int n, ElemType e){
    // 越界判定
    if (n > L->length+1 || n < 1) {
        return ERROR;
    }
    // 内存溢出判定
    if (L->length == MAXSIZE) {
        return ERROR;
    }
    
    // 如果插入位置不在表尾
    if (n <= L->length) { // 需要对内存位置进行移位
        for (int i = L->length-1; i >= n-1; i--) { // 从最后一位开始,到n的位置 所有元素后移一位
            L->data[i+1] = L->data[i];
        }
    }
    
    // 将n位置的数据填上
    L->data[n-1] = e;
    
    // 长度+1
    ++L->length;
    return OK;
}

3.3 结果预览

4.读取顺序表的值

4.1 分析

  • 处理超界情况
  • 将data[i-1]位置的数据取出

4.2 代码实现

// 3.顺序表的取值
Status ReadValueInOrderList(OrderList *L, int i, ElemType *e){
    // 判断超界情况
    if (i < 1 && i > L->length) return ERROR;
    // 取出 i-1位置的值
    *e = L->data[i-1];
    return OK;
}

4.3 结果预览

5.顺序表的删除

5.1 分析

  • 表空处理
  • 处理超界情况
  • 表尾位置判定,直接删除元素,并且长度减一
  • 中间位置判定,将删除位置元素之后到表尾位置前移一位,长度减一

5.2 代码实现

// 4.顺序表的删除
Status DeleteOrderList(OrderList *L, int n){
    // 表空判定
    if (L->length == 0) {
        return ERROR;
    }
    // 越界判定
    if (n > L->length+1 || n < 1) {
        return ERROR;
    }
    
    // 如果插入位置不在表尾
    if (n <= L->length) { // 需要对内存位置进行移位
        for (int i = n - 1; i <= L->length - 1; i++) { // 从n-1开始,到最后位置 所有元素前移一位
            L->data[i] = L->data[i+1];
        }
    }

    // 长度-1
    --L->length;
    return OK;
}

5.3 结果预览

6. 顺序表的清空

因为顺序表的内存空间是固定的,长度是可变的,所以直接将长度为置为0,就代表顺序表为空

Status ClearOrderList(OrderList *L){
    L->length = 0;
    return OK;
}

7. 判断顺序表是否清空

判断长度即可

Status IsEmptyOrderList(OrderList *L){
    if (L->length == 0) {
        return TRUE;
    }else{
        return FALSE;
    }
}

8. 获取顺序表的长度

获取长度即可

int GetLengthOrderList(OrderList *L){
    return L->length;
}

9. 输出顺序表

按顺序打印数据

Status TravelOrderList(OrderList *L){
    for (int i = 0; i < L->length; i++) {
        printf("%d ",L->data[i]);
    }
    printf("\n");
    return OK;
}

10. 顺序表查找元素并返回位置

10.1 分析

  • 非空判定
  • 顺序查找位置
  • 位置越界判定
  • 返回位置

10.2 代码实现

Status LocateOrderList(OrderList *L, ElemType e, int *locate){
    
    // 非空判定
    if(L->length == 0)return ERROR;
    
    int i;
    for (i = 0; i < L->length; i++) {
        if (L->data[i] == e) {
            break;
        }
    }
    // 没有找到
    if (i >= L->length) {
        return ERROR;
    }
    
    *locate = i+1;
    
    return OK;
}

10.3 结果预览

小结

以上就是关于线性表的顺序存储结构的基本操作,下一篇将会进入线性表的链式存储结构的分析,也就是大家熟悉的链表,敬请期待~~