数据结构——顺序表

目录

一、顺序表的基本概念

二、顺序表的定义和初始化

1.数据类型定义

2.顺序表的定义和初始化

2.1顺序表的定义

2.1顺序表的初始化

2.3另一个方法的顺序表的定义和初始化

图示

三、顺序表的建立

四、顺序表的输出

五、顺序表的插入

代码解析

插入过程图示

六、顺序表的删除

六、查找顺序表中数据的操作

6.1 按位置求值

6.2 按值求位置

七、代码总览

八、总结

适用情况


一、顺序表的基本概念

        顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系,采用顺序存储结构的线性表通常称为顺序表。顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中。


二、顺序表的定义和初始化

1.数据类型定义

typedef struct     //定义数据类型
{
	char id[N];
	char name[N];
	double price;
}Book;

本篇文章用的数据类型为结构体型。

2.顺序表的定义和初始化

2.1 顺序表的定义

typedef struct         //定义顺序表
{
	Book* data;           //数据的类型
	int length;           //数据的长度
}SQlist;

这次命名了一个名为SQlist的顺序表,其中Book *data为顺序表中的数据类型,length为顺序表的实际长度。

2.1 顺序表的初始化

顺序表的初始化既建立一个空表,并将表长设为1

void InitList(SQlist* L)            //初始化
{
	L->data = (Book*)malloc(sizeof(Book)*N);      //动态分配内存空间
	L->length = 0;                                //设表长为一
}

在主函数中引用定义一个顺序表再引用该函数,并将顺序表的指针传入函数

L->data = (Book*)malloc(sizeof(Book)*N);既动态分配N个Book类型大小的空间给顺序表

L->length = 0;既将表长设为1;

2.3 另一个方法的顺序表的定义和初始化

注:若使用静态分配内存空间则不需要使用L->data = (Book*)malloc(sizeof(Book)*N);

静态分配内存空间的方法定义和初始化顺序表

typedef struct         //定义顺序表
{
	Book data[N];           //数据的类型
	int length;           //数据的长度
}SQlist;

void InitList(SQlist* L)            //初始化
{
	L->length = 0;                                //设表长为一
}

图示


三、顺序表的建立

void CreateList(SQlist* L,int n)       //建立顺序表
{
	int i;
	for (i = 0; i < n; i++)              //循环输入数据
	{
		printf("请输入第%d个数据:", i+1);
		scanf("%s %s %lf", &L->data[i].id, &L->data[i].name, &L->data[i].price);
	}
	L->length = i;                  //重新设置表长
}

从键盘输入循环输入数据,并将这些数据存入顺序表中,最后修改表长。


四、顺序表的输出

void printfList(SQlist* L)         //输出顺序表上的数据
{
	int i;
	for (i = 0; i < L->length; i++)            //用循环输出顺序表的数据
	{
		printf("%s %s %.2lfn", L->data[i].id, L->data[i].name, L->data[i].price);
	}
}

用for循环即可输出顺序表中的元素


五、顺序表的插入

int Insdata(SQlist* L)            //插入数据
{
	Book x;
	int i = 0, j = 0;
	printf("input data:");
	scanf("%s %s %lf", &x.id, &x.name, &x.price);
	printf("input i:");
	scanf("%d", &i);
	if (i<1 || i>L->length + 1)                //判断插入位置是否合法
	{
		printf("输入位置错误n");
		return 0;
	}
	if (L->length >= N)             //判断表是否为满
	{
		printf("表满n");
		return 0;
	}
	if (i == L->length + 1)             //如果插入的位置为最后一位
	{
		L->data[i - 1] = x;
		L->length++;
		return 0;
	}
	for (j = L->length - 1; j >= i - 1; j--)              
	{
		L->data[j + 1] = L->data[j];               //从最后一位开始后移
	}
	L->data[i - 1] = x;
	L->length++;
	return 1;

}

代码解析

将数据存在x中

    Book x;
	printf("input data:");
	scanf("%s %s %lf", &x.id, &x.name, &x.price);

判断i的位置是否合法,和判断表是否已满。

if (i<1 || i>L->length + 1)                //判断插入位置是否合法
	{
		printf("输入位置错误n");
		return 0;
	}
	if (L->length >= N)             //判断表是否为满
	{
		printf("表满n");
		return 0;
	}

若插入的位置为当顺序表的最后,则直接插入

if (i == L->length + 1)             //如果插入的位置为最后一位
	{
		L->data[i - 1] = x;
		L->length++;
		return 0;
	}

若插入的位置不为最后一位则从最后一位开始各向后移一位

for (j = L->length - 1; j >= i - 1; j--)              
	{
		L->data[j + 1] = L->data[j];               //从最后一位开始后移
	}
	L->data[i - 1] = x;
	L->length++;

最后将x插入,并将表长+1

for (j = L->length - 1; j >= i - 1; j--)              
	{
		L->data[j + 1] = L->data[j];               //从最后一位开始后移
	}
	L->data[i - 1] = x;
	L->length++;

插入过程图示


六、顺序表的删除

int DelList(SQlist* L,Book *x)          //删除操作
{
	int i = 0;
	int j = 0;
	printf("input i:");
	scanf("%d", &i);
	if (i<1 || i>L->length)                //判断删除位置是否合法
	{
		printf("输入位置错误n");
		return 0;
	}
	if (L->length ==0 )             //判断表是否为空
	{
		printf("表为空n");
		return 0;
	}
	*x = L->data[i - 1];
	for (j = i; j < L->length; j++)
	{
		L->data[j - 1] = L->data[j];         //前移一位
	}
	L->length--;               //表长减一
	return 1;
}

顺序表的删除与插入差不多,区别就在于插入是往后移,而删除是往后移。

根据需求,也可以用一个Boox *来保存删除的数据。


