1. 线性表的顺序存储

顺序表的定义

  • 用一片连续的存储空间存放线性表,也就是逻辑上相邻的元素,在物理地址上也是相邻的
  • 假设线性表L存储的起始位置为 L O C ( A ) LOC(A) LOC(A),每个数据元素占用的内存空间为 s i z e o f ( E l e m T y p e ) \rm sizeof(ElemType) sizeof(ElemType),则存储结构图为
数组下标顺序表内存地址
0 a 1 a_1 a1 L O C ( A ) LOC(A) LOC(A)
1 a 2 a_2 a2 L O C ( A ) + s i z e o f ( E l e m T y p e ) LOC(A)+\rm sizeof(ElemType) LOC(A)+sizeof(ElemType)
⋯ \cdots ⋯ \cdots ⋯ \cdots
i − 1 i-1 i1 a i a_i ai L O C ( A ) + ( i − 1 ) s i z e o f ( E l e m T y p e ) LOC(A)+\rm (i-1)sizeof(ElemType) LOC(A)+(i1)sizeof(ElemType)
⋯ \cdots ⋯ \cdots ⋯ \cdots
n − 1 n-1 n1 a n a_n an L O C ( A ) + ( n − 1 ) s i z e o f ( E l e m T y p e ) LOC(A)+\rm (n-1)sizeof(ElemType) LOC(A)+(n1)sizeof(ElemType)
⋯ \cdots ⋯ \cdots ⋯ \cdots
M a x S i z e − 1 MaxSize-1 MaxSize1 a M a x S i z e a_{MaxSize} aMaxSize L O C ( A ) + ( M a x S i z e − 1 ) s i z e o f ( E l e m T y p e ) LOC(A)+\rm (MaxSize-1)sizeof(ElemType) LOC(A)+(MaxSize1)sizeof(ElemType)

顺序表的基本操作

  • 顺序表在定义数据结构时,有两种方式:
分配内存方式做法优点缺点
静态分配使用数组,最开始就定义一个大小固定的数组运行速度快如果最开始分配的内存太小,则可能不满足问题需求,如果分配内存太大,又可能用不完,造成内存浪费
动态分配定义一个指向目标数据类型的指针,在运行中动态申请内存1需要多少内存,就申请多少内存,最大限度的使内存空间满足需求,并且不造成浪费运行速度可能会慢(如果存储空间不够,将存储空间进行扩展2 时候会消耗时间)一点

静态顺序表的相关操作

  1. 数据结构定义
#define MAX_SIZE 20     //静态顺序表的最大长度

typedef int ElementType;

//静态顺序表
typedef struct Node{
    ElementType Data[MAX_SIZE]; //静态顺序表使用静态数组,长度为最大长度
    int length;                 //数据用来记录目前存入的数据长度
}SeqList;

typedef SeqList* List1;
  1. 顺序表初始化
  • 使用一维数组对顺序表进行初始化
  • 需要检查顺序表存储空间是否足够存下数组中的数据
//静态顺序表相关操作
//1.数据初始化
void Init1(List1 L,ElementType *Data,int Data_Size)
{
    L->length = 0;
    //检查顺序表空间是否足够
    if(Data_Size > MAX_SIZE)
    {
        printf("初始化失败,数据过多,请重试\n");
        return;
    }
    for(int i = 0;i < Data_Size;i++)	//循环语句进行初始化线性表操作
    {
        L->Data[i] = Data[i];
        L->length++;					//这一句放到最后,写一条 L->length = Data_Size 亦可
    }
}
  1. 按位置找到对应的值
  • 要判断给的位置是否符合顺序表的范围
//2.按位置找到对应的值
ElementType Find_Ac_Position(List1 L,int Position)
{
    if(Position < 1 || Position > L->length)	//位置不在顺序表中,直接退出
    {
        printf("输入位置有误,请重新输入\n");
        return -1;
    }
    return L->Data[Position - 1];
}
  1. 按值查找位置
  • 在这里涉及到了查找问题,没有很细节的考虑高效的算法,具体的查找算法在查找章节中具体探究
//3.按值查找位置
int Find_Position(List1 L,ElementType value)
{
    for(int i = 0;i < L->length;i++)
        if(L->Data[i] == value)
            return i + 1;
    return -1;
}
  1. 插入数据
  • 检查位置是否合法
  • 检查顺序表是否已满
//4.插入一个数据
void Insert1(List1 L,ElementType value,int Position)
{
    //检查插入位置的合法性
    if(Position < 1 || Position > L->length + 1)
    {
        printf("插入位置不合法\n");
        return;
    }
    //检查顺序表是否已满
    if(L->length == MAX_SIZE)
    {
        printf("顺序表已满,不可以插入\n");
        return;
    }
    //插入元素
    for(int i = L->length - 1;i >= Position - 1;i--)
        L->Data[i + 1] = L->Data[i];
    L->Data[Position - 1] = value;
    L->length++;
}
  1. 删除数据
  • 检查删除元素的位置是否合法
  • 判断顺序表是否已经是空表
