数据结构,(动态)顺序表,C语言实现

——如果代码存在问题,请务必评论告诉我,感激不尽(#^.^#)

——动态和静态的顺序表差别主要在于开辟内存的方式,动态顺序表中的数据所在内存是通过malloc函数实现的,这也意味着,动态顺序表可以更改存储数据的内存大小,其他的话基本没什么差别

1.数据类型定义  struct ElemType

想要建立顺序表,必须先确定顺序表中数据的类型,我这里用的是struct结构体类型,一般的类型(int,char,float)比较简单,所以我就没用(#^.^#),大家可以根据自己的需要进行修改。

typedef struct ElemType
{//元素类型 
	char name[20];
	int age;
	char sex[10]; 
}ElemType;

2.顺序表类型定义  struct SqeList

动态顺序表和静态顺序表的定义有一定的不同,动态顺序表中数据存放地址是动态开辟的,所以类型是一个ElemType*的指针而不是数组;其次动态顺序表的最大存放个数不是一定的,所以需要定义maxsize来描述。

typedef struct SqeList
{//顺序表 
	ElemType* data;
	int length;
	int maxsize;
}SqeList;

3.顺序表初始化  InitList(&L)

动态和静态顺序表在初始化的不同,归根结底是是顺序表结构上的不同。

void InitList(SqeList* L)
{//初始化 
	L->data=(ElemType*)malloc(INITSIZE*(sizeof(ElemType)));
	assert(L->data!=NULL);
	L->length =0;
	L->maxsize=INITSIZE;
}

4.增加内存空间  IncreaseList(&L)

增加内存空间可以通过malloc或者realloc函数来实现,二者使用起来有些区别,realloc更方便,malloc更直观

malloc扩充内存

void IncreaseList(SqeList* L)
{//增加内存空间 
	ElemType* p=(ElemType*)malloc((L->maxsize+INCREASESIZE)*(sizeof(ElemType)));
	assert(p!=NULL);
	//转移数据 
	int i=0;
	for(i=0;i<L->length;i++)
	{
		p[i]=L->data[i];
	}
	free(L->data);
	L->data=p;
	p=NULL;
	L->maxsize+=INCREASESIZE;
	printf("扩容成功!\n");
}

realloc扩充内存

void IncreaseList(SqeList* L)
{//增加内存空间 
	L->data=realloc(L->data,(L->maxsize+INCREASESIZE)*(sizeof(ElemType)));
	assert(L->data!=NULL);
	L->maxsize+=INCREASESIZE;
	printf("扩容成功!\n");
}

5.在位序i上插入数据ListInsert(&L,i,e)

虽然这里的e不改变他的真实值,可以直接传数据,但由于结构体的空间占用比较大,传地址会更高效,所以只要涉及到结构体,我传的大多数是const型的结构体地址,直接传值也是可以的;值得注意的是,位序是从1开始的,而数组的下标是从0开始的,这一点让我挺头疼的o(╥﹏╥)o

bool ListInsert(SqeList* L,int i,const ElemType* e)
{//在位序i上插入数据 
    if(L->length==L->maxsize)
    {
    	printf("空间已经满了!\n");
    	IncreaseList(L);
	}
	if(i>=1&&i<=(L->length+1))
	{
		int j=0;
		for(j=L->length-1;j>=i-1;j--)
		{
			L->data[j+1]=L->data[j];
		}
		L->data[i-1]=*e;
		L->length++;
		printf("插入成功!\n");
		return true;
	}
	printf("插入失败!\n");
	return false;
}

6.删除位序i上的数据  ListDelete(&L,i,e)

因为是顺序表,我们找到对应位序的数据地址是很容易的,所以一般都是按位删除,当然也可以按值删除,不过稍微麻烦一点(一个一个遍历比较,然后找到第一个相同的数据,然后进行删除)。

bool ListDelete(SqeList* L,int i,ElemType* e)
{//删除位序i上的数据 
	if(i<=0||i>L->length)
	{
		printf("删除失败!\n");
		return false;
	}
	*e=L->data[i-1];
	int j=0;
	for(j=i-1;j<L->length-1;j++)
	{
		L->data[j]=L->data[j+1];
	}
	L->length--;
	return true;
}

7.比较数据是否相同  ElemCompare(e1,e2)

由于数据的比较是很常用的,所以我们把他封装出来,这样我们下次用的时候只需要调用就可以了。

int ElemCompare(const ElemType* e1,const ElemType* e2)
{//数据比较,相同返回1,不同返回0 ,不同数据类型的比较方式会不同 
	if(strcmp(e1->name,e2->name)==0&&strcmp(e1->sex,e2->sex)==0&&e1->age==e2->age)
	{
		return 1;
	}
	return 0;
}

 8.查询数据所在的位序  LocateElem(L,e)

int LocateElem(const SqeList* L,const ElemType* e)
{//查找数据,返回位序 
	int i=0;
	for(i=0;i<L->length;i++)
	{
		if(ElemCompare(L->data+i,e)==1)
		{
			return i+1;
		}
	 } 
	return 0;//返回找到元素的位序,0表示不存在 
}

9.单个数据的打印输出  ElemPrint(&L,i)

void ElemPrint(SqeList* L,int i)
{
	printf("%s %d %s \n",L->data[i-1].name,L->data[i-1].age,L->data[i-1].sex);
}

10.顺序表的遍历及打印  ListTraverse(L)

如果你想要遍历做别的事情,可以根据需要修改循环里的内容。

void ListTraverse(SqeList* L)
{
	int i=0;
	for(i=1;i<=L->length;i++)
	{
		ElemPrint(L,i);
	}
}

11.得到第i个位序上的数据  GetElem(L,int i,&e)

因为我们想要得到数据,所以函数的参数需要有一个ElemType* e 类型的,我们通过将主函数中变量的地址传入到函数中,(求出所需数据),解引用将数据传到主函数里。

bool GetElem(const SqeList* L,int i,ElemType* e)
{//取第i个位序上的数据 
	if(i<1||i>L->length)
	{
		return false;
	}
	else
	{
		*e=L->data[i-1];
		return true;
	}
}

 12.判断是否为空表   ListEmpty(L)

bool ListEmpty(const SqeList* L)
{//判断是否为空表 
	if(L->length==0)
	{
		return true;
	}
	return false;
}

  13.全部代码

#include<stdio.h>
#include<string.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>
#define INITSIZE 5 
#define MAXSIZE 5
#define INCREASESIZE 2
void menu()
{
	printf("*************************************\n");
	printf("***1.插入数据       2.删除数据*******\n");
	printf("***3.打印数据表     4.查找数据位序***\n");
	printf("***5.按位查找数据   6.初始化数据表***\n");
	printf("***0.退出程序************************\n");
}
typedef struct ElemType
{//元素类型 
	char name[20];
	int age;
	char sex[10]; 
}ElemType;
typedef struct SqeList
{//顺序表 
	ElemType* data;
	int length;
	int maxsize;
}SqeList;
void InitList(SqeList* L)
{//初始化 
	L->data=(ElemType*)malloc(INITSIZE*(sizeof(ElemType)));
	assert(L->data!=NULL);
	L->length =0;
	L->maxsize=INITSIZE;
}
void IncreaseList(SqeList* L)
{//增加内存空间 
	ElemType* p=(ElemType*)malloc((L->maxsize+INCREASESIZE)*(sizeof(ElemType)));
	assert(p!=NULL);
	//转移数据 
	int i=0;
	for(i=0;i<L->length;i++)
	{
		p[i]=L->data[i];
	}
	free(L->data);
	L->data=p;
	p=NULL;
	L->maxsize+=INCREASESIZE;
	printf("扩容成功!\n");
}
//void IncreaseList(SqeList* L)
//{//增加内存空间 
//	L->data=realloc(L->data,(L->maxsize+INCREASESIZE)*(sizeof(ElemType)));
//	assert(L->data!=NULL);
//	L->maxsize+=INCREASESIZE;
//	printf("扩容成功!\n");
//}
bool ListEmpty(const SqeList* L)
{//判断是否为空表 
	if(L->length==0)
	{
		return true;
	}
	return false;
}
int ListLength(const SqeList* L)
{//返回顺序表元素个数 
	return L->length;
}
bool GetElem(const SqeList* L,int i,ElemType* e)
{//取第i个位序上的数据 
	if(i<1||i>L->length)
	{
		return false;
	}
	else
	{
		*e=L->data[i-1];
		return true;
	}
}
int ElemCompare(const ElemType* e1,const ElemType* e2)
{//数据比较,相同返回1,不同返回0 ,不同数据类型的比较方式会不同 
	if(strcmp(e1->name,e2->name)==0&&strcmp(e1->sex,e2->sex)==0&&e1->age==e2->age)
	{
		return 1;
	}
	return 0;
}
int LocateElem(const SqeList* L,const ElemType* e)
{//查找数据,返回位序 
	int i=0;
	for(i=0;i<L->length;i++)
	{
		if(ElemCompare(L->data+i,e)==1)
		{
			return i+1;
		}
	 } 
	return 0;//返回找到元素的位序,0表示不存在 
}
bool ListInsert(SqeList* L,int i,const ElemType* e)
{//在位序i上插入数据 
    if(L->length==L->maxsize)
    {
    	printf("空间已经满了!\n");
    	IncreaseList(L);
	}
	if(i>=1&&i<=(L->length+1))
	{
		int j=0;
		for(j=L->length-1;j>=i;j--)
		{
			L->data[j+1]=L->data[j];
		}
		L->data[i-1]=*e;
		L->length++;
		printf("插入成功!\n");
		return true;
	}
	printf("插入失败!\n");
	return false;
}
bool ListDelete(SqeList* L,int i,ElemType* e)
{//删除位序i上的数据 
	if(i<=0||i>L->length)
	{
		printf("删除失败!\n");
		return false;
	}
	*e=L->data[i-1];
	int j=0;
	for(j=i-1;j<L->length-1;j++)
	{
		L->data[j]=L->data[j+1];
	}
	L->length--;
	return true;
}
void ElemPrint(SqeList* L,int i)
{
	printf("%s %d %s \n",L->data[i-1].name,L->data[i-1].age,L->data[i-1].sex);
}
void ListTraverse(SqeList* L)
{
	int i=0;
	for(i=1;i<=L->length;i++)
	{
		ElemPrint(L,i);
	}
}
int main()
{
	int i=0;
	int input=0;
	SqeList L1;
	ElemType e1;
	InitList(&L1);
	do
	{
		menu();
		printf("选择操作:"); 
		scanf("%d",&input);
		switch(input)
		{
			case 1:
				printf("分别输入插入数据的姓名年龄性别:\n");
		       	scanf("%s%d%s",e1.name,&(e1.age),e1.sex); 
			    ListInsert(&L1,L1.length+1,&e1);
				break;
			case 2:
				printf("输入要删除的数据所在位序:\n");
				scanf("%d",&i);
				ListDelete(&L1,i,&e1);
				printf("删除的数据是:\n");
				printf("%s %d %s \n",e1.name,e1.age,e1.sex);
				break;
			case 3:
				ListTraverse(&L1); 
				break;
			case 4:
				printf("输入要查找的数据:\n");
				scanf("%s%d%s",e1.name,&(e1.age),e1.sex);
				i=LocateElem(&L1,&e1);
				if(i==0)
				{
					printf("没有此数据!\n");
				}
				else
				{
					printf("该数据的位序为:%d\n",i);
				}
				break;
			case 5:
				printf("输入要查找的数据位序:\n");
				scanf("%d",&i);
				GetElem(&L1,i,&e1);
				printf("%d位上的数据为:\n",i);
				printf("%s %d %s\n",e1.name,e1.age,e1.sex);
				break;
			case 6:
				InitList(&L1);
				printf("初始化成功!\n");
				break;
			default:
				printf("选择错误,重新选择\n");
				break;
		}
	}while(input);
	return 0;
 } 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值