线性表的顺序表示

〇、顺序表定义

用一组地址连续的存储单元一次存储线性表的数据元素。特点是:逻辑上相邻的数据元素,其物理次序也是相邻的。

一、顺序表的存储结构

C/C++ 中常用数组来描述数据结构中的顺序存储结构,由于线性表的长度可变,且所需的最大存储空间随问题不同而不同,则可以用动态分配的一维数组表示线性表,如下所示

#define MAXSIZE 100      //顺序表可能达到的最大长度
typedef struct
{
    ElemType* elem;      //存储空间的基地址
    int length;          //当前长度
}SqList;

其中Elemtype是为了描述统一而自定的抽象数据类型,具体如下所示:

1.1 表示稀疏多项式数据

#define MAXSIZE 100
typedef struct    //多项式中非零项的定义
{
    float coef;   //系数
    int expn;     //指数
}Polynomial;

typedef struct
{
    Polynomial* elem;      //存储空间的基地址
    int length;          //多项式中的项数
}SqList;

1.2 表示图书馆的书籍

#define MAXSIZE 50000    //能记录的最多种类数
typedef struct          //图书信息的定义 
{
    char ISBN[20];      //ISBN号码
    char name[50];      //书名
    float price;        //书的价格
}Book;

typedef struct
{
    Book* elem;         //存储空间的基地址
    unsigned int length;//当前图书总数
}SqList;

二、基本操作的实现

2.0 先声明一些状态

后面直接使用,不再加以说明

#define Status int

enum MyStatus
{
    ERROR = 0,\
    OK    = 1,\
    FALSE = 0,\
    TURE  = 1
};

2.1 初始化

顺序表的初始化就是构建一个空的顺序表

2.1.1 算法步骤
  1. 为顺序表L分配一个预定义大小的数组空间,使elem指向这段空间的基地址
  2. 将表的当前长度设置为0
2.1.2 算法实现
/*顺序表的初始化*/
Status InitList(SqList* L)            //构建一个空的顺序表L
{
    L -> elem = new ElemType(MAXSIZE); //为其分配一个大小为MAXSIZE的内存空间
    L->length = 0;                   //空表长度为0
    return OK;                       //成功返回OK
    if (! L->elem)
    {
        return ERROR;                //如果分配失败返回ERROR
    }
}

2.2 取值

取值操作就是根据指定的位置序号i,获取顺序表中的第i个数据元素的值。由于顺序存储结构具有随机存取的特点,可以直接通过数组下标定位得到,我们可以知道,数组elem[i - 1]单元存储第i个数据元素。

2.2.1 算法步骤
  1. 判断指定的位置序号i值是否合理(1 ≤ i ≤ L.length),若不合理则返回ERROR
  2. i合理,则将第i个元素L.elem[i - 1]赋给参数e,通过e返回第i个数据元素的传值
2.2.2 算法实现
/*顺序表的取值*/
Status GetElem(SqList L, const int* i, ElemType* e)
{
    if (*i < 1 || *i > L.length)  //判断i是否合理
    {
        return ERROR;
    }
    else
    {
        *e = L.elem[(*i) - 1];    //取第i个值 
        return OK;
    }
}
2.2.3 复杂度分析

顺序表取值算法的时间复杂度为O(1)

2.3 查找

查找操作就是根据指定的元素e,找出顺序表中第一个e相等的元素。若查找成功,则读出该元素在表中的位置序号传给num;否则返回ERROR

2.3.1 算法步骤
  1. 对元素进行遍历,如果找到与e相等的元素,将其序号传给num
  2. 若没找到,返回ERROR
2.3.2 算法实现
/*顺序表的查找*/
Status LocateElem(SqList L, const ElemType* e, int* num)
{
    *num = 0;
    for (int i = 0; i < L.length; i++)//遍历
    {
        if (*e == L.elem[i])
        {
            *num = i + 1;            //查找到将位置传递出去
        }
    }
    return !(*num) ? OK : ERROR;      //返回状态值
}
2.3.3 复杂度分析

顺序表查找算法的时间复杂度为O(n)

2.4 插入

顺序表的插入操作是指在表的第i个位置插入一个新的数据元素e,使长度为L.length的顺序表变为长度为L.length + 1的顺序表

