数据结构3:线性表2-顺序存储的线性表

文章目录

简介

作为线性表的一种,顺序存储的线性表(以后简称:顺序表)在存储结构上更像是一种数组,与数组不同的是,它在操作上要复杂一些,但是与线性表的操作一致(毕竟数据表是线性表的一种)。本章节将对顺序表的定义和操作进行详细的讲解和实现。

顺序表长度与最大长度之间的关系:

由于顺序表的存储结构是顺序存储,它的元素存储在一片连续的存储空间。因此,顺序表的最大长度从建立是就已经固定,无法动态的增加或减少。顺序表长度是指顺序表内数据元素的个数,会随着数据元素的插入或删除而增加或减少;最大长度是指存储空间内所允许容纳最多的数据元素的个数。如图1所示:顺序表中是数据元素为E类型的数据,存储区间可容许数据元素个数为8,因此最大数据长度为8;顺序表中的共5个数据元素,因此顺序表的长度为5。需要注意的是,顺序表元素的位置是指相对于表中其他元素的位置,而不是相对于存储区间的位置。

数据类型定义:

c 复制代码
#define LIST_LEN 10 //定义顺序表的最大长度
typedef struct 		 //定义顺表数据类型
{
	int data;
}element;
typedef struct		//定义线性表数据类型
{
	int element[LIST_LEN];
	int length;
}List;

定义顺序表首先需要定义其长度(LIST_LEN),用于规定表中最多元素个数;element为元素类型结构体,包含int 类型的数据data,根据实际应用不同,element的类型可以修改;List是顺序表定义类型,它包含了LIST_LEN个element类型的元素和顺序表长度length。

线性表API函数及其具体实现:

创建函数:

c 复制代码
List* ListCreate()
{
	//新建一个List类型的指针,并将分配空间
	List *temp = (List *)malloc(sizeof(List));
	//将顺序表的长度,设置为0
	temp->length = 0;
	//返回指针
	return temp;
}

创建一个顺序表函数的作用是,在堆区分配一个List大小的内存空间,将顺序表长度设置为0。它的数据元素存储区、顺序表长度和存储区间长度关系如图2所示。函数的最后返回一个List 类型的指针,使用时可以先定义一个List类型的指针,将ListCreate函数的返回值赋值给该指针,即完成了顺序表的创建。

函数应用代码如下:

c 复制代码
List * MyList = NULL;//建立一个线性表指针
MyList = ListCreate();//建立一个线性表

销毁函数:

销毁函数的作用是将List 类型指针指向的内存空间释放掉,必将它指向NULL(避免野指针)。函数参数为二级指针,因为我们将要一个指针的值,根据值传和地传的概念,我们只能用二级指针才能修改一级指针的值。

c 复制代码
int ListDestory(List **list)
{
	if (*list == NULL)
	{
		//如果顺序表是否已经销毁,返回-1
		return -1;
	}
	//释放顺序表内存空间
	free(*list);
	//将顺序表指针指向NULL
	*list = NULL;
	return 0;
}

函数应用代码如下:

c 复制代码
ListDestory(&MyList);

清空函数:

清空函数只是将顺序表内的数据元素清空,因此只要将顺序表的长度清0,数据元素便不会再被访问,即实现清空数据元素;后续的插入覆盖原来的元素实现了元素的插入。

c 复制代码
int ListClear(List *list)
{
	if (list == NULL)
	{
		//如果输入参数为NULL,返回-1
		return -1;
	}
	//将顺序表长度设置为0
	list->length = 0;
	return 0;
}

函数应用代码如下:

c 复制代码
ListClear(MyList);

长度获取函数:

长度获取函数的作用是,返回顺序表的长度,便于用户了解此时的顺序表的长度。

c 复制代码
int ListGetLength(List *list)
{
	if (list == NULL)
	{
		//如果输入参数为NULL,返回-1
		return -1;
	}
	//返回顺序表长度
	return list->length;
}

函数应用代码如下:

c 复制代码
listLen = ListGetLength(MyList);

相应位置元素获取函数:

长度获取函数的作用是将顺序表中相应位置的元素复制一份,通过函数参数将该元素传递出去,如图所示。

c 复制代码
int ListGet(List *list, int position,element *ele)
{
	if (list == NULL || position < 0 || position >= list->length)
	{
		//如果list为NULL,position小于0或者大于最大长度,返回-1
		return -1;
	}
	*ele = list->member[position];
	return 0;
}

函数应用代码如下:

c 复制代码
ListGet(MyList,i,&temp);

插入元素函数:

c 复制代码
int ListAdd(List *list, int position, element e)
{
	int i;
	//判断输入参数是否有误
	if (list == NULL || position < 0 || position >LIST_LEN)
	{
		//如果list为NULL,position小于0或者大于最大长度,返回-1
		return -1;
	}
	if (list->length == LIST_LEN)
	{
		//如果顺序表已满,返回-2
		return -2;
	}
	if (position == list->length)
	{
		//如果插入位置在末尾,在末尾加入元素
		list->member[position] = e;
		//顺序表长度加1
		list->length++;
		return 0;
	}
	//将从position开始位置的元素向后移动一个位置
	for (i = list->length; i > position; i--)
	{
		list->member[i] = list->member[i-1];
	}
	//在插入位置插入元素(此时i==position)
	list->member[i] = e;
	//顺序表长度加1
	list->length++;
	return 0;
}

