线性表-list
啥叫线性表呢? ---线性表是零个或者多个数据元素的序列。
线性表是一种穿起来的元素,具有一定的顺序,就像排队买东西一样,一个元素和一个元素之间有顺序,类似于数组,也可以理解成数组。看他的概念需要明确一些东西,他是一个序列,他就有一定的顺序,他的头元素只有后驱,尾元素只有前驱,中间节点两者都有,一个一个排起来的数据结构。
当线性表元素的个数n(n>=0)定义为线性表的长度,当n=0时,为空表。在非空的表中每个元素都有一个确定的位置,如果a1是第一个元素,那么an就是第n个元素。
依照他的存储位置的区分,它可以有两种存储结构
顺序存储的线性表和链式存储的线性表
线性表的顺序存储结构是指用一段地址连续的存储单元一次存储线性表的数据元素。
链式结构是指线性表链式存储结构的特点是一组任意的存储单位存储线性表的数据元素,存储单元可以是连续的,也可以不连续。可以被存储在任意内存未被占用的位置上。
他们之间各具有各自的优缺点这个再文末就行对比。
我们先来讲顺序存储的线性表
1、线性表的常规操作 ADT
typedef struct person {
char name[32];
char sex;
int age;
int score;
}DATATYPE;
这里定义一个DATATYPE的数据结构体,他里面存有一个学生的基本信息
name名字,sex性别,arg 年龄,score 分数
以一个结构体为线性表的一个数据节点
typedef int Datatype;
typedef struct list {
DATATYPE *head;
int tlen;
int clen;
}SeqList;
定义一个线性表,以DATATYPE为指针数据的头节点,int 一个tlen总长int一个clen目前长度构成一个线性表。
SeqList* CreateSeqList(int size);
int DestroySeqList(SeqList*sl);
int InsertTailSeqList(SeqList *list, DATATYPE *data);
int IsFullSeqList(SeqList *list);
int IsEmptySeqList(SeqList *list);
int ShowSeqList(SeqList* list);
int GetSizeSeqList(SeqList* list);
int FindSeqList(SeqList *list, char *name);
DATATYPE* GetSeqListItem(SeqList *list,int ind);
int InsertPosSeqList(SeqList *list, DATATYPE *data, int pos);
int ModifySeqList(SeqList *list, char *old, DATATYPE *newdata);
int DeleteSeqList(SeqList *list, char *name);
int CleanSeqList(SeqList *list);
这些是一个线性表的基本操作,创建,增删改查,清除元素等;
下面我们以一个我示例来详细的了解这些结构和代码。
以下是具体函数
SeqList *CreateSeqList(int size)
{
if(size<=0)
{
fprintf(stderr,"size is error,range >1");
return NULL;
}
SeqList* sl = ( SeqList*)malloc(sizeof(SeqList));
if(NULL == sl)
{
perror("CreateSeqList malloc");
exit(1);
}
sl->head = (DATATYPE*)malloc(sizeof(DATATYPE)*size);
if(NULL == sl->head)
{
perror("CreateSeqList malloc");
exit(1);
}
sl->tlen = size;
sl->clen = 0;
return sl;
}
创建线性表,得到一个seqlist的一个指针,参数是一个size就是线性表中需要开辟的线性存储空间范围。三个if判断是异常处理,以免数据的出错,和开辟空间的失败。sl是线性表,sl.head是头元素也得开辟空间,sl.clen = 0,此时没有节点现在位置就只有0;sl.tlen = size,线性表的总长度是定义的参数size。返回这个线性表指针创建结束。
int IsFullSeqList(SeqList *list)
{
return list->clen == list->tlen;
}
int IsEmptySeqList(SeqList *list)
{
if((list->clen == 0)&&(list->tlen == 0))
{
return 1;
}
return 0;
}
int ShowSeqList(SeqList *list)
{
int i = 0 ;
int len = GetSizeSeqList(list);
for(i=0;i<len;i++)
{
printf("name:%s sex:%c age:%d score:%d\n",list->head[i].name,list->head[i].sex,list->head[i].age
,list->head[i].score);
}
return 0;
}
这是判断满了还是空了的函数,直接通过clen和tlen的大小判断简单不做过多解释。打印数据和得到当前位置也很简单。
int InsertTailSeqList(SeqList *list, DATATYPE *data)
{
if(IsFullSeqList(list))
{
fprintf(stderr,"InsertTailSeqList error ,seqlist is full\n");
return 1;
}
//list->head[list->clen] = *data;
memcpy(&list->head[list->clen] , data,sizeof(DATATYPE));
list->clen++;
return 0;
}
int InsertPosSeqList(SeqList *list, DATATYPE *data, int pos)
{
if(NULL == list)
{
fprintf(stderr,"list is null\n");
return 1;
}
if(IsFullSeqList(list))
{
fprintf(stderr,"list is full\n");
return 1;
}
if(pos<0 ||pos>GetSizeSeqList(list))
{
fprintf(stderr,"pos is error\n");
return 1;
}
int i = 0 ;
for(i =GetSizeSeqList(list); i>=pos ; i-- )
{
memcpy(&list->head[i],&list->head[i-1],sizeof(DATATYPE));
}
memcpy(&list->head[pos],data,sizeof(DATATYPE));
list->clen++;
return 0;
}
有了上面基础函数的支持后我们来写插入函数,第一个是尾插函数,为满就报错退出插入不了。有参数传入线性表指针和数据结构体,通过mmcpy函数来把数据存入线性表斌且clen++,实现了数据的插入;
第二个是按位置插入,这里就需要移动要插入数据后面的元素,还是利用mmcpy函数利用for循环把这个位置和以后的元素都向后面挪动一个,再在那个位置插入那个元素数据。
int FindSeqList(SeqList *list, char *name)
{
if(IsEmptySeqList(list))
{
fprintf(stderr,"FindSeqList error,seqlist is empty\n");
return -1;
}
int len = GetSizeSeqList(list);
int i = 0 ;
for(i=0;i<len;i++)
{
if(0==strcmp(list->head[i].name,name))
{
return i;
}
}
return -1;
}
DATATYPE *GetSeqListItem(SeqList *list, int ind)
{
if(NULL == list)
{
fprintf(stderr,"seqlist is NULL\n");
return NULL;
}
if(ind<0 || ind>GetSizeSeqList(list))
{
fprintf(stderr,"index is error . range>0 && <size\n");
return NULL;
}
return &list->head[ind];
}
这两个函数一个是按照名字查找元素位置下标,一个是按照下表查找元素,名字查找只需要strcmp和每一个遍历到的元素的name进行比较就行了。
int ModifySeqList(SeqList *list, char *old, DATATYPE *newdata)
{
if(NULL == list)
{
fprintf(stderr,"ModifySeqList error,list is null\n");
return 1;
}
int ret = FindSeqList(list,old);
if(-1 == ret)
{
fprintf(stderr,"modify error,can't find\n");
return 1;
}
DATATYPE* tmp = GetSeqListItem(list,ret);
memcpy(tmp,newdata,sizeof(DATATYPE));
return 0;
}
上面的函数为修改,通过两个查找函数找到位置减想要修改的数据填入即可,中间需要借助一个temp的临时data指针。
int DeleteSeqList(SeqList *list, char *name)
{
if(NULL == list)
{
fprintf(stderr,"ModifySeqList error,list is null\n");
return 1;
}
int ret = FindSeqList(list,name);
if(-1 == ret)
{
fprintf(stderr,"find name error,can't find\n");
return 1;
}
//GetSeqListItem(list,ret);
int i = 0;
int len = GetSizeSeqList(list);
for(i = ret;i<=len-1;++i)
{
memcpy(&list->head[i],&list->head[i+1],sizeof(DATATYPE));
}
list->clen--;
return list->clen;
}
int CleanSeqList(SeqList *list)
{
if(NULL == list)
{
fprintf(stderr,"CleanSeqList error,list is null\n");
return 1;
}
list->clen = 0 ;
return 0;
}
int DestroySeqList(SeqList *sl)
{
if(NULL == sl)
{
fprintf(stderr,"SeqList point not NULL");
return 1;
}
if(sl->head)
free(sl->head);
free(sl);
return 0;
}
上面是伤处和清空函数,清空函数很简单,把clen置为0就行了,接下来的增改查操作会覆盖原本的内容,而且clen为0位置固定不会出现错乱现象。第一个是按照for循环让后面一个元素把要处理的那个位置覆盖clen--;最后这个是删除函数,把一切都删除,释放空间。
接下来是一个示例
#include <stdio.h>
#include "seqlist.h"
int main()
{
SeqList* sl = CreateSeqList(10);
DATATYPE data[8]={
{"faker",'m',28,100},
{"gumayusi",'m',24,95},
{"zues",'m',20,90},
{"keria",'m',24,88},
{"oner",'f',23,85},
};
InsertTailSeqList(sl,&data[0]);
InsertTailSeqList(sl,&data[1]);
InsertTailSeqList(sl,&data[2]);
InsertTailSeqList(sl,&data[3]);
InsertTailSeqList(sl,&data[4]);
ShowSeqList(sl);
// char find_name[50]="faker";
// int ret = FindSeqList(sl,find_name);
// if(-1 == ret)
// {
// printf("can't find person ,%s\n",find_name);
// }
// else
// {
// DATATYPE* tmp = GetSeqListItem(sl,ret) ;
// printf("name:%s score:%d\n",tmp->name,tmp->score);
// }
DATATYPE data1 = {"kkoma",'m',32,99};
printf("----------------pos------------------\n");
InsertPosSeqList(sl,&data1,0);
ShowSeqList(sl);
printf("----------------delete------------------\n");
int num = DeleteSeqList(sl,"keria");
printf("%d\n",num);
ShowSeqList(sl);
printf("----------------clearn------------------\n");
CleanSeqList(sl);
ShowSeqList(sl);
DestroySeqList(sl);
printf("Hello World!\n");
return 0;
}
这里所有写的代码都可以执行,需要的可以复制,点赞就行。
线性表顺序存储的优点,缺点
优点
1,无需为表中的逻辑关系增加额外的存储空间
2,可以快速随机访问元素O(1)
缺点
1,插入,删除元素需要移动元素o(n)
2,无法动态存储。
本来还想写一下链式表的,没想到写太多有点累了,明天写吧。
喜欢记得点赞!