2.4.1 算法步骤
  1. 判断插入位置i是否合法(1 ≤ i ≤ L.length + 1),若不合法则返回ERROR
  2. 判断顺序表的存储空间是否已满,若满则返回ERROR
  3. 将第i到第L.length个元素向右移动一个位置,空出第i个位置(iL.length + 1时不用移动)
  4. 将要插入的新元素e放入第i个位置
  5. 顺序表的长度L.length1
2.4.2 算法实现
/*顺序表的插入*/
Status ListInsert(SqList* L, const int* i, const ElemType* e)
{
    if (L->length == MAXSIZE || (*i) < 1 || (*i) > L->length + 1)
    {//已经没有存储空间或i的值不合法
        return ERROR;
    }
    else
    {
        if ((*i) == L->length + 1)     //i在表尾
        {
            L->elem[L->length] = *e;//直接放入表尾
        }
        else//i合法且不在表尾
        {
            for (int j = L->length - 1; j >= i - 1; j--)
            {//第i个元素开始全部后移动
                L->elem[j + 1] = L->elem[j];
            }
            L->elem[(*i) - 1] = *e;   //插入
        }
        L->length++;
        return OK;
    }
}
2.4.3 复杂度分析

顺序表插入算法的时间复杂度为O(n)

2.5 删除

顺序表的删除操作是指在表的第i个位置删除一个数据元素e,使长度为L.length的顺序表变为长度为L.length - 1的顺序表

2.5.1 算法步骤
  1. 判断i是否合法(1 ≤ i ≤ L.length),若不合法则返回ERROR
  2. 读出这个数据元素e
  3. 将顺序表第i + 1到第L.length个元素向左移动一个位置,覆盖i个位置的元素(iL.length时不用移动)
  4. 顺序表的长度L.length1
2.5.2 算法实现
/*顺序表的删除*/
Status ListDelete(SqList* L, const int* i, ElemType* e)
{
    if ((*i) < 1 || (*i) > L->length)//i的值非法
    {
        return ERROR;
    }
    else
    {
        *e = L->elem[(*i) - 1];//取出第i个值
        for (int j = (*i); j < L->length - 1; j++)
        {//第i个值以后的元素均向前移一位
            L->elem[j - 1] = L->elem[j];
        }
        L->length--;//长度减一
        return OK;
    }
}
2.5.3 复杂度分析

顺序表删除算法的时间复杂度为O(n)

三、顺序表的优劣

3.1 优点

  • 逻辑结构和物理结构相关联,无需为表示元素间的逻辑关系增加额外的代码量和储存空间
  • 可以快速存取某一位置的元素

3.2 缺点

  • 插入和删除操作需要移动大量的元素
  • 线性表长度变化很大时难以确定储存空间的容量
  • 容易造成物理存储空间的碎片化

四、测试

4.1 测试要求

  1. 创建一个内存为10的顺序表
  2. 对其赋8个值,分别为 10 28 36 15 20 11 5 3
  3. 取出第4个值并打印出来
  4. 打印出11的位置
  5. 在第5元素后插入22,打印出插入后的顺序表
  6. 删除第2个元素并打印出其值以及删除后的顺序表
  7. 删除整个顺序表

4.2测试代码

以C语言为主,代码稍微有那么点点长

#include <iostream>
#include <malloc.h>

using namespace std;

#define MAXSIZE 10 //顺序表可能达到的最大长度
#define ElemType int
#define Status int

enum MyStatus
{
    ERROR = 0, \
    OK = 1, \
    FALSE = 0, \
    TURE = 1
};

/***顺序表的存储结构***/
typedef struct
{
    ElemType* elem;      //存储空间的基地址
    int length;          //当前长度
}SqList;
SqList List;
/*顺序表的初始化*/
Status InitList(SqList* L);
/*顺序表的取值*/
Status GetElem(SqList L, const int* i, ElemType* e);
/*顺序表的查找*/
Status LocateElem(SqList L, const ElemType* e, int* num);
/*顺序表的插入*/
Status ListInsert(SqList* L, const int* i, const ElemType* e);
/*顺序表的删除*/
Status ListDelete(SqList* L, const int* i, ElemType* e);
//输出线性表
void print(SqList* L);
//空线性表赋值
Status ConfigList(SqList* L, int i);
/*顺序表的删除*/
Status Delete(SqList* L);

