数据结构[顺序表]

文章目录

      • (1)线性表
      • (2)顺序表概念
            • 1.顺序表结构
            • 2.增删查改操作的接口实现
            • 顺表表结构定义
            • 顺序表的初始化
            • 顺序表的尾插
            • 顺序表的头插
            • 顺序表的尾删
            • 顺序表的头删
            • 顺序表的任意出插入
            • 顺序表的任意出删除
            • 顺序表空间的释放
            • 3.顺序表优势和缺点

(1)线性表

线性表是一个具有n个相同元素类型的有序系列。 常见的线性表有:顺序表,链表,队列,栈…
线性表的划定:在逻辑上是线性的,物理结构上可以不是连续的。

(2)顺序表概念

  1. 顺序表是一个线性表,在逻辑是线性的,物理结构上也是连续的。
1.顺序表结构
  1. 顺序表的底层就是通过数组来实现的。
    在这里插入图片描述
2.增删查改操作的接口实现
顺表表结构定义

1.顺序表可分为静态顺序表动态顺序表

静态顺序表:数组元素个数是一个固定值,使用定长数组来存储数据

typedef struct SeList
{
	int a[100];
	int size;//记录有效数据个数
}SL;

动态顺表表:动态开辟空间来存放数据

typedef int SLDataType;
typedef struct SeList
{
	SLDataType *a;
	int size;//记录有效数据个数
	int capacity;//记录开辟数组空间的总数
}SL;
  • 这里使用动态顺序表结构实现
顺序表的初始化

顺序表的初始化,是现在测试函数中或主函数中创建一个结构体(顺序表)变量,封装一个函数进行初始化。
直接在测试函数中或主函数中创建位置处初始化也是可以。代码是灵活的。
封装一个函数以后以后实现初始化操作比较方便

这里来封装一个顺序表初始化函数

//想要改变外面函数的变量需要外面函数的地址才能修改,所以参数是一个(顺序表)结构体的指针


void SeListInit(SL* p)
{
	p->a = NULL;//这里也可以直接开辟空间
	p->size = p->capacity = 0;
}
顺序表的尾插
  • 顺序表底层实现通过数组来实现的,那么尾插就是在数组下标位置的后面插入(输入)一个数据。
  • 数据结构[顺序表]_第1张图片
void SeListPushBack(SL* p)
{	
这里传过来的指针一定不能为空,因为要使用开辟的数组
	assert(p);
//插入之前,判断够不够空间存入数据
if(p->size==p->capacity)
{	

//这里要判断一下p->capacity的值是否为0,为0*2还是0,就没有办法开辟空间
	int newcapacity = p->capacity==0?4:capacity*2;
	SLDataType * temp = (SLDataType*)recalloc(sizeof(SLDataType)*newcapacity)
	//判断是否为NULL
	if(temp==NULL)
	{
		perror("recalloc faile");
	}
	//此时开辟空间成功,要接收开辟新开辟空间的指针赋值给结构体中的成员
	SLDataType * a =temp;
	temp = NULL;
	p->capacity = newcapacity;
}
//此时有足够空间扩容
p->a[p->size++] = x;

顺序表的头插

顺序表的头插就是将每一个数据移动一位,这是第一个位置插入数据就不会影响顺序表的数据了。

头插操作,数组元素的后移
数据结构[顺序表]_第2张图片
注意在结构体中定义的size初始值为0,在插入数据之后,他会到有效数据的下一位置。
数据结构[顺序表]_第3张图片

void SeListFront(SL* p)
{
	assert(p);
//判断是否需要扩容 这里的扩容操作不止一个函数使用
//把扩容操作封装一个函数,方便使用
	SLCheckCapacity(p);
	for(int i = p->size ; i>0 ; i--)
	{
		p->a[i-1]=p->[i];
	}
	
}

扩容:

void SLCheckCapacity(SL* p)
{if(p->size==p->capacity)
{	

//这里要判断一下p->capacity的值是否为0,为0*2还是0,就没有办法开辟空间
	int newcapacity = p->capacity==0?4:capacity*2;
	SLDataType * temp = (SLDataType*)recalloc(sizeof(SLDataType)*newcapacity)
	//判断是否为NULL
	if(temp==NULL)
	{
		perror("recalloc faile");
	}
	//此时开辟空间成功,要接收开辟新开辟空间的指针赋值给结构体中的成员
	SLDataType * a =temp;
	temp = NULL;
	p->capacity = newcapacity;
}
}
顺序表的尾删

尾删操作让顺序表不能访问就可以,直接p->size–,数据不要改变,也不可以字节释放掉,因为开辟的是一个数组空间,释放掉空间要把所以开辟好的空间全部释放。

void SeListPop(SL*p)
{
	assert(p);
	assert(p->size);

	p->size--;
}
顺序表的头删

头删直接数据覆盖即可
数据结构[顺序表]_第4张图片

void SeListPopFront(SL*p)
{
	assert(p);
	assert(p->size);
	for(int i = 0;i<p->size;i++)
	{
		p->a[i] = p->a[i+1];
	}
	p->size--;
	
}
顺序表的任意出插入
void SLInsert(SL* ps, int pos, SLDataType x) {
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);

	for (size_t i = ps->size-1; i >=pos ; i--)
	{
		ps->a[i + 1] = ps->a[i];
	}
	ps->a[pos] = x;
	ps->size++;

}
顺序表的任意出删除
void SLErase(SL* ps, int pos) {
	assert(ps);
	assert(!SLISEmpty);
	assert(pos >= 0 && pos < ps->size);
	for (size_t i = pos; i <ps->size-1 ; i++)
	{	//    size-2         size-1
		ps->a[i] = ps->a[i+1];
	}
	ps->size--;
}
顺序表空间的释放
void SeList(SL*p)
{	
	assert(p);
	assert(p->a!=NULL);
	free(p);
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}
3.顺序表优势和缺点

顺序表的优点:可以下标访问,尾插效率高

缺点:头,中间节点处插入删除操作,效率不高,时间复杂度为O(N)。可能会存在空间浪费问题。

你可能感兴趣的:(数据结构,算法)