//5.删除一个数据
void Delete1(List1 L,int Position)
{
    //检查删除元素位置的合法性
    if(Position < 1 || Position > L->length)
    {
        printf("删除元素的位置有误,删除失败\n");
        return;
    }
    //检查顺序表是否已经为空
    if(L->length == 0)
    {
        printf("顺序表已空,无法删除元素\n");
        return;
    }
    //删除元素
    for(int i = Position - 1;i < L->length - 1;i++)
        L->Data[i] = L->Data[i + 1];
    L->length--;
}
  1. 打印顺序表
  • 判断顺序表是否为空
//6.打印顺序表
void Print1(List1 L)
{
    //判断顺序表是否为空
    if(L->length == 0)
    {
        printf("顺序表为空\n");
        return;
    }
    //打印
    for(int i = 0;i < L->length;i++)
        printf("%d  ",L->Data[i]);
    printf("\n");
}

动态顺序表的相关操作

  1. 数据结构定义
  • 定义了初始的长度,每次需要扩充,就每次增加扩容的长度,C++中STL的vector的实现规则与此类似
  • 正常情况下,这样做速度很快,但是在遇到需要新增内存空间时,就会耗费时间,因为要新申请一片更大的空间,还要将之前存在的值一起复制到新的存储空间
#define INIT_SIZE 10    //动态顺序表的初始长度
#define INCREASE_SIZE 10    //动态顺序表每次扩容的长度

typedef int ElementType;

//动态顺序表
typedef struct Anode{
    ElementType *Data;          //通过动态分配内存来创建
    int length;                 //目前的长度
    int MaxSize;                //目前的最大容量
}ASeqList;

typedef ASeqList* List2;
  1. 顺序表初始化
  • 使用malloc()函数动态申请内存空间
//动态顺序表相关操作
//1.顺序表初始化
void Init2(List2 L)
{
    L->length = 0;
    L->Data = malloc(sizeof(ElementType)*INIT_SIZE);    //初始化数组
    L->MaxSize = INIT_SIZE;
}
  1. 顺序表扩容
  • 在这里使用了realloc(void *ptr, size_t size)函数进行内存空间扩展
//2.顺序表扩容
void Extend(List2 L)
{
    ElementType* Base = (ElementType*)realloc(L->Data,sizeof(ElementType)*INCREASE_SIZE);
    if(!Base)
        exit(-1);
    L->Data = Base;
    L->MaxSize = L->MaxSize + INCREASE_SIZE;
}
  1. 用数组为顺序表赋值
  • 赋值之前也要判断空间是否足够,如果不够,就扩充空间
//3.用数组为顺序表赋值
void InsertByArray(List2 L,ElementType* Data,int Size)
{
    if(L->MaxSize < Size)
        Extend(L);
    if(Size < 1)
    {
        printf("用于赋值的数组输入无效\n");
        return;
    }
    for(int i = 0;i < Size;i++)
        L->Data[i] = Data[i];
    L->length = Size;
}
  1. 按位置找到对应的值
  • 与静态顺序表类似
//4.按位置找到对应的值
ElementType Find_Ac_Position2(List2 L,int Position)
{
    if(Position < 1 || Position > L->length)
    {
        printf("输入位置有误,请重新输入\n");
        return -1;
    }
    return L->Data[Position - 1];
}
  1. 按值找到对应的位置
  • 与静态顺序表类似
//5.按值查找位置
int Find_Position2(List2 L,ElementType value)
{
    for(int i = 0;i < L->length;i++)
        if(L->Data[i] == value)
            return i + 1;
    return -1;
}
  1. 插入数据
  • 检查位置是否合法
  • 检查顺序表是否已满,满了则扩容
//6.插入一个数据
void Insert2(List2 L,ElementType value,int Position)
{
    //检查插入位置的合法性
    if(Position < 1 || Position > L->length + 1)
    {
        printf("插入位置不合法\n");
        return;
    }
    //检查顺序表是否已满
    if(L->length == L->MaxSize)
    {
        Extend(L);  //扩容
    }
    //插入元素
    for(int i = L->length - 1;i >= Position - 1;i--)
        L->Data[i + 1] = L->Data[i];
    L->Data[Position - 1] = value;
    L->length++;
}
  1. 删除数据
  • 与静态顺序表类似
