C:数据结构之顺序表

目录

概念

顺序表准备工作

函数接口

1.初始化

2.尾插

3.头插

4.尾删

5.头删

6. 在指定位置插入数据

7.在指定位置删除数据

8.查找

 9.修改

10.打印

11.销毁 


概念

简而言之,顺序表就是数组,是由一段连续的物理空间组成的序列。


数组分为定长数组和变长数组,同理,顺序表也是有定长(静态)的和变长(动态)的,二者的区别就是前者的储存的空间是有限的,而后者的空间可以根据情况调整空间容量。

顺序表准备工作

typedef int SLDataType;
//定义
typedef struct SeqList
{
	SLDataType* arr;//动态顺序表使用动态开辟可以扩大空间
    //如果是静态的顺序表
    //SLDataType arr[N];//N是确定的值
	int capacity;
	int size;
}SL;

1.数组中储存的元素可能是任意类型,为了更加方便,我们将类型定义为SLDataType。
2.在储存元素的过程中我们对数组进行操作,需要随时记录下标和元素的个数,所以将数组和size(元素的个数)和capacity(总容量)进行包装,方便进行访问。

函数接口

1.初始化

//初始化
void SLInit(SL* ps);

利用函数对形参进行值的修改,就需要传递地址,所以形参的类型应该是封装好的结构体指针类型。

//初始化
void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

刚开始时数组中应该没有元素,而且下标是0,个数和容量也是0,在插入的时候,在进行开辟空间。

2.尾插

//尾插
void SLPushBack(SL* ps,SLDataType x)
{
	//assert(ps);
	//空间不够,扩容
	SLCheckCapacity(ps);//如果空间足够直接跳过,如果空间不够,就进行扩容;
	//空间足够,直接插入
	ps->arr[ps->size++] =x;
}

 尾插就是按照顺序进行直接赋值,但是在插入前需要进行检查是否容量已经满了,如果容量已经满了那么就需要进行扩容,我们将扩容进行函数包装,以便在后续使用到。

void SLCheckCapacity(SL* ps)
{
	if (ps->capacity == ps->size)
	{
		//记录的总空间翻倍
		int newcapacity = (ps->capacity == 0) ? 4 : 2 * ps->capacity;
		//顺序表的空间也翻倍
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));
//  /    realloc的函数的参数是空间地址,新的空间地址,以字节为单位;
//  判断是否扩容成功		
		if (tmp == NULL)
		{
			perror("realloc fail!\n");
			exit(1);
		}
		//将新的空间给到数组空间
		ps->arr = tmp;
		//将新的空间大小重新赋值
		ps->capacity=newcapacity;
	}
 }

 先来进行if判断,如果已有元素个数(size)等于容量,那么就需要进行扩容,第一次进行扩容时,由于初始化容量为0,所以我们默认开辟4个元素的空间,如果不是第一次进行开辟空间,我们直接将空间进行翻倍扩大,我们使用realloc来进行扩容,realloc是在原有的地址进行扩容。
注意:我们开辟的新空间需要先用一个临时变量进行接收,目的是防止开辟失败造成原有的空间损坏。

开辟过之后直接将临时变量进行赋值。

  1. 注意:capacity是元素个数的最大值,而tmp是元素个数最大值所占的空间,单位是字节;

3.头插

//头插
void SLPushFront(SL* ps,SLDataType x)
{
	//判断是否满容
	SLCheckCapacity(ps);
	//全部向后移
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[0] = x;
	ps->size++;
}

头插的时间复杂度是O(n),因为数组存储的地址是连续的,所以在头部插入,就需要将所有的元素进行后移, 同时也需要进行判断是否需要扩容。

4.尾删

//尾删
void SLPopBack(SL* ps)
{
	//不能为空
	assert(ps);
	assert(ps->size);
	ps->size--;
}

在尾删之前需要先判断是否是个空的数组,如果数组是空的就无法进行删除,而且传递过来的地址也不能为空,对于删除最后面的元素,我们直接将元素个数size-1即可。 

5.头删

//头删
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 0; i<ps->size-1; i++)
	{
		ps->arr[i] = ps->arr[i+1];
	}
	ps->size--;
}

同理,头删也得保证数组和地址不为空,对于头删,我们直接把第二个及后面的所有元素向前面移动即可。最后不要忘了size也要减1;

6. 在指定位置插入数据

//指定插入位置的数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	//插入的位置限制
	assert(pos-1 >= 0 && pos-1 <= ps->size);
	SLCheckCapacity(ps);
	for (int i = ps->size; i >pos-1; i--)
	{
		ps->arr[i] = ps->arr[i-1];
	}
	ps->arr[pos-1] = x;
	ps->size++;
}

pos是指的第pos个元素,需要先判断pos是否合法,pos-1需要大于0小于size;我们要实现在pos处插入数据,就需要将pos以及后面的所有数据进行后移,然后直接进行赋值,最后size加1;

7.在指定位置删除数据

//指定位置删除数据
void SLDelete(SL* ps, int pos)
{
	assert(ps);
	assert((pos-1) >= 0 && (pos-1) < ps->size);
	//pos后面的数据向前移动
	for (int i = pos-1; i <ps->size-1; i--)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

同理,保证ps和pos的合法性,再pos删除数据,就要将后面的数据全部向前移动一位,最后size--;

8.查找

//查找
void search(SL* ps, int pos)
{
	assert(ps);
	assert(pos-1 >= 0 && pos-1 < ps->size);
	printf("这个位置上的数是%d", ps->arr[pos - 1]);
}

直接打印下表是pos-1的数据即可;

 9.修改

//修改
void change(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos-1 >= 0 && pos-1 < ps->size);
	{
		ps->arr[pos - 1] = x;
	}
}

修改就是在改位置直接进行赋值即可。

10.打印

//打印
void SLPrint(SL* ps)
{
	printf("操作后顺序表为:>");
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
}

时间复杂度是O(N),将整个数组进行遍历,按顺序打印;

11.销毁 

void SLDestory(SL*p)
{
    assert(p);
    free(arr);
    arr=NULL;
    p->size=0;
    p->capacity=0;
}

将原有的空间进行释放,size和capacity置为0;arr置为空; 

  • 20
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值