在元素进行插入时,首先要进行输入参数的检测,主要是检测指针是否为空,插入位置是否符合要求;然后判断顺序表是否已满,若已满,返回-2,否则继续插入元素。此时元素的插入有两种情况:

第一种:在顺序表末尾插入元素,如图4左侧图所示。因为我们元素下标从0开始,因此,当插入位置position大于或等于顺序表长度时(大于时可插入是为了提高使用方便性,但是严谨性降低,实际使用可以进行调整),表示在表尾部插入,此时将表中相应位置元素赋值即可。在图4左侧图中,顺序表长度为5,我们在下标5处插入新的元素,即实现了顺序表元素的尾部插入,插入成功后,顺序表长度加1,函数返回。

第二种:在顺序表中间位置插入元素,如图4右侧所示。在顺序表中间位置插入元素时,需要先将插入位置及其后面的元素,向后移动一位,然后将插入位置元素赋值为新元素。在图4右侧中,我们要在位置1处插入新的元素,因此需要将E1-E5向后移动一位,移动时从后面的元素开始(从前开始,元素会覆盖丢失),移动到插入位置。移动完成后,在位置1处插入元素,顺序表长度加1,函数返回。

应用代码如下:

c 复制代码
ListAdd(MyList,0,data0);
ListAdd(MyList,0,data1);
ListAdd(MyList,0,data2);

删除元素函数:

c 复制代码
int ListDelete(List *list, int position,element *e)
{
	int i;
	//判断输入参数是否有误
	if (list == NULL || position < 0 || position >= list->length)
	{
		//如果list为NULL,position小于0或者大于最大长度,返回-1
		return -1;
	}
	if (list->length == 0)
	{
		//如果顺序表已空,返回-2
		return -2;
	}
	//保存要删除位置的元素
	if (e != NULL)
	{
		*e = list->member[position];
	}
	//如果要删除元素在末尾
	if (position == list->length -1)
	{
		//顺序表长度减1
		list->length--;
		return 0;
	}
	//position位置之后,所有的元素向前移动
	for (i = position; i < list->length -1; i++)
	{
		list->member[i] = list->member[i + 1];
	}
	//顺序表长度减1
	list->length--;
	return 0;
}

元素的删除与元素的插入有类似之处,首先进行输入参数的检测,判断顺序表指针是否为空,判断要删除的元素的位置是正确。如果此时,表中无元素,表长度为0,此时返回错误;否则进行元素删除。元素的删除也分为两种情况,不过在删除前,可以选择将元素取出或者不取出(删除前进行)。

第一种:要删除的元素在顺序表的尾部,如图5左侧图所示。删除前,顺序表长度为5,要删除的元素位置为4。删除元素时,只需要将顺序表长度减1,以后就无法对该位置的元素读取,即实现了元素的删除。

第二种:要删除的元素在顺序表中间位置,只需要将要删除位置元素后面的元素以此前移一位,然后将顺序表长度减1,即实现了元素的删除。

应用代码如下:

c 复制代码
ListDelete(MyList,0,NULL);

小结

顺序表结构及其功能函数较为简单,它们的主要功能都是对元素存储位置来实现的。在在顺序表学习中,要理解好存储区间长度和顺序表长度的区别,元素存储位置的变换(特别是在元素插入和删除的时候)。因此,想学好顺序表,首先要对C语言中的数据有较深刻的理解,理解和熟练掌握了数组,顺序表就很简单了!

相关推荐
1白天的黑夜14 小时前
递归-24.两两交换链表中的节点-力扣(LeetCode)
数据结构·c++·leetcode·链表·递归
阿拉-M834 小时前
IntelliJ IDEA Windows 系统高频快捷键使用手册
java·windows·intellij-idea
1白天的黑夜14 小时前
递归-206.反转链表-力扣(LeetCode)
数据结构·c++·leetcode·链表·递归
靠近彗星4 小时前
3.1 栈
数据结构·算法
lingggggaaaa4 小时前
小迪安全v2023学习笔记(一百三十四讲)—— Windows权限提升篇&数据库篇&MySQL&MSSQL&Oracle&自动化项目
java·数据库·windows·笔记·学习·安全·网络安全
孤廖6 小时前
吃透 C++ 栈和队列:stack/queue/priority_queue 用法 + 模拟 + STL 标准实现对比
java·开发语言·数据结构·c++·人工智能·深度学习·算法
豆沙沙包?6 小时前
2025年--Lc197-077. 排序链表(链表,尾插法)--Java版
java·数据结构·链表
杨福瑞7 小时前
C语言数据结构:算法复杂度(2)
c语言·开发语言·数据结构
是店小二呀8 小时前
远程办公自由:rdesktop+cpolar让Windows桌面随身而行
windows