顺序表

顺序表是什么呢?
顾名思义,顺序表是物理地址连续的存储单元依次存储数据的线性结构,一般情况下采用数组存储,在数组上完成数据的增删查改。
在这里插入图片描述
顺序表和数组有什么区别呢?
顺序表比数组更约束,顺序表物理地址上必须连续存储,数组是顺序表在实际编程中的具体实现方式。

顺序表分为静态顺序表和静态顺序表(主要区别在于他们的容量是否可变)

静态顺序表

静态顺序表的概念

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

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

静态顺序表相对来比较简单,我们这里就不做深入的讨论,接下来主要了解一下动态顺序表。

动态顺序表

动态顺序表的概念

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

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

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

	SeqList seqlist;
 	SeqListInit(&seqlist,10);

SeqList.h

void SeqListInit(SeqList *ps,int capacity);

SeqList.c

void SeqListInit(SeqList *ps,int capacity){
	ps->array = malloc(sizeof(int) * capacity);//申请空间大小
	assert(ps->array != NULL);
	ps->size = 0;
	ps->capacity = capacity;
}
动态顺序表的销毁

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

SeqListDestroy(&seqlist);

SeqList.h

void SeqListDestroy(SeqList *ps);

SeqList.c

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

}
动态顺序表的扩容

当顺序表的容量不够用时,我们应该怎么办呢?当然是扩大顺序表的容量。
在这里插入图片描述
具体步骤:
1.当size(实际存储)>=capacity(顺序表容量)时,顺序表执行扩容。
2.扩容一般是两倍增长,新顺序表是原顺序表容量的2倍大小。(缺陷:会造成空间的浪费)int newCapacity = ps->capacity * 2;
3.注意:不是在原顺序表的基础上增加容量,而是新建一个顺序表。int *newArray = (int*)malloc(sizeof(int)*newCapacity);

4.将原来顺序表的数据加载到新的顺序表中。
for (int i = 0; i < ps->sz; i++){ newArray[i] = ps->array[i]; }
5.扩容完成,释放原来顺序表的内存。
free(ps->array);
6.将array的关系指向新的顺序表。
ps->array = newArray;
7.改变capacity
ps->capacity = newCapacity;

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);

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

头插
在这里插入图片描述
头插可以直接将数据插到顺序表的首位吗?很显然是不行的,因为顺序表首位已经有了数据。
头插时,应从后向前依次将数据向后搬移一位,将首位腾出给目标数据插入。

void SeqListPushFront(SeqList *ps, int v);

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);

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下标删除)

尾删
在这里插入图片描述
直接使顺序表size--

void SeqListPopBack(SeqList *ps);


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

头删
在这里插入图片描述
直接前移覆盖第一个数据

void SeqListPopFront(SeqList *ps);

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);

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 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 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);

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);

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

到这里顺序表的基本问题就解释完了,相信多多少少会解决大家心头的疑问,在数据结构的学习中应当善于思考,多画图,死磕代码,注意细节,将伪代码转换为代码,这样才能很好的掌握数据结构的有关知识。

  • 24
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值