数据结构——顺序表讲解及实现

本文详细介绍了顺序表的基本概念、静态与动态的区别,重点展示了动态顺序表的接口实现,包括初始化、扩容、操作函数,同时讨论了其优缺点。

线性表介绍,顺序表讲解以及实现

线性表

众所周知,线性表是一个n个具有相同特性的数据元素的有限序列,在现实学习中使用非常广泛,例如非常常见的线性表:顺序表,链表,栈,队列等等,虽然它在逻辑上是线性结构,但是在物理结构并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式储存,今天也就是要实现最简单基础的顺序表
可爱的猫猫过来凑数

顺序表的讲解

顺序表的概念

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

顺序表的种类

顺序表分为静态顺序表和动态顺序表,静态顺序表采用定长数组来储存元素,简单且不实用:动态顺序表采用动态开辟的数组来进行存储数据,若存储的空间不够可以及时扩容,可以较好的完成任务,我们今天实现的也是动态顺序表

顺序表的实现

当然,讲到这里,有的兄弟们可能就要问了,讲了这么多听着恶心的东西,那我们该怎么实现呢,首先我们先看看动态顺序表的接口,然后把它们引入到头文件中,然后我们再一个一个实现出来,今天的任务就完成啦
开始进行实现,不多说了

顺序表的接口实现

typedef int SLDataTpye;

typedef struct SeqList{
	SLDataTpye* a;
	int size;
	int capacity;
}SeqList;

void SeqListInit(SeqList* p);
void SeqListPrint(SeqList* p);

//时间复杂度为O(1)
void SeqListPushBack(SeqList* p, SLDataTpye x);
void SeqListPopBack(SeqList* p); 

//时间复杂度为O(N)
void SeqListPopFront(SeqList* p);
void SeqListPushFront(SeqList* p, SLDataTpye x);

void SeqListInsert(SeqList* p, int pos, SLDataTpye x);
void SeqListErase(SeqList* p, int pos);

void checkCapacity(SeqList* p);

void SeqListDestroy(SeqList* p);

好的,我们很明显的看到,动态顺序表采用了SLDataType 了一个指针,这个指针便是需要动态开辟的指针了,任务的进行,这个指针不可或缺,size表示有效数组的个数,capacity表示容量空间的大小,剩余的接口根据名称便可大致知道其功能一二,如果不知道的话建议不要再溜冰了!!!*
希望能找回独角兽

接口的具体实现

相信只有真正的家人才能看到这里,那么,现在将介绍真正的代码实现,若有错误,也请各位朋友一一指正

void checkCapacity(SeqList* p) {
	assert(p);
	if (p->size == p->capacity) {
		size_t newcapacity = p->capacity == 0 ? 4 : (p->capacity) * 2;
		SLDataTpye* tmp = realloc(p->a, sizeof(SLDataTpye) * newcapacity);
		if (tmp) {
			p->a = tmp;
			p->capacity = newcapacity;
		}
		else {
			printf("alloc fail\n");
			exit(-1);
		}
	}
}

void SeqListInit(SeqList* p) {
	p->a = NULL;
	p->size = 0;
	p->capacity = 0;
}

首先出场的便是检查容量以及初始化顺序表,当p的容量不够时便赶紧扩容到先前的2倍,但是感觉指数级增长的太快了,有点占用内存,但是瑕不掩瑜,这点小伤无足挂齿;初始化顺序表没有甚么可以值得谈一谈的,请大家自行理解

void SeqListPushFront(SeqList* p, SLDataTpye x) {
	checkCapacity(p);
	/*int tmpsize = p->size;
	while (tmpsize > 0) {
		p->a[tmpsize] = p->a[tmpsize - 1];
		tmpsize--;
	}
	p->a[0] = x;
	p->size++;*/
	SeqListInsert(p,0,x);
}

void SeqListPushBack(SeqList* p, SLDataTpye x){
	checkCapacity(p);
	/*p->a[p->size] = x;
	p->size++;*/
	SeqListInsert(p, 0, p->size-1);
}

void SeqListPopBack(SeqList* p) {
	checkCapacity(p);
	if (p->size > 0) {
		p->size--;
	}
}

void SeqListPopFront(SeqList* p) {
	assert(p);
	if (p->size != 0) {
		int tmpbegin = 0;
		while (tmpbegin < p->size - 1) {
			p->a[tmpbegin] = p->a[tmpbegin + 1];
			tmpbegin++;
		}
		p->size--;
	}
	else {
		printf("The size is empty\n");
		return;
	}
}

紧接着便是push和pop的四组,由此可见,从后面进行的操作都非常简单,从前面进行的操作都相对复杂一点,但是还是很好理解的

void SeqListPrint(SeqList* p) {
	assert(p);
	if (p->size!=0) {
		for (int tma = 0; tma < (p->size)-1; tma++) {
			printf("%d ",p->a[tma]);
		}
		printf("%d\n",p->a[p->size-1]);
	}
	else {
		printf("There is no data\n");
		return;
	}
}

就是一个普通的打印函数,随意看一下理解便好

//pos从0开始算
void SeqListInsert(SeqList* p, int pos, SLDataTpye x) {
	checkCapacity(p);
	int tmpsize = p->size;
	if (pos >= 0 && tmpsize >= pos) {
		while (tmpsize > pos) {
			p->a[tmpsize] = p->a[tmpsize - 1];
			tmpsize--;
		}
		p->a[pos] = x;
		p->size++;
	}
	else {
		printf("The pos is not suit\n");
		return;
	}
}

void SeqListErase(SeqList* p, size_t pos) {
	assert(p);
	assert(pos < p->size);
	size_t tmpsize = pos + 1;
	while (tmpsize < p->size) {
		p->a[tmpsize - 1] = p->a[tmpsize];
		tmpsize++;
	}
	p->size--;
}

void SeqListDestroy(SeqList* p) {
	assert(p);
	free(p->a);
	p->a = NULL;
	p->capacity = p->size = 0;
}

好的,最后的三组函数出现了! 但是很好理解,第一个insert插入函数也就是从后往前遍历,给要插入的数值腾出地方;第二个erase消除函数很好理解;最后的destroy销毁顺序表的函数,有一个注意点便是free掉p->a后,需要将它变成NULL,防止它成为野指针被使用,那就会出乱子了。

顺序表的优缺点

当然,顺序表虽然简单,但是也是有优缺点的,优点是它使用了连续的物理空间,方便下标随机访问;但是缺点更加明显,1,插入数据时,空间不足要扩容,扩容有会性能消耗;2,头部或者中间位置插入或者删除数据时,需要挪动数据,效率比较低;3,不能按照需求来申请和释放空间,可能会存在一定的空间占用,浪费空间。

顺序表总结

顺序表作为数据结构的基础,对于新手来说还是非常友好的,也希望我能一直坚持下去,努力完成学业,也希望看到这里的观众事业顺利,心想事成,下次再见

老实人本人

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值