数据结构 2-线性表

本文详细介绍了线性表的概念、物理结构和抽象数据类型,重点讲解了顺序存储结构(包括初始化、显示、获取、定位、插入和删除元素)以及链式存储结构,特别是单链表的创建、显示、插入和删除操作。同时对比了两种存储结构的优缺点,强调了顺序存储适合数据稳定、不常插入删除,链式存储适合频繁插入删除的场景。
摘要由CSDN通过智能技术生成

线性表

基础

线性表:由零个或者多个数据元素组成的有限序列

  • 线性表是一个序列,多个元素先来后到
  • 若元素存在多个,则第一个元素无前驱,最后一个元素无后继,其他元素有且只有一个前驱和后继
  • 线性表是有限的

🎨如果用数学语言来进行定义,例如将线性表的元素表示为:
(a1,a2.......a(i-1), ai, a(i+1),.......an
其中ai-1领先于ai,ai领先于a(i+1),称a(i-1)为ai的直接前驱元素,a(i+1)是ai的直接后继元素

线性表的元素个数n(n>=0)定义为线性表的长度,当长度n=0时,称为空表

例如下图表示了典型的线性表:
在这里插入图片描述
🎨线性表的抽象数据类型:

ADT 线性表(List)
数据对象:D={
   ai | ai ∈ ElemSet, i = 1, 2, 3..., n, n >= 0}
数据关系:R={
   <a(i-1), ai> | a(i-1), ai ∈ D, i = 2, .... n }
基本操作:
	InitList(&L)
	操作结果:构建一个空的线性表L
	DestroyList(&L)
	初始条件:线性表L已存在
	操作结果:销毁线性表L
	ClearList(&L)
	初始条件:线性表L已存在
	操作结果:销毁线性表L
	ListEmpty(L)
	初始条件:线性表L以及存在
	操作结果:若L为空表,返回true,否则返回false
	ListLength(L)
	初始条件:线性表L已存在
	操作结果:返回L中数据元素的个数
	GetElem(L, i, &e)
	初始条件:线性表L已存在,且 1 <= i <= ListLength(L)
	操作结果:用e返回L中第i个元素
	LocateElem(L, e)
	初始条件:线性表L已存在
	操作结果:返回L中第1个值与e相同的元素在L中的位置。这样的值不存在返回0
	PriorElem(L, cur_e, &pre_e)
	初始条件:线性表L已存在
	操作结果:若cur_e是L的数据元素,且不是第一个,用pre_e返回其前驱,否则操作失败,pre_e无定义
	NextElem(L, cur_e, &next_e)
	初始条件:线性表L已存在
	操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回其后继,否则操作失败,next_e无定义
	ListInsert(&L, i, e)
	初始条件:线性表L已存在
	操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1
	ListDelete(&L, i, *e)
	初始条件:线性表L已存在
	操作结果:删除L的第i个数据元素,L的长度减1
	TraverseList(L)
	初始条件:线性表L已存在
	操作结果:对线性表L进行遍历,在遍历过程中对L的每个结点访问一次
end ADT

线性表的物理结构:

顺序存储结构

顺序存储结构的封装需要三个属性:

  • 存储空间的起始位置,数组data, 它的存储位置就是线性表存储空间的起始位置
  • 线性表大最大存储容量:数组的容量MAX_SIZE
  • 线性表的当前长度:length

🏁地址计算方法:
假设ElemType占用的是c个存储单位(字节)

那么顺序表中第i+1个数据元素和第i个数据元素的存储位置的关系是(LOC表示获得存储位置的函数):
LOC(a( i + 1 ) ) = LOC(a ( i ) ) + c
而顺序表中第i个元素的存储位置可以由a1的位置推算出:
LOC(a ( i ) ) = LOC( a1 ) + ( i -1 ) * c
在这里插入图片描述
🏀C语言实现

初始化

我们以学生表为例,其具体数据结构如下:

名称 成员变量
学号 no
姓名 name
年龄 age

然后我们通过结构体建立学生类型作为ElemType,名为Student

#define MAXSIZE 10
typedef struct {
   
    char no[10]; //编号
    char name[50]; //姓名
    int age; //年龄
} Student;

然后在此基础上实现,一个顺序表类型SqList,存储一个学生类型的数组和顺序表长度:

typedef struct {
   
    Student data[MAXSIZE]; //顺序表的数据
    int length; //顺序表的长度
} SqList;

通过以下代码初始化这个顺序表(放置在主函数main()中:

初始化5个学生的信息和一个空的顺序表,然后给顺序表依次赋值并更新长度:

	Student stu1 = {
   "2020001", "Yuri", 22};
    Student stu2 = {
   "2020002", "Alice", 22};
    Student stu3 = {
   "2020003", "LiLi", 17};
    Student stu4 = {
   "2020004", "Steve", 3};
    Student stu5 = {
   "2020005", "Bill", 65};
    Student stu6 = {
   "2020007", "Kiss", 65};
    Student stu7 = {
   "2020010", "Tim", 58};
    SqList sqList;
    sqList.length = 5;
    sqList.data[0] = stu1;
    sqList.data[1] = stu2;
    sqList.data[2] = stu3;
    sqList.data[3] = stu4;
    sqList.data[4] = stu5;
显示

打印输出元素和顺序表的信息也是很重要的一个功能,我们通过遍历和取址完成:

/**
 * 打印顺序表
 * @param L 顺序表
 */
void PrintList(SqList L) {
   
    printf("*********\n");
    for (int i = 0; i < L.length; ++i) {
   
        printf("编号:%d 学号:%s 姓名:%s 年龄:%d\n", i + 1, L.data[i].no, L.data[i].name, L.data[i].age);
    }
    printf("*********\n");
}
/**
 * 打印元素
 * @param e
 */
void PrintElem(Student e){
   
    printf("学号:%s 姓名:%s 年龄:%d\n",  e.no, e.name, e.age);

}

初始化完成后的顺序表数据如下:

编号:1 学号:2020001 姓名:Yuri 年龄:22
编号:2 学号:2020002 姓名:Alice 年龄:22
编号:3 学号:2020003 姓名:LiLi 年龄:17
编号:4 学号:2020004 姓名:Steve 年龄:3
编号:5 学号:2020005 姓名:Bill 年龄:65
获取、定位元素

实现GetElem的具体操作,只需要把线性表L第 i 个下标的值返回即可:

/**
 * 取值
 * @param L 顺序表的拷贝
 * @param i 要查找元素的下标
 * @param e 新的学生指针
 * @return
 */
int GetElem(SqList L, int i, Student *e) {
   
    int len = L.length;
    if (i >= len || i < 0) {
   
        return -1; //下标不合理
    }
    *e = L.data[i]; //将i处学生的地址赋给指针
}

使用这个方法

 GetElem(sqList, 3, &newStu)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值