顺序表讲解

顺序表

线性表

定义:

  线性表是n个具有相同特性的数据元素的有限序列,常见的线性表有:顺序表、链表、栈、队列…
  之所以叫线性表,是因为线性表在逻辑上是线性结构,好像一条线一样贯穿始终,但在物理结构上(即内存中的结构)并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

在这里插入图片描述
  本篇文章讲解顺序表。

顺序表

  顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般采用数组存储,包括静态数组和动态数组。

静态顺序表

//创建一个静态顺序表
#define N 10   //重定义宏或者标识符
typedef int SLDataType;//重定义类型,以后要改的时候直接改这儿
struct SeqList{
	SLDataType a[N];
    int size;//可以用来存储数组的大小
}

静态顺序表实际上不好用,因为个数写死了,大了浪费空间,小了不够用,使用起来非常不方便,所以我们实际上通常使用动态顺序表。

动态顺序表

  动态顺序表的特点是按需申请,非常灵活。

#define INIT_CAPACITY 10  //顺序表的初始长度
//创建一个动态顺序表
typedef int SLDataType;//重定义类型,以后要改的时候直接改这儿
struct SeqList{
	SLDataType* a;
    int size;//可以用来存储当前数据个数
    int capacity;//用来存储当前空间的容量
}SL;

实现顺序表的一些功能(增删查改)

初始化顺序表
void SLInit(SL* ps){
	ps->a=(SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);//开辟初始大小个空间
    if(ps->a==NULL){
        perror("malloc failed");
        return;
    }
      ps->size=0;
      ps->capacity=INIT_CAPACITY;//变成初始大小了 
}
销毁顺序表(因为动态申请一定要记得销毁否则内存泄漏)
void SLDestroy(SL* ps){
	free(ps->a);
	ps->a=NULL;//好习惯,置空
    ps->size=0;
	ps->capacity=0;
}
顺序表里增加数据

  我们使用的是动态顺序表,因此在增加新数据之前要检查是否满容量,满容量需要扩容,扩容可以封装成一个函数:

void SLCheckCapacity(SeqList* ps) {
	assert(ps);
	SLDateType* tmp;
	if (ps->size == ps->capacity) {
		//注意扩容扩的是数组,是ps->a而不是ps,注意了
		tmp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * ps->capacity * 2);
		if (tmp == NULL) {
			perror("realloc failed\n");
		}
		ps->a = tmp;//防范异地扩容
		ps->capacity *= 2;//扩容以后容量标识变一下
	}
}

  尾插法(在数据末尾加数据):

void SLPushBack(SL* ps,SLDataType x){
	assert(ps);
	//检查扩容
    SLCheckCapacity(SeqList* ps);
	ps->a[ps->size++]=x;
}

  头插法(在第一个数据之前添加新数据):

void SLPushFront(SeqList* ps, SLDateType num) {
	assert(ps);
	//检查扩容
	SLCheckCapacity(ps);
	//插入
	int end = ps->size;
	while (end > 0) {
		ps->a[end] = ps->a[end - 1];
		end--;
	}
	ps->a[end] = num;
	ps->size++;//插入了要把数据个数更新一下啊
}

  在下标为pos的位置上插入一个数:

void SeqListInsert(SeqList* ps, int pos,SLDateType num) {
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);//检查参数,插入的时候可以尾插
	SLCheckCapacity(ps);
	int end = ps->size;
	while (pos < end) {
		ps->a[end] = ps->a[end - 1];
		end--;
	}
	ps->a[pos] = num;
	ps->size++;//数量增加了,记得加上
}
删除数据

  尾删法:

void SLPopBack(SL* ps){
	//ps->a[ps->size-1]=0;//现在最后一个下标是size-1,但万一数据本来就是0呢?就可能混淆,所以直接减ps->size比较合适,后面访问也是用size
    
    //如果已经删空了就不要再删了,所以要检查
    
    //温柔的检查,删空了就不删了,我也不终止程序,不过没有报错信息
    if(ps->size == 0){
        return;
    }
    //暴力的检查,断言发挥作用的时候会终止程序并显示报错信息
     assert(ps->size > 0);
	 ps->size--;
     return;
  }
  

  头删法:

void SLPopFront(SeqList* ps) {
	assert(ps);
	assert(ps->size > 0);
	int end = 0;
	while (end < ps->size) {
		ps->a[end] = ps->a[end + 1];
		end++;
	}
	ps->size--;
}

  删除下标为pos的数据

void SeqListErase(SeqList* ps, int pos) {
	assert(ps);
	assert(pos >= 0 && pos < ps->size);//检查参数,但相当于尾删的时候删不了size位置的
	assert(ps->size > 0 );
	int end = pos;
	while (end < ps->size) {
		ps->a[end] = ps->a[end + 1];
		end++;
	}
	ps->size--;//数量减少了
}
查找数据

查找某数据,并返回下标,如果找不到返回-1

int SeqListFind(SeqList* ps, SLDataType num) {
	assert(ps);

	int i = 0;
	for (i = 0; i < ps->size; i++) {
		if (ps->a[i] == num) {
			return i;
		}
	}
	return -1;//没有找到,返回-1
}
修改数据
void SeqListModify(SeqList* ps, SLDataType num,SLDataType newnum) {
	assert(ps);
	int pos = 0;
	//先查找,以数据1为例
	pos = SeqListFind(ps,1);	
	if(pos != -1){
		ps->a[pos] = newnum;
	}
}
打印数据

  将顺序表中的数据打印出来

void SLPrint(SeqList* ps) {
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->size; i++) {
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

本文结束。
                (如果文章有错误之处,请在评论区点醒作者,谢谢!)

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
好的,我可以回答这个问题。顺序表是一种线性表,它的元素在内存中是连续存储的。顺序表的实现可以使用数组来完成。下面是一个简单的顺序表的代码实现: ``` #define MAXSIZE 100 // 定义顺序表的最大长度 typedef struct { int data[MAXSIZE]; // 用数组存储顺序表的元素 int length; // 顺序表的当前长度 } SqList; // 初始化顺序表 void InitList(SqList *L) { L->length = 0; } // 插入元素 int ListInsert(SqList *L, int i, int e) { if (i < 1 || i > L->length + 1 || L->length == MAXSIZE) { return 0; // 插入位置不合法或者顺序表已满,插入失败 } for (int j = L->length; j >= i; j--) { L->data[j] = L->data[j - 1]; // 将插入位置后面的元素依次后移 } L->data[i - 1] = e; // 插入新元素 L->length++; // 长度加1 return 1; // 插入成功 } // 删除元素 int ListDelete(SqList *L, int i) { if (i < 1 || i > L->length) { return 0; // 删除位置不合法,删除失败 } for (int j = i; j < L->length; j++) { L->data[j - 1] = L->data[j]; // 将删除位置后面的元素依次前移 } L->length--; // 长度减1 return 1; // 删除成功 } // 查找元素 int GetElem(SqList L, int i) { if (i < 1 || i > L.length) { return 0; // 查找位置不合法,查找失败 } return L.data[i - 1]; // 返回查找到的元素 } ``` 这个代码实现了顺序表的基本操作,包括初始化、插入、删除和查找。当然,实际应用中还需要考虑其他因素,比如顺序表的扩容和缩容等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嫋嫋.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值