数据结构——顺序表

文章目录


前言

数据结构——顺序表


一、顺序表

1.灵魂三连击:咋来的?啥玩意?有啥用?

先来说一说咋来的: 你敲代码需要定义数据(字符串、数组、阿巴阿巴)吗?
数据结构——顺序表
所以理所应当就会有线性表这个概念??????线性表(linear list)是n个具有相同特性的数据元素的有限序列。顺序表也是线性表的一种,最常见的数组也算~~~算吗?我也具体忘记了,这无伤大雅!

再来说一说啥玩意: 顺序表就是数据按顺序结构在一段连续的空间上进行存储!
数据结构——顺序表
顺序表有什么卵用?: 对连续的数据进行操作。以满足实际工作中的需求,比如需要在连续顺序的数据中插入一个数,变成这样
数据结构——顺序表

2.这玩意这么实在,怎么用?

当然就是要创建了!!顺序表分为静态和动态两种,静态的话参考数组,没啥说的,如果有,那就不说了
数据结构——顺序表

3.那就来看看动态顺序表是个什么东西?如何创建?

动态顺序表------底层空间从堆上动态申请出来的! 底层空间?堆?可以看看这个文章C 语言函数中栈帧的创建与销毁

typedef struct SeqList {	//自定义结构体SeqList,里面包含三个变量
	DataType* array;		//指向存储元素空间的起始位置
	int capacity;	//表示空间总的大小
	int size;           //有效元素的个数
}SeqList;

//对array,capacity,size进行初始化设置
//Struct SeqList S;
//	S.array :10
//	S.capacity :10
//	S.size :

原理如下:
数据结构——顺序表

二、顺序表操作

1.操作声明

什么是对顺序表的操作?就是在上面定义好的顺序表中对其进行元素的增删查找。都有哪些呢?

//初始化ps(对指向顺序表的指针进行初始化操作)
void SeqListInit(SeqList* ps, int initCapacity);
//销毁(对顺序表进行销毁)
void SeqListDestory(SeqList* ps);
//尾插(在顺序表最后面加入元素)
void SeqListPushBack(SeqList* ps, DataType data);
//尾删(删除顺序表最后的元素)
void SeqListPopBack(SeqList* ps);
//头插(在顺序表最前面加入元素)
void SeqListPushFront(SeqList* ps, DataType data);
//头删(删除顺序表第一个元素)
void SeqListPopFront(SeqList* ps);
//在顺序表的pos位置插入元素data
// 注意pos的范围必须在[0,ps->size]
void SeqListInsert(SeqList* ps, int pos, DataType data);
//删除pos位置的值
// 注意pos范围
void SeqListErase(SeqList* ps, int pos);
//有效元素的个数
int SeqListSize(SeqList* ps);
//空间总的大小
int SeqListCapacity(SeqList* ps);
//返回空间中某个元素的位置
void SeqListFind(SeqList* ps, DataType data);
//检查顺序表是否为空
int SeqListEmpty(SeqList* ps);
//获取顺序表中第一个元素
DataType SeqListFront(SeqList* ps);
//获取顺序表中最后一个元素
DataType SeqListBack(SeqList* ps);
//获取顺序表任意一个位置元素
DataType SeqListGet(SeqList* ps,int pos);
//打印顺序表
void SeqListPrint(SeqList* ps);
//测试顺序表
void TestSeqList();

2.具体操作定义

初始化: 先从堆上申请一块内存空间用以存储数组。先利用malloc申请空间initCapacity,

//将ps指向的结构体变量初始化成功
void SeqListInit(SeqList* ps, int initCapacity) {        //检测一下指针参数ps,防止取空
	assert(ps); 
	ps->array = (int*)malloc(initCapacity * sizeof(int));//申请一块内存用以村存储数组 
	//检测生成是否成功
	if (NULL == ps->array) {  //检测指针ps指向申请的内存空间中存放的数组首元素地址是否存在
		assert(0);
		return;
	}
	ps->capacity = initCapacity; //指针ps指向的capacity初始化为申请的内存空间
	ps->size = 0; //初始化内存空间中的元素个数
}

销毁: 销毁顾名思义就是之前在堆上申请了内存空间用以存储顺序表,现在这个顺序表结束了它的使命,就要将申请的空间进行释放,否则久而久之,申请的内存空间过多而没有销毁会出现所谓的内存泄漏
数据结构——顺序表

//将ps指向的结构体变量销毁
void SeqListDestory(SeqList* ps){
	assert(ps);
	if (ps->array) {
		free(ps->array);//释放申请的内存
		ps->array = NULL;//释放后,数组清空
		ps->capacity = 0;//申请的内存空间清零
		ps->size = 0;//元素个数清零
	}
}

尾插: 这里需要注意的是,你要在array的末尾插入元素,得有地方给你插,因为原来capacity已经给定了空间为10,array有10个元素数量。能插的地方有10个,10个都满了,需要扩容才能继续在后面插入元素。
数据结构——顺序表

数据结构——顺序表

//尾插
void SeqListPushBack(SeqList* ps, DataType data) {
	assert(ps);

	//1.检查空间是否足够
	CheckCapacity(ps);
	//2.在最后一个元素之后插入data
	ps->array[ps->size] = data;//ps指向size的位置恰好是元素个数,同时是尾插的存储位置
	ps->size++;//由于加入一个元素,导致size增加1
}

检查空间是否足够: 这里不用多说,尾插中由于需要有足够的空间,所以要检查

