C语言丨线性表(一):顺序表

线性表是由数据类型相同n\left ( n\geq 0 \right )个数据元素组成的有限序列,通常记为:

\left ( a_{1},a_{2},\cdots ,a_{i-1},a_{i},a_{i+1},\cdots ,a_{n} \right )

其中n为表长,n=0时称为空表;下标i表示数据元素的位序

线性表的特点是组成它的数据元素之间是一种线性关系,即数据元素“一个接在另一个的后面排列,每一个数据元素的前面和后面都至多有一个其他数据元素”。

本文在介绍线性表的基本概念的基础上,重点介绍线性表的顺序表示及相应的算法


定义

线性表的顺序存储结构是指用一组地址连续(存储空间紧邻)的存储单元依次存储线性表的数据元素,用这种形式存储的线性表称为顺序表,因此顺序表的逻辑顺序和物理顺序是一致的,线性表中各个数据元素之间的逻辑关系可以由它们的存储地址来实现。

地址关系

设每个数据元素占据的存储块包括c个存储单元,则第一个存储地址通常称为该数据元素的地址。a_{i}的地址用Loc\left ( a_{i} \right )表示,则第i+1个数据元素的地址为:

Loc\left ( a_{i+1} \right )=Loc\left ( a_{i} \right )+c      1\leq i\leq n

数据元素a_{1}的地址通常称为线性表的基地址。很显然有:

Loc\left ( a_{i} \right )=Loc\left ( a_{1} \right )+\left ( i-1 \right )\times c

基本类型

(1)一维数组

一维数组在内存中占用的存储空间就是一组连续的存储区域,因此顺序表可以用一维数组来表示。但由于线性表有插入、删除等运算,它的长度是可变的,所以一维数组的长度需要定义得足够大,设用elem[MAXSIZE]来表示,其中MAXSIZE是一个根据实际问题定义的足够大的整数。此外,当前线性表中的实际元素个数可能达不到MAXSIZE那么多个,因此需要用一个变量length记录当前线性表中最后一个元素在数组中的位置,表空时length=0。例如:

#define MAXSIZE 100
DataType elem[MAXSIZE];
int length;

(2)动态数组

由于线性表所需的最大存储空间不容易确定,通常可以使用动态分配的一维数组来存储线性表。因此通常可以定义如下的结构来表示一个顺序表类型。

typedef struct
{
    DataType *elem;/*线性表的基地址*/
    int length;/*线性表当前的长度*/
    int listsize;/*线性表当前分配的最大存储容量*/
} SeqList;

1.初始化

顺序表的初始化即构造一个空表,用MAXSIZE表示最初分配给线性表的顺序存储空间的大小。

int InitSeqList(SeqList *L)
{
    L->elem = (DataType *)malloc(MAXSIZE * sizeof(DataType));
    if (L->elem == NULL)
    {
        printf("error!\n");
        exit (-1);
    }
    L->length = 0;/*此时顺序表为空表*/
    L->listsize = MAXSIZE;
    return OK;
}

2.插入运算

顺序表的插入是指在序号为i的元素前面插入一个值为x的新元素,成为新的第i个元素。顺序表的插入运算的步骤如下:

(1)将a_{n}\sim a_{i}顺序向后移动,以空出第i个元素的位置。

(2)将x置入空出的位置。

(3)修改顺序表的长度。

int InsertSeqList(SeqList *L, int i, DataType x)
{
    int j;
    if (L->length == L->listsize)
    {
        printf("顺序表已满!");
        return (-1);
    }/*顺序表已满,不能插入*/
    else if (i<1 || i>L->length+1)
    {
        printf("位置不合法!");
        return (0);
    }
    else
    {
        for (j=L->length; j>=i; j--)
        {
            L->elem[j+1] = L->elem[j];
            L->elem[i] = x;/*新元素插入*/
            L->length++;/*表长加1*/
            return (1);/*插入成功,返回*/
        }
    }
}

若要通过不断插入来建立顺序表,只需在顺序表末端依次插入新元素即可。当输入非法字符或顺序表已满时,结束插入。

void SetSeqList(SeqList *L)
{
    int ret;
    while (L->length <= L->listsize)
    {
        ret = scanf("DataType的格式转换符", &L->elem[L->length+1]);
        if (ret == 1)
        {
            L->length++;
        }
        else//通过输入非法字符来结束插入
        {
            break;
        }
    }
    return;
}

3.删除运算

顺序表的删除运算是指将表中第i个元素从顺序表中去掉。顺序表的删除运算的步骤如下:

(1)将a_{i+1}\sim a_{n}顺序向上移动。

(2)修改表长。

int DeleteSeqList(SeqList *L, int i)
{
    int j;
    if(i<1 || i>L->length)/*检查删除位置的合法性*/
    {
        printf("不存在第%d个元素", i);
        return 0;
    }
    else
    {
        for (j=i; j<=L->length; j++)/*向上顺序移动元素*/
        {
            L->elem[j] = L->elem[j+1];
        }
    }
    L->length--;/*表长减1*/
    return (1);
}

4.按值查找

顺序表中的按值查找是指在线性表中查找与给定值x相等的数据元素。在顺序表中完成该运算最简单的方法是线性查找法(顺序查找法)。

int SearchSeqList(SeqList *L, DataType x)
{
    int j = 1;
    while (j<=L->length && L->elem[j]!=x)
    {
        j++;
    }
    if (j>L->length)
    {
        return (-1);
    }
    else
    {
        return j;
    }
}

效率更高的办法还有折半查找(对分搜索)。现把我之前介绍过的这两种方法的文章链接给出如下:C语言丨线性查找(顺序查找)C语言丨折半查找(对分搜索)


可以证明,顺序表插入、删除、查找算法的时间复杂度都为O\left ( n \right )


参考文献:

文益民 张瑞霞 李健 编著,数据结构与算法(第2版),清华大学出版社,P18,P20-24.

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值