引言
无论网上还是课本上对于线性表的定义都是官方且笼统,
而刚刚学习的同学由于知识储备的欠缺,无法很快理解到线性表的本质,
这篇文章会由浅到深讲解线性表,
希望由笔者的一些引导帮助刚刚接触编程的同学
线性表
线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。(这个定义是网上和书本上很常见的定义,但很多初次接触线性表的同学肯定是一头雾水!!)
而我们需要在官方定义上加上自己的理解。
内存
首先:我们都知道数据是储存在电脑的内存中,而电脑的内存我们可以理解是一块无限线性的单元格。
如下图所示:
但是我们无法直接对储存在内存中的数据进行很好的管理,这时候线性表就出现了。
线性表定义中的 “数据元素的有限序列”,是指人为指定开辟一段空间为我们使用,是不可控的内
实现了可控化。
根据是否可以随着需要的变化,改变提前开辟的内存的大小,把线性表分为静态和动态线性表。
静态线性表
静态线性表是以数组为主,提前申请一段空间,这段空间在程序运行时不可改变大小。
#define Capacity 10 //表示线性表的最大容量
typedef struct
{
int data[Capacity]; //数组存放数据元素
int size; //表示数组中储存了多少数据
}SqList;
上面是静态线性表的C语言实现方式,Capacity 10, 代表了这次线性表一次只能存储10个数据。
size 表示了当前有多少个数据。只要size<Capacity 说明这段线性表还有空间可以储存数据。
下面是初始化线性表:
void SeqListInit1(Seqlist* ps) //初始化线性表
{
for (int i = 0; i < Capacity; i++)
{
ps->data[i] = 0; //将所有元素赋值为0
}
ps->size = 0; //已存数据为0
}
上面代码完成了线性表的初始化,数组元素为0,数组已存数据为0;
下面实现数据的插入:
void SeqListPushBack(SL* ps, int x) //从头开始插入数据
{
if (ps->size < Capacity)
{
ps->data[ps->size] = x;
ps->size++;
}
else
{
printf("The capacity of SeqList is insufficient");
exit(0);
}
}
if (ps->size < Capacity),判断是否还有空间容量,放入数据。
下面实现了线性表的数据删除:
void SeqListPopDelete(SL* ps) //从头开始删除数据
{
int begin = 0;
while (begin < ps->size)
{
ps->data[begin] = ps->data[begin + 1];
begin++;
}
ps->data[begin-1] = 0;
}
从头部开始删除数据,之后将数组中的所以数据,向前移动一位。
上面完成了静态线性表的基本操作(初始化、添加、删除数据),但是会发现静态线性表具有很大的
一旦数据总量超过了数据的大小,则将无法添加数据。
而动态线性表弥补了静态线性表的上述缺点。
动态线性表
动态线性表和动态线性表的最大不同点,在于定义结构体的时候,用指针代替了数组。
动态线性表的定义:
typedef struct Seqlist
{
int* List;
int size; //表示数组中储存了多少数据
int capacity; //数据的容量
}SL;
动态线性表主要由三个要素组成,
指针(List):用于线性表中数据的检索;
size:表示线性表中有效数据的个数;
capacity:表示线性表容量。
而动态线性表的 “动态”体现在什么地方呢? “动态” 体现在根据数据个数的变化,通过relloc 函数增
加线性表的容量。
对动态线性表的初始化:
void SeqListInit(SL* ps)
{
ps->a = NULL;
ps->size = ps->capacity = 0;
}
对于动态线性表,给定一段初始的空间
void SeqListChackCapacity(SL* ps)
{
//判断容量是否为0
if (ps->size == ps->capacity)
{
//三目运算符,如果==0,赋值4,
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
//分配ps->capacity个空间
int* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(int));
if (NULL == tmp)
{
printf("realloc failed\n");
exit(-1);
}
ps->a = tmp;
ps->capacity = newcapacity;
}
在分配容量之前,需要判断线性表是否还有有效空间,否则需要对线性表进行原容量两倍扩容,
这就是动态线性表相对了静态线性表的高明之处了,只要线性表容量满了,则会自动对原容量进
行两倍的扩容,完美的解决了容量不足的问题!
添加数据
//添加数据
void SeqListPushBack(SL* ps, int x)
{
SeqListChackCapacity(ps);
ps->a[ps->size] = x;
ps->size++;
}
添加数据之前需要判断线性表是否需要扩容,将 数据 x 添加到线性表中,每次添加一个数据,线
性表的有效数据+1;
删除数据
//从尾部删除数据
void DeletList(SL* ps)
{
if (ps->size > 0)
{
ps->size--;
}
}
线性表的删除数据就显得比较容易了,将有效数据-1,则完成了数据的删除。