六、查找顺序表中数据的操作

6.1 按位置求值


int Getdata(SQlist* L, Book *x)        //按位置求值
{
	int i = 0;
	printf("input i:");
	scanf("%d", &i);
	if (i<1 || i>L->length)      //判断位置是否正确
	{
		printf("输入位置错误n");
		return 0;
	}
	else
	{
		*x = L->data[i - 1];  //带出数据
		return 1;
	}
}

注:顺序表的下标与数组相同,第i个数据的下标为i-1。

6.2 按值求位置

int Getdata2(SQlist* L)        //按值求位置
{
	Book x;
	printf("input data:");
	scanf("%s %s %lf", &x.id, &x.name, &x.price);
	int i;
	for (i = 0; i < L->length; i++)                    //遍历判断是否相等
	{
		if (strcmp(x.id, L->data[i].id) == 0 && strcmp(x.name, L->data[i].name)==0 && x.price == L->data[i].price)
		{
			printf("位置为:%dn", i + 1);
			return 1;
		}
	}
	if (i = L->length)                           
	{ 
		printf("未找到该数据n");
	}
	return 0;
}

注:在比较字符串时不能直接比较,要用strcmp()函数。

       遍历比较顺序表的每一项,当i>表长时既顺序表中没有该数据。


七、代码总览

#define  _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 20
typedef struct     //定义数据类型
{
	char id[N];
	char name[N];
	double price;
}Book;

typedef struct         //定义顺序表
{
	Book* data;           //数据的类型
	int length;           //数据的长度
}SQlist;

void InitList(SQlist* L)            //初始化
{
	L->data = (Book*)malloc(sizeof(Book)*N);      //动态分配内存空间
	L->length = 0;                                //设表长为一
}

void CreateList(SQlist* L,int n)       //建立顺序表
{
	int i;
	for (i = 0; i < n; i++)              //循环输入数据
	{
		printf("请输入第%d个数据:", i+1);
		scanf("%s %s %lf", &L->data[i].id, &L->data[i].name, &L->data[i].price);
	}
	L->length = i;                  //重新设置表长
}

void printfList(SQlist* L)         //输出顺序表上的数据
{
	int i;
	for (i = 0; i < L->length; i++)            //用循环输出顺序表的数据
	{
		printf("%s %s %.2lfn", L->data[i].id, L->data[i].name, L->data[i].price);
	}
}

int Getdata(SQlist* L, Book *x)        //按位置求值
{
	int i = 0;
	printf("input i:");
	scanf("%d", &i);
	if (i<1 || i>L->length)      //判断位置是否正确
	{
		printf("输入位置错误n");
		return 0;
	}
	else
	{
		*x = L->data[i - 1];  //带出数据
		return 1;
	}
}

int Getdata2(SQlist* L)        //按值求位置
{
	Book x;
	printf("input data:");
	scanf("%s %s %lf", &x.id, &x.name, &x.price);
	int i;
	for (i = 0; i < L->length; i++)                    //遍历判断是否相等
	{
		if (strcmp(x.id, L->data[i].id) == 0 && strcmp(x.name, L->data[i].name)==0 && x.price == L->data[i].price)
		{
			printf("位置为:%dn", i + 1);
			return 1;
		}
	}
	if (i = L->length)                           
	{ 
		printf("未找到该数据n");
	}
	return 0;
}

int Insdata(SQlist* L)            //插入数据
{
	Book x;
	int i = 0, j = 0;
	printf("input data:");
	scanf("%s %s %lf", &x.id, &x.name, &x.price);
	printf("input i:");
	scanf("%d", &i);
	if (i<1 || i>L->length + 1)                //判断插入位置是否合法
	{
		printf("输入位置错误n");
		return 0;
	}
	if (L->length >= N)             //判断表是否为满
	{
		printf("表满n");
		return 0;
	}
	if (i == L->length + 1)             //如果插入的位置为最后一位
	{
		L->data[i - 1] = x;
		L->length++;
		return 0;
	}
	for (j = L->length - 1; j >= i - 1; j--)              
	{
		L->data[j + 1] = L->data[j];               //从最后一位开始后移
	}
	L->data[i - 1] = x;
	L->length++;
	return 1;

}

int DelList(SQlist* L,Book *x)          //删除操作
{
	int i = 0;
	int j = 0;
	printf("input i:");
	scanf("%d", &i);
	if (i<1 || i>L->length)                //判断删除位置是否合法
	{
		printf("输入位置错误n");
		return 0;
	}
	if (L->length ==0 )             //判断表是否为空
	{
		printf("表为空n");
		return 0;
	}
	*x = L->data[i - 1];
	for (j = i; j < L->length; j++)
	{
		L->data[j - 1] = L->data[j];         //前移一位
	}
	L->length--;               //表长减一
	return 1;
}

int main()
{
	SQlist L;
	Book x;
	Book Del;
	int n=0;
	//输入数据个数
	printf("input n:");
	scanf("%d", &n);
	//初始化
	InitList(&L);
	//创建链表并输出
	CreateList(&L,n);
	printfList(&L);
	//按位置求值
	Getdata(&L,&x);
	printf("%s %s %.2lfn", x.id,x.name,x.price);
	//按值求位置
	Getdata2(&L);
	//插入数据并输出
	Insdata(&L);
	printfList(&L);
	//删除数据并输出
	DelList(&L,&Del);
	printfList(&L);
	return 0;
}

八、总结

     顺序表要预先分配空间,会导致空间闲置或溢出,采用随机存取,时间复杂度为O(1),但删除和插入要一项一项的移动,时间复杂度为O(n)。

适用情况

1.表长变化不大,且能事先确定变化的范围

2.很少进行插入或删除操作,经常按元素序号访问数据元素