//7.删除一个数据
void Delete2(List2 L,int Position)
{
    //检查删除元素位置的合法性
    if(Position < 1 || Position > L->length)
    {
        printf("删除元素的位置有误,删除失败\n");
        return;
    }
    //检查顺序表是否已经为空
    if(L->length == 0)
    {
        printf("顺序表已空,无法删除元素\n");
        return;
    }
    //删除元素
    for(int i = Position - 1;i < L->length - 1;i++)
        L->Data[i] = L->Data[i + 1];
    L->length--;
}
  1. 打印顺序表
  • 与静态顺序表类似
//8.打印顺序表
void Print2(List2 L)
{
    //判断顺序表是否为空
    if(L->length == 0)
    {
        printf("顺序表为空\n");
        return;
    }
    //打印
    for(int i = 0;i < L->length;i++)
        printf("%d  ",L->Data[i]);
    printf("\n");
}

主函数

int main()
{
    int Data[6] = {12,23,31,21,18,22};
    printf("-----------静态顺序表操作------------\n");

    printf("\n\n-------------------------------------\n");
    printf("1.初始化顺序表\n");
    List1 L = malloc(sizeof(SeqList));
    Init1(L,Data,6);
    Print1(L);

    printf("\n\n-------------------------------------\n");
    printf("2.按位置找到对应的值\n");
    int value;
    int Position;
    printf("请输入要查找的位置:  ");
    scanf("%d",&Position);
    value = Find_Ac_Position(L,Position);
    if(value != -1)
        printf("第%d位置的值为%d\n",Position,value);

    printf("\n\n-------------------------------------\n");
    printf("3.按值找到对应的位置\n");
    printf("请输入要查询的值:   ");
    scanf("%d",&value);
    Position = Find_Position(L,value);
    if(Position == -1)
        printf("没有这个值\n");
    else
        printf("%d在顺序表的第%d个位置\n",value,Position);

    printf("\n\n-------------------------------------\n");
    printf("4.插入一个值\n");
    printf("请输入要插入的值:   ");
    scanf("%d",&value);
    printf("请输入要插入的位置:  ");
    scanf("%d",&Position);
    Insert1(L,value,Position);
    printf("插入数据后的顺序表\n");
    Print1(L);

    printf("\n\n-------------------------------------\n");
    printf("5.删除一个值\n");
    printf("请输入要删除的值的位置:    ");
    scanf("%d",&Position);
    Delete1(L,Position);
    printf("删除数据后的顺序表\n");
    Print1(L);


    printf("-----------动态顺序表操作------------\n");
    int Data1[10] = {12,23,31,21,18,22,11,9,14,25};
    printf("\n\n-------------------------------------\n");
    printf("1.初始化顺序表\n");
    List2 L2 = malloc(sizeof(ASeqList));
    Init2(L2);
    InsertByArray(L2,Data1,10);
    Print2(L2);

    printf("\n\n-------------------------------------\n");
    printf("2.按位置找到对应的值\n");
    printf("请输入要查找的位置:  ");
    scanf("%d",&Position);
    value = Find_Ac_Position2(L2,Position);
    if(value != -1)
        printf("第%d位置的值为%d\n",Position,value);

    printf("\n\n-------------------------------------\n");
    printf("3.按值找到对应的位置\n");
    printf("请输入要查询的值:   ");
    scanf("%d",&value);
    Position = Find_Position2(L2,value);
    if(Position == -1)
        printf("没有这个值\n");
    else
        printf("%d在顺序表的第%d个位置\n",value,Position);

    printf("\n\n-------------------------------------\n");
    printf("4.插入一个值\n");
    printf("请输入要插入的值:   ");
    scanf("%d",&value);
    printf("请输入要插入的位置:  ");
    scanf("%d",&Position);
    Insert2(L2,value,Position);
    printf("插入数据后的顺序表\n");
    Print2(L2);

    printf("\n\n-------------------------------------\n");
    printf("5.删除一个值\n");
    printf("请输入要删除的值的位置:    ");
    scanf("%d",&Position);
    Delete2(L2,Position);
    printf("删除数据后的顺序表\n");
    Print2(L2);

    return 0;
}

程序运行结果

  • 静态顺序表
    在这里插入图片描述
  • 动态顺序表
    在这里插入图片描述

全部代码下载链接:https://download.csdn.net/download/qq_43655213/12696029

参考文献

[1] 严蔚敏,吴伟民. 数据结构 (C语言版 ) [M]. 北京:清华大学出版社, 2011-07-01;
[2] 王道论坛,2021年数据结构考研复习指导[M]. 北京:电子工业出版社,2020.1


  1. 动态申请内存:在C语言中,可以使用malloc(sizeof(ElemType))函数,在C++中,可以直接使用new函数 ↩︎

  2. 扩展内存空间:在C语言中,使用realloc(Ptr,sizeof(ElemType))函数进行内存空间扩展 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值