int main(void)
{
    cout << "正在创建顺序表\n";
    int flag = InitList(&List);
    if (flag)
    {
        cout << "顺序表创建完毕" << "请进行赋值" << endl;
    }

    for (int i = 0; i < 8; i++)
    {
        flag = ConfigList(&List, i);
    }
    if (flag)
    {
        cout << "\n赋值完毕,当前顺序表中的内容为:  ";
        print(&List);
    }

    int temp = 4;
    ElemType e;
    flag = GetElem(List, &temp, &e);
    if (flag)
    {
        cout << "读取成功:第4个值为" << e << endl;
    }
    else
    {
        cout << "读取失败" << endl;
    }

    e = 11;
    int num;
    flag = LocateElem(List, &e, &num);
    if (flag)
    {
        cout << "查找成功,第: " << num << "个值为11" << endl << endl;
    }
    else
    {
        cout << "查找失败" << endl;
    }
    
    temp = 5;
    e = 22;
    flag = ListInsert(&List, &temp, &e);
    if (flag)
    {
        cout << "在第5元素前插入22后的顺序表为:";
        print(&List);
    }
    else
    {
        cout << "插入失败" << endl;
    }
    

    temp = 2;
    flag = ListDelete(&List, &temp, &e);
    if (flag)
    {
        cout << "删除成功,删除的元素为:" << e << endl << "成功删除第2个元素后的顺序表为:";
        print(&List);
    }
    else
    {
        cout << "删除元素失败" << endl;
    }

    flag = Delete(&List);
    if (flag)
    {
        cout << "顺序表已删除" << endl;
    }
    else
    {
        cout << "删除顺序表失败" << endl;
    }
    return 0;
}


/*顺序表的初始化*/
Status InitList(SqList* L)            //构建一个空的顺序表L
{
    //为其分配内存
    L->elem = (ElemType*)malloc(sizeof(ElemType) * MAXSIZE);
    L->length = 0;                   //空表长度为0
    return OK;                       //成功返回OK
    if (!L->elem)
    {
        return ERROR;                //如果分配失败返回ERROR
    }
}

/*顺序表的取值*/
Status GetElem(SqList L, const int* i, ElemType* e)
{
    if (*i < 1 || *i > L.length)  //判断i是否合理
    {
        return ERROR;
    }
    else
    {
        *e = L.elem[(*i) - 1];    //取第i个值 
        return OK;
    }
}

/*顺序表的查找*/
Status LocateElem(SqList L, const ElemType* e, int* num)
{
    *num = 0;
    for (int i = 0; i < L.length; i++)//遍历
    {
        if (*e == L.elem[i])
        {
            *num = i + 1;            //查找到将位置传递出去
            return OK;
        }
    }
    return ERROR;                   
}

/*顺序表的插入*/
Status ListInsert(SqList* L, const int* i, const ElemType* e)
{
    if (L->length == MAXSIZE || (*i) < 1 || (*i) > L->length + 1)
    {                             //已经没有存储空间或i的值不合法
        return ERROR;
    }
    else
    {
        if ((*i) == L->length + 1)     //i在表尾
        {
            L->elem[L->length] = *e;//直接放入表尾
        }
        else                      //i合法且不在表尾
        {
            for (int j = L->length - 1; j >= (*i) - 1; j--)
            {                    //第i个元素开始全部后移动
                L->elem[j + 1] = L->elem[j];
            }
            L->elem[(*i) - 1] = *e;   //插入
        }
        L->length++;
        return OK;
    }
}

/*顺序表的删除*/
Status ListDelete(SqList* L, const int* i, ElemType* e)
{
    if ((*i) < 1 || (*i) > L->length)//i的值非法
    {
        return ERROR;
    }
    else
    {
        *e = L->elem[(*i) - 1];//取出第i个值
        for (int j = (*i); j < L->length; j++)
        {//第i个值以后的元素均向前移一位
            L->elem[j - 1] = L->elem[j];
        }
        L->length--;//长度减一
        return OK;
    }
}

//输出线性表元素
void print(SqList* L) {
    for (int i = 0; i < L->length; i++)
    {
        cout << L->elem[i] << "  ";
    }
    cout << "共" << L->length << "个元素\n\n";
}

//空线性表赋值
Status ConfigList(SqList* L, int i)
{
    ElemType scanfnum;
    cin >> scanfnum;
    L->elem[i] = scanfnum;
    L->length++;
    return OK;
}

/*顺序表的删除*/
Status Delete(SqList* L)   //删除顺序表L
{
    free(L->elem);         //释放内存
    L->elem = NULL;
    L->length = 0;         //长度置为0
    if (! L->elem)
    {
        return OK;         //成功
    }
    return ERROR;          //失败
}

4.3 测试结果

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值