一、线性表
线性表是一种基本的数据结构,广泛用于计算机学中,它的核心概念如下:
- 线性表的概念:线性表(Linear List)是由一组相同类型的元素按现行顺序排列组成的集合,每个元素在表中都有一个确定的位置,且位置之间具有顺序结构,线性表可以用来表示许多不同的实际数据结构,如数组,链表
- 线性表的基本操作包括以下几点(增删改查等操作)
- 插入:在指定位置插入一个新元素
- 删除:删除指定位置的元素
- 访问:获取指定位置的元素
- 查找:在表中查找指定元素的位置
- 更新:修改指定位置的元素
3.线性表的特点:
- 顺序性:元素按顺序排列,每个元素有一个前驱和后继(除了第一个和最后一个元素)
- 线性关系:元素之间有明确的线性关系,即前一个元素和后一个元素的关系是确定的。
4.静态存储的线性表:
在静态存储中,线性表通常使用固定大小的数组来实现,这种方法的优点是操作简单且速度快,因为可以通过索引直接访问元素。但是,它的缺点是存储空间的浪费和在大小在不够时扩展困难。
5.动态存储的线性表
动态存储的线性表通常是指那些使用动态数据结构来实现的线性表,最常见的动态存储线性表的实现是链表。
既然在这提到了链表,我们就简单提一下,具体内容会在下一篇博客。
6.单链表:
是一种常见的动态存储线性表的实现方式,基本结构如下:
节点:每个节点包含两部分:数据部分和指针部分,数据部分存储元素的值,指针部分指向下一个节点。
头指针:指向链表的第一个节点(这里我们可以理解为数组的首地址元素,但不能混淆),链表中的最后一个节点的指针部分为NULL,表示链表的结束。
提到了线性表,那我们就需要敲个代码具体看一下了:
二、顺序表的增删改查
这个程序实现了线性表的静态存储方式和动态存储方式的增删改查的基本操作,所以看上去会有一点点的长和枯燥,后续Leo会改进的。
Leo对本程序只检验了查找,插入的功能,其他功能暂时没测,有问题的地方请大家帮忙指正
/*该文件实现线性表的基本功能,完成表创建,初始化,增删改查等任务的简单实现
*作者:Linux初学者Leo,时间:2024.08.10
*/
#include <stdio.h>
#include <stdlib.h>
#define SIZEINCREMENT 10
#define VALID_INDEX(index, count) ((index) >= 0 && (index) <= (count))
//#include <string.h>配合memset()使用
//静态顺序表的定义
struct LIST
{
int data[10];//静态分配方式
int count;//存储当前顺序表已经存储数据的数量
};
void init_list(struct LIST *L)
{
L->count = 0;
for(int i = 0;i < 10;i++)
L->data[i] = 0;
}
//动态顺序表的定义
struct LIST2
{
int *data;//存储数据空间的指针
int count;//存储当前顺序表已经存储数据的数量
int listsize;//存储当前分配空间的大小
};
void init_list2(struct LIST2 *L)
{
/*
* L->data =(int *) malloc(10 * sizeof(int));malloc()在开辟空间后不会自动初始化内存,会导致产生垃圾数
* memset(L->data, 0, 10 * sizeof(int));使用memset()将内存区域初始化为零,或在分配内存后立即为数组元素赋初始值
* memset()配合malloc() 使用,可以解决malloc在开辟空间时产生垃圾数的问题
* 这里根据编译器的不同,大家可以选择不同的方法,Leo使用的编译器是DEVC++,我在这里选择的calloc()
*/
L->data = (int *)calloc(10, sizeof(int));//calloc()分配并自动初始化内存
L->count = 0;
L->listsize = 10;
}
/*判空操作
参数:顺序表结构体指针
返回值:为空返回0,非空返回-1
*/
int isempty(struct LIST *L)
{
if(L->count == 0)
return 0;
else
return -1;
}
/*查数据
参数1:顺序表结构体指针
参数2:位置/值
返回值:如果参数2是位置,返回当前位置值,如果是某个值,返回该值在表中的位置,失败返回-1
*/
int findindex(struct LIST *L,int elem)
{
for(int i=0;i<L->count;i++)
if(L->data[i] == elem)
return i;//i从0开始,当取值为0,表示该元素存在,放在首位
//for循环结束,没找到数据
return -1;
}
//index从0开始取,当为0时,表示获取首元素
int findelem(struct LIST *L,int index)
{
if((index>L->count) || (index<0))//如果超限或者无效
return -1;
return L->data[index];
}
/*改数据
参数1:指向顺序表结构体的指针
参数2:指定修改的位置
参数3:指定修改的新值
返回值:成功返回0,失败返回-1
*/
int changeelem(struct LIST *L,int index,int elem)
{
if(findelem(L,index) == -1)
return -1;
else
{
L->data[index] = elem;
return 0;
}
}
/*向静态存储结构的顺序表中,插入数据
参数1:线性表指针
参数2:要插入的位置
参数3:要插入的值
返回值:成功返回0,失败返回-1
*/
int insert_list_static(struct LIST *L, int index, int elem)
{
int i;
if (!VALID_INDEX(index, L->count) || L->count >= 10)
return -1; // 位置非法或表满
for (i = L->count; i > index; i--)
L->data[i] = L->data[i - 1];
L->data[index] = elem;
L->count++;
return 0;
}
/*向动态存储结构的顺序表中,插入数据
参数1:指向顺序表的指针
参数2:位置
参数3:值
返回值:成功返回0,失败返回-1
*/
int insert_list_dynamic(struct LIST2 *L,int index,int elem)
{
int *newbase;
if((index < 0) || (index>L->count))
return -1;
if(L->count == L->listsize)//空间已满
newbase=(int *)realloc(L->data,(L->listsize+SIZEINCREMENT)*sizeof(int));
if(newbase == NULL)
return -1;//空间开辟失败
for(int i=L->count;i>index;i--)//存储元素
L->data[i]=L->data[i-1];
L->data[index] = elem;
L->count++;
return 0;
}
//输出函数
void list_printf(struct LIST sqlist1,struct LIST2 sqlist2)
{
printf("sqlist1已使用的元素个数%d\n",sqlist1.count);
printf("salist1顺序表里的元素为:\n");
for(int i=0;i<10;i++)
printf("%d ",sqlist1.data[i]);
printf("\n");
printf("sqlist2已使用的元素个数%d\n",sqlist2.count);
printf("sqlist2申请空间元素的个数%d\n",sqlist2.listsize);
printf("salist2顺序表里的元素为:\n");
for(int i=0;i<10;i++)
printf("%d ",sqlist2.data[i]);
printf("\n");
}
int main()
{
//创建顺序表
struct LIST sqlist1;//静态
struct LIST2 sqlist2;//动态
//初始化
init_list(&sqlist1);//静态
init_list2(&sqlist2);//动态
//打印静态顺序表
if(isempty(&sqlist1) == 0)
printf("sqlist1是空\n");
else
printf("sqlist1非空\n");
insert_list_static(&sqlist1,0,15);//向静态存储的顺序表,首位插入15
list_printf(sqlist1,sqlist2);//静态输出顺序表
if(isempty(&sqlist1) == 0)
printf("sqlist1是空\n");
else
printf("sqlist1非空\n");
changeelem(&sqlist1,0,20);
list_printf(sqlist1,sqlist2);//输出顺序表
return 0;
}