数据结构之顺序表(C语言)

1.线性表

线性表 linear list n 个具有相同特性的数据元素的有限序列。
即每一个元素与其上下连接的元素都只有一个
例:顺序表

反例:二叉树

 2.顺序表

2.1顺序表的定义

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

1.静态顺序表:使用定长数组存储元素

//静态顺序表的结构
typedef struct SeqList
{
Datatype a[N];
int size;
}Static_SeqList;
//其中Datatype为存储顺序表的数据类型
//N为人为定义的数组最大个数
//size为顺序表中元素的个数

2.动态顺序表:使用动态开辟的数组存储。

//动态顺序表的结构
typedef struct SeqList
{
Datatype *array;
int size;
int capacity;
}Dynamic_SeqList;
//其中Datatype为存储顺序表的数据类型
//array为动态顺序表的首地址
//size为顺序表中元素的个数
//capacity为动态顺序表的最大容量

而在使用中,我们一般会使用动态顺序表更为方便,故只考虑动态顺序表的接口。

2.2动态顺序表的基本操作

2.2.1动态顺序表的创建

对于动态顺序表的创建,我们需要进行以下操作

1.以函数传来的地址为首地址开辟一块新的空间

2.检测空间是否开辟成功

3.初始化顺序表结构中各个元素的量

void SeqListInit(SeqList* ps)
{
	ps->a = (SLDateType*)malloc(sizeof(SLDateType) * 4);
//开辟了4个空间
	if (ps->a == NULL)
	{
		perror("malloc error");
		return;
	}
//检测空间是否开辟成功
	ps->capacity = 4;
//该顺序表最大容量是开辟的4个空间
	ps->size = 0;
//该顺序表没有元素
}

2.2.2动态顺序表的删除

对于动态顺序表的删除,我们需要进行以下操作

1.清空动态顺序表中的元素

2.将动态顺序表的最大容量和元素个数归零

void SeqListDestroy(SeqList* ps)
{
	free(ps->a);
//清空元素
	ps->capacity = 0;
	ps->size = 0;
//归零
}

2.2.3动态顺序表的打印

对于动态顺序表的打印,我们只需遍历动态顺序表,然后打印出遍历的每一个元素

void SeqListPrint(SeqList* ps)
{
	for (int i = 0; i < ps->size; i++)//遍历动态顺序表
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

2.2.4动态顺序表的尾插

对于动态顺序表的尾插,我们需要进行以下操作

1.检查动态顺序表元素是否达到上限(若达到上限则需要扩容)

2.在尾部插入元素

void SeqListPushBack(SeqList* ps, SLDateType x)
{
	if (ps->size == ps->capacity)//检查元素是否达到上限
	{
		SLDateType *tmp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * ps->capacity*2);
//扩容,将数组的容量扩容到原来的两倍
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
//检查是否扩容成功
		ps->a = tmp;
		ps->capacity *= 2;
	}
	ps->a[ps->size] = x;
	ps->size++;
}

此时便可以体现出顺序表的优点之一:可以随机访问任一元素而不需遍历整个数组

2.2.5动态顺序表的头插

对于动态顺序表的尾插,我们需要进行以下操作

1.检查动态顺序表元素是否达到上限(若达到上限则需要扩容)

2.将顺序表中所有元素从后往前开始向后挪动一个单位的地址

(注:一定必须从后往前开始挪动,如果从前往后开始挪动,则在后一个元素还没有挪动之前,前一个元素会对其进行覆盖)

3.在首地址插入新元素

void SeqListPushFront(SeqList* ps, SLDateType x)
{
	if (ps->size == ps->capacity)
	{
		SLDateType* tmp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * ps->capacity*2);
		if (tmp == NULL)
		{
			perror("realloc error");
			return;
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
//检查扩容
	for (int i = ps->size ; i > 0; i--)
	{
		ps->a[i] = ps->a[i - 1];
	}//从后往前开始挪动数组
	ps->a[0] = x;
	ps->size++;
}

2.2.6动态顺序表的尾删

对于动态顺序表的尾删,我们不需要将尾部的数据改为0,因为数组size后面的元素我们不需要关心他们的具体值,我们无法访问到也不会去访问那些没有被定义的具体值

但是对于任意一个数据结构的节点删除,我们都必须判断其是否为空,若为空进行删除,很可能会导致越界的问题

void SeqListPopBack(SeqList* ps)
{
	assert(ps->size > 0);
//判断数组是否为空
	ps->size--;
}

2.2.7动态顺序表的头删

对于动态顺序表的头删,和尾删一样,我们不需要关心删除后size外的其它元素,只需要从前往后开始对其进行依次覆盖

void SeqListPopFront(SeqList* ps)
{
	assert(ps->size > 0);
	for (int i = 0; i < ps->size; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}//从前往后开始依次进行覆盖
	ps->size--;
}

2.2.8动态顺序表的查找

对于动态顺序表的查找,我们只需要遍历整个动态顺序表,若找到元素则返回元素的位置,若没有找到元素则返回-1

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

2.2.9动态顺序表在任一位置的插入

其原理和动态顺序表头插和尾插相同,只需要在该位置往后所有元素向后挪动一个单位,然后在该单位插入新元素即可

头插和尾插是该操作的一种特殊情况

// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x)
{
	assert(pos <= ps->size);
	if (ps->size == ps->capacity)
	{
		SLDateType* tmp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * ps->capacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
	for (int i = ps->size; i > pos-1; i--)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[pos - 1] = x;
	ps->size++;
}

2.2.10动态顺序表在任一位置的删除

其原理和动态顺序表头删和尾删相同,只需在该位置往后所有元素向前挪动一个单位即可

// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos)
{
	assert(ps->size);
	assert(pos <= ps->size);
	for (int i = pos - 1; i < ps->size; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值