【数据结构】顺序表详解

文章目录


前言

本文详细的介绍了数据结构当中的最基础的顺序表,可以让初学者对顺序表进行深刻的的理解

一、顺序表是什么

顺序表是一种线性结构,它的逻辑上相邻的数据在计算机内的存储位置也是相邻的,可以快速定位第几个元素,中间不允许有空,所以插入、删除时需要移动大量元素。顺序表可以分配一段连续的存储空间。顺序表上的基本操作有:初始化、顺序表头插、尾插、头删、尾删、查找、插入、删除、修改、销毁顺序表。

二、顺序表的基本操作

1.初始化

一个程序要进行首先一个功能,首先要保证要进行初始化。对数据的初始化就如同汽车的车架子相同。

实现思想:

主体思想:为程序开辟所需要的内存空间,并对开辟的结构体进行初始化

顺序表的初始化,首先要保证头节点地址不为空,然后使用malloc函数开辟一个固定大小结构体的空间,使结构体的当中的指针至指向该空间,并且判断是否开辟失败,如果失败perror函数返回开辟失败的原因,并将结构体的其他的变量进行初始化

代码如下(示例):

void SLInit(SL* ps)
{
	assert(ps);
	ps->a = (SLDataType*)malloc(sizeof(SLDataType)*4);
	if (ps->a == NULL)
	{
		perror("malloc failed");
		return;
	}
	ps->size = 0;
	ps->capacity = 4;
}

2.顺序表扩容函数

扩容函数主要是为满足增加功能在使用时的内存不足的情况,而该函数可以帮助函数进行空间的扩大

实现思想:

主体思想:先判断该结构体指向的地址不为空,然后进行数据存放数量和空间大小进行比较,如果有效存储空间满了就进行空间的增补,使用realloc函数进行在原来的空间的后面开辟空间,开辟失败就返回原因,并结束程序,开辟成功就在对指针进行重新的赋值有效空间同样进行跟改。

代码如下(示例):

void SLCheckCapacity(SL* ps)
{
	assert(ps);
	// 满了要扩容
	if (ps->size == ps->capacity)
	{
		SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * (sizeof(SLDataType)));
		if (tmp == NULL)
		{
			perror("realloc failed");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
}

3.顺序表头插

顺序表的头插的通俗理解:

就像在超市结账时一条长长的,尽然有序的买完东西人们正在排着队,突然来了一个人,以非常豪横的态度要第一个结账,大家看这个人不好惹,不想自找麻烦,就默认让这个人插了队,这个人插了队不要紧,因为他一个的插队造成第一个位置原本只能一个人的位置,现在两个人站着那里,就比较拥挤,这个时候,那个豪横的人就向后面的人说往后退一个位置,后面的人就和他后面的人说让个位置,就这样一个人的插入让整个队伍向后退了一个位置。

实现思想:

主体思想:判断结构体地址不为空。在判断空间是否足够,不够就扩容,然后利用数据的下标写一个循环进行数据向后移动,循环完的顺序表就可以利用下标在数组头部进行插入,再让有效数据的大小进行加一位

代码如下(示例):

void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
    // 挪动数据
	int end = ps->size - 1;
	while (end >= 0)
	{
	    ps->a[end + 1] = ps->a[end];
	    --end;
	}
	ps->a[0] = x;
	ps->size++;
}

代码实现图(示例):

4.顺序表尾插

实现思想:

主体思想:就数值的末端添加一个数据

先判断传的地址是否为空,在进行扩容判断,在通过下标添加数据

代码如下(示例):

void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
	
}

代码实现图(示例):

5.顺序表尾删

实现思想:

主体思想:将最后一个数值释放控制权

确保传的地址和有效大小不为空,再对有效大小减少一位,这样就删除了尾数据。因为数据在空间当中的存储是比特,释放控制权就是让空间可以被其他人利用,我们不要了,不对其进行访问。

代码如下(示例):

void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);
	ps->size--;
}

代码实现图(示例):

6.顺序表头删

实现思想:

主体思想:让数据此前往后的进行打印复制

代码如下(示例):

void SLPopFront(SL* ps)
{
	assert(ps);

	assert(ps->size > 0);

	int begin = 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		++begin;
	}

	ps->size--;
}

代码实现图(示例):

7.顺序表查找

实现思想:

主体思想:通过下标指向的值进行判断来寻找

代码如下(示例):

int SLFind(SL* ps, SLDataType x)
{
	assert(ps);

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

代码实现图(示例):

8.顺序表任意位置插入

实现思想:

主体思想:通过查找函数找到下标,将下标及后面的数据进行移动,再将新的数值通过下标插入进去。

代码如下(示例):

void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);

	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);

	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	ps->a[pos] = x;
	ps->size++;
}

代码实现图(示例):

9.顺序表任意位置删除

实现思想:

主体思想:通过下标来找到那个位置的值,让后面的数值向前面进行覆盖。

代码如下(示例):

void SLErase(SL* ps, int pos)
{
	assert(ps);

	assert(pos >= 0 && pos < ps->size);

	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		++begin;
	}

	ps->size--;
}

代码实现图(示例):

10.销毁顺序表

实现思想:

主体思想:将指针指向的空间释放,然后在将该空间赋为空。

代码如下(示例):

void SLDestroy(SL* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}

11.顺序表打印

实现思想:

主体思想:和打印数组相同

代码如下(示例):

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

代码实现图(示例):

12.顺序表修改

实现思想:

主体思想:通过下标找到该元素,对该元素进行再次赋值

代码如下(示例):

void SLModify(SL* ps, int pos, SLDataType x)
{
	assert(ps);

	assert(pos >= 0 && pos < ps->size);

	ps->a[pos] = x;
}

代码实现图(示例):

总结

以上就是数据结构当中的顺序表的全部功能的实现,通过思想和代码实现,和效果图让初学者也可以快速上手。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
心中带点小风骚的头像心中带点小风骚普通用户
上一篇 2023年12月8日
下一篇 2023年12月8日

相关推荐