C顺序表的增删查改

顺序表是物理地址连续的存储单元依次存储数据的线性结构,一般情况下采用数组存储,在数组上完成数据的增删查改。

顺序表比数组更约束,顺序表物理地址上必须连续存储,数组是顺序表在实际编程中的具体实现方式。

顺序表分为静态顺序表和动态顺序表,主要区别是他们的容量是否可变。

静态顺序表

静态顺序表的容量在静态时期(编译期间)确定,大小不可改变。

静态顺序表的创建

typedef struct SeqList
{
	int array[100];
	int size;//顺序表中实际存储的数据个数
}SeqList;//别名

静态顺序表比较简单,主要介绍动态数据表

动态数据表

动态顺序表的容量在动态时期(运行期间)确定,大小可改变。

动态数据表的创建

typedef struct SeqList{
	int* array;//动态从堆上申请
	int capacity;//容量
	int size;//有效数据的个数  尾插时,可用位置的下标
}SeqList;

动态数据表的初始化

初始化顺序表传参时应该传&seqlist,用结构体指针SeqList ✳ps来接收,并且还应传顺序表的容量capacity。

void SeqListInit(SeqList *ps,int capacity){
	ps->array = malloc(sizeof(int) * capacity);//申请空间大小
	assert(ps->array != NULL);
	ps->size = 0;
	ps->capacity = capacity;
}

动态顺序表的销毁

这里传参依旧是&seqlist,注意释放顺序表空间free(ps->array),销毁时传参不需要传顺序表的容量。

void SeqListDestroy(SeqList *ps){
	free(ps->array);
    //释放 array 的空间
	ps->array = NULL;
	ps->size = 0;
	ps->capacity = 0;
	//锦上添花
}

动态顺序表的扩容

1.检查是否需要扩容,当size(实际存储)>=capacity(顺序表容量)时,顺序表执行扩容。
2.扩容一般是两倍增长,新顺序表是原顺序表容量的2倍大小。(缺陷:会造成空间的浪费)
3.注意:不是在原顺序表的基础上增加容量,而是新建一个顺序表。
4.将原来顺序表的数据加载到新的顺序表中。
5.扩容完成,释放原来顺序表的内存。
6.将array的关系指向新的顺序表。
7.改变capacity
具体代码如下:

static void CheckCapacity(SeqList *ps)
{
	if (ps->size < ps->capacity)
	{
		return;
	}
	//需要扩容
	int newCapacity = ps->capacity * 2;
	int *newArray = (int*)malloc(sizeof(int)*newCapacity);
	assert(newArray != NULL);
	//搬移
	for (int i = 0; i < ps->size; i++)
	{
		newArray[i] = ps->array[i];
	}
    //释放老空间
	free(ps->array);
	ps->array = newArray;
	ps->capacity = newCapacity;
}

动态顺序表的插入(头插,尾插,根据pos下标插入)

尾插时,顺序表有效数据的个数就是尾插时可用位置的下标,完成尾插之后,使有效数据个数size++。

void SeqListPushBack(SeqList *ps, int v)
{
	CheckCapacity(ps);
	ps->array[ps->size] = v;
	ps->size++;
}

头插时,应从后向前依次将数据向后搬移一位,将首位腾出给目标数据插入。

void SeqListPushFront(SeqList *ps, int v)
{
	CheckCapacity(ps);
	//i表示空间下标
	for (int i = ps->size; i >= 1; i--)
	{
		ps->array[i] = ps->array[i - 1];
	}
	ps->array[0] = v;
	ps->size++;
}

根据POS下标插入:

将下标为pos及pos之后的数据向后移动一位,使ps->array[pos]=v。

void SeqListInsert(SeqList *ps, int pos, int v)
{
	CheckCapacity(ps);
	//pos = 0为头插  pos = size为尾插
	assert(pos >= 0 && pos <= ps->size);
	//i代表数据的下标
	for (int i = ps->size - 1; i >= pos; i--)
	{
		ps->array[i + 1] = ps->array[i];
	}
	ps->array[pos] = v;
	ps->size++;
}

动态顺序表的删除(头删,尾删,根据pos下标删除)

尾删:

void SeqListPopBack(SeqList *ps)
{
	assert(ps->size > 0);
	ps->size--;
}

头删:

直接前移覆盖第一个数据

void SeqListPopFront(SeqList *ps)
{
	assert(ps->size > 0);
	//i代表空间的下标
	for (int i = 0; i <= ps->size - 2; i++)
	{
		ps->array[i] = ps->array[i + 1];
	}
	ps->size--;
}

根据pos下标删除:

将pos+1及以后的数据依次前移

void SeqListErase(SeqList *ps, int pos){
	assert(ps->size > 0);
	assert(pos >= 0 && pos < ps->size);
	//i代表数据的下标
	for (int i = pos + 1; i <= ps->size - 1; i++){
		ps->array[i - 1] = ps->array[i];
	}
	ps->size--;
}

删除第一个遇到的目标元素:

调用查找和根据pos下标删除的函数即可

int SeqListRemove(SeqList *ps, int v){
	int pos = SeqListFind(ps, v);
	if (pos = -1){
		return;
	}

	SeqListErase(ps, pos);

}

删除所有的目标元素:

定义i 和 j,若没有遇到目标元素,i++,j++,若遇到目标元素i++,j不动,直到i找到下一个不是目标元素的值,将值赋给j下标所在的数据,即可完成替换目标元素

int SeqListRemoveAll(SeqList *ps, int v){
	int i, j;
	for (i = 0, j = 0; i < ps->size; i++){
		if (ps->array[i] != v){
			ps->array[j] = ps->array[i];
			j++;
		}
	}
	ps->size = j;
}

动态顺序表的查找:

int SeqListFind(SeqList *ps, int v){
	for (int i = 0; i < ps->size; i++){
		if (ps->array[i] = v){
			return i;
		}
	}
	return -1;
}

动态顺序表的更新:

目标数据直接替换pos下标所在数据

void SeqListModify(SeqList *ps, int pos, int v)
{
	assert(pos >= 0 && pos < ps->size);
	ps->array[pos] = v;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值