//检查容量进行扩容
void CheckCapacity(SeqList* ps) {
	assert(ps);
	if (ps->size == ps->capacity) { //元素的个数和申请的内存空间个数相等,说明需要扩容
		int newCapacity = (ps->capacity << 1);//定义一个新的空间newCapacity在原空间上左移1(左移扩大两倍)
		DataType* temp = (DataType*)malloc(sizeof(DataType) * newCapacity);//为newCapacity申请内存空间,指针temp
		if (NULL == temp) {
			exit(0);
			return;
		}
		//memcpy
		for (int i = 0; i < ps->size; ++i) { //令指针temp代替指针原指针ps的位置
			temp[i] = ps->array[i];
		}
		//对原内存空间进行释放,使用新的内存空间
		free(ps->array);
		ps->array = temp;
		ps->capacity = newCapacity;
	}
}

尾删: 尾删很简单,零数组array的size数量减 1 就行。不过在这里需要检测顺序表是否为空,空的话拿头给你删?

//尾删
void SeqListPopBack(SeqList* ps) {
	assert(0);

	//1.要检查是否为空,为空直接返回,有元素删除
	//if (0 == ps->size) {
	//	return;
	//}
	
	//添加函数检测顺序表是否为空
	if (SeqListEmpty(ps)) {
		return;
	}
	ps->size--;
}

检测顺序表是否为空(判空): 这里就是对尾删里面那个判空进行的填坑。

//判空
int SeqListEmpty(SeqList* ps) {
	assert(ps);
	return 0 == ps->size;//size如果等于0的话,与0相等,此表达式为真。返回真
}

头插: 与尾插类似,不同点在于需要对整个元素向后进行搬移,然后第一个位置空出来进行头插
数据结构——顺序表

//头插
void SeqListPushFront(SeqList* ps, DataType data) {
	assert(ps);

	//1.检测空间是否足够
	CheckCapacity(ps);
	//2.将顺序表中的所有元素整体向后搬移一位
	for (int i = ps->size - 1; i >= 0; --i) {
		ps->array[i + 1] = ps->array[i]; //原来array[i]的位置变成现在array[i+1]的位置
	}
	//3.插入元素
	ps->array[0] = data;
	ps->size++;
}

头删:

//头删
void SeqListPopFront(SeqList* ps) {
	//判空
	if (SeqListEmpty(ps)) {
		return;
	}
	//将顺序表中除第一个元素外往前搬
	for (int i = 0; i < ps->size - 1; i++) {
		ps->array[i] = ps->array[i + 1];
	}ps->size--;
}

在顺序表的pos位置插入元素data:(注意pos的范围必须在[0,ps->size]) 这里的原理就是把pos位置前的元素不管,然后,pos位置之后包括pos位置的元素进行头插

数据结构——顺序表

void SeqListInsert(SeqList* ps, int pos, DataType data) {
	//1.参数检测
	assert(ps);
	if (pos < 0 || pos > ps->size) {
		printf("pos的位置有问题");
		return;
	}
	//2.检测是否需要扩容
	CheckCapacity(ps);
	//3.插入元素
	for (int i = ps->size - 1; i >= pos; i--) {
		ps->array[i+1] = ps->array[i];
	}
	ps->array[pos] = data;
	ps->size++;
}

删除pos元素位置的值: 同样的,pos之后的元素向前进行头删

void SeqListErase(SeqList* ps, int pos) {
	assert(ps);
	if (pos < 0 || pos >= ps->size) {
		printf("位置有问题");
		return;
	}
	if (SeqListEmpty(ps)) { //判空,元素不能为空,才能进行某一位置的删除
		return;
	}
	for (int i = pos + 1; i < ps->size; ++i) {
		ps->array[i - 1] = ps->array[i];
	}
	ps->size--;
}

其他: 包括有效元素个数的定义(定义顺序表中有几个有效元素),空间总的大小定义,返回空间中某个元素的位置(从前往后进行遍历,遍历的值 i == data时,输出 i),获取顺序表中的元素(首元素,尾元素,任意位置元素),打印顺序表,测试顺序表。这些都比较简单,统一列举出来

//有效元素的个数
int SeqListSize(SeqList* ps) {
	assert(ps);
	return ps->size; //有效元素个数就是size之前的所有 array 中的元素
}
//空间总的大小
int SeqListCapacity(SeqList* ps) {
	assert(ps);
	return ps->capacity; //空间总的大小就是 capacity
}
//返回空间中某个元素的位置
int SeqListFind(SeqList* ps, DataType data) {
	assert(ps);
	for (int i = 0; i < ps->size; i++) { //i从0到有效元素进行遍历,
		if (ps->array[i] == data) { //遍历到的值 == data 时,得到位置i
			return i;
		}
	}return -1;
}

//获取顺序表中第一个元素
DataType SeqListFront(SeqList* ps) {
	assert(ps);
	return ps->array[0];
}
//获取顺序表中最后一个元素
DataType SeqListBack(SeqList* ps) {
	assert(ps);
	return ps->array[ps->size - 1];
}
//获取顺序表任意一个位置元素
DataType SeqListGet(SeqList* ps, int pos) {
	assert(ps);
	return ps->array[pos];
}

//打印顺序表
void SeqListPrint(SeqList* ps) {
	assert(ps);
	for (int i = 0; i < ps->array; ++i) {
		printf("%d ", ps->array[i]);//打印数组中所有的元素
	}printf("\n");
}

总结

上面总结的很详细了,还总结??我跟在座的各位总结个

上一篇:ZOJ2532_Internship


下一篇:【two pointers】程序设计竞赛系列第七章——六道力扣经典带你刷爆双指针