数据结构与算法——线性表的顺序存储

2.线性表

线性表,顾名思义是像线一样性质的表,是最常用且最简单的一种数据结构。线性表的存储结构有顺序存储结构和链式存储结构两种。

2.1 什么是线性表

线性表是具有相同特性的数据元素组成的一个有限序列。

线性表中元素的个数为线性表的长度,当元素个数为0时,称该线性表为空表,。

线性表中的元素可以是整数、字符等简单数据,也可以由数个数据项组成的。

每一种数据结构都有它自己的特征,线性表作为一种最简单的数据结构,有如下几个特征:

  1. 线性表中有且只有一个开始结点(头结点),这个开始结点没有前驱结点。
  2. 线性表中有且只有一个末尾结点(尾结点),这个末尾结点没有后继结点。
  3. 除去开始结点与末尾结点,其他结点都有一个前驱结点和一个后继结点。

线性表在存储结构上有顺序存储结构和链式存储结构两种方式,但不管那种存储方式,他们的结构都有如下特点:

  1. 均匀性。虽然不同数据表的数据元素可以是各种各样的,但对于同一个线性表来说,数据元素必须具有相同的数据类型和数据长度。
  2. 有序性。各数元素在线性表中的位置只取决于它们的序号,数据元素之间的相对位置是线性的,即存在唯一的“第一个”和“最后一个”数据元素。除了第一个和最后一个外,其他元素前面均只有一个数据元素(直接前驱),后面均只有一个数据元素(直接后继)。

线性表是一种比较灵活的数据结构,它的长度可根据需要增减,它也可以进行插入、删除等操作。可对线性表进行的基本操作如下:

  • 创建——Create():创建一个新的线性表。
  • 初始化——Init():初始化操作,将新创建的线性表初始化为空。
  • 获取长度——GetLength():获取线性表的长度。
  • 判断表是否为空——IsEmpty():判断线性表是否为空
  • 获取元素——Get():获取线性表某一个位置的元素。
  • 清空表——Clear():清空线性表,将线性表置为空。

当然,在设计线性表时,也可以有其他操作,例如,根据某个条件对线性表中的元素进行排序,将两个线性表合并成一个线性表,重新复制一个线性表等,上面只是描述了线性表一些最基本的操作。

2.2线性表的顺序存储

2.2.1 顺序存储的原理

所谓顺序存储,就是在存储器中分配一段连续的存储空间,逻辑上相邻的数据元素,其物理存储地址也是相邻的。

地址序号
0x001d0
0x002b1
0x003w2
0x004t3

要存储的4个字母被存储在一段连续的存储空间中。由存储空间的地址可以看出,这4个存储单元是连续的,第一个存储单元由序号0来标记,接下来的存储单元依次递增标记序号,这样在查找元素时,只要找到相应的索引就能找到元素,非常方便。线性表的这种存储方式称为顺序存储或顺序映射,又由于逻辑上相邻的两个元素在对应的顺序表中的存储位置也相邻,因此这种映射也称为直接映射。

在顺序存储中,只要确定了线性表在存储空间里的起始位置,线性表中任意元素就都可随机存取,所以线性表的顺序存储结构是一种随机存取的结构。在高级语言中,顺序存储是用数组来实现的。

在顺序存储中,系统不需要为表元素之间的逻辑关系增加额外的存储空间,而且在存取元素时,它可以根据给出的下标快速计算出元素的存储地址,从而达到随机读取的目的。例如如果要读取第3个元素,因它的下标为2(与第1个元素之间有两个间隔),由内存段的起始地址0x001和元素相差个数可以快谏计算出第3个元素的存储地址0x003,计算出地址后,就可以方便地对数据进行操作。

但是,如果在顺序表中插入或删除元素,效率会特别低。对插入来说,只限于在表的长度小于表的容量的顺序表中,如果插入大量数据,很难保证空间是否充足而且一旦分配了存储空间,如果想要扩充容量,需要重新分配空间,然后将原来的数据复制到新的空间中,非常麻烦。另一方面,即使空间充足,在插入位置之后的元素也必须都要向后移动,效率非常低。同理,如果要删除大量元素,那么势必会造成空间的浪费,而且删除元素后,后面的元素都要向前移动,效率也会非常低。

2.2.2顺序存储的实现

1.创建顺序表

在创建顺序表时,需要创建一个头结点来存放顺序表的长度、大小和地址等信息,然后再创建顺序表,同时将顺序表的地址保存在头结点中。

实现思路:

1. 定义一个struct 来保存顺序表信息
2. 为头结点分配空间
3. 为顺序表分配空间,将顺序表空间地址保存在头结点中。
4. 将头结点地址分会给调用者。

代码实现如下:

typedef struct _tag_SeqList   //头结点,记录表的信息
{

    int capacity;    //表容量
    int length;      //长度
    int *node;       //node[capacity]  ,为指针数组
    
}TSeqList;

SeqList *SeqList_Create(int capacity)	//返回值为SeqList*类型的,即顺序表的地址
{
	int ret;
    TSeqList * temp = NULL;
    temp = (TSeqList *)malloc(sizeof(TSeqList)) ;    //为头结点分配空间
    if(temp == NULL)
    {
    	ret = 1;
        printf("func SeqList_Create() error:%d\n",ret);
        return NULL;

    }
    memset(temp,0,sizeof(TSeqList));
    temp->capacity = capacity;
    temp->length = 0;
    temp->node = (int*)malloc(sizeof(void*)*capacity);    //分配一个指针数组
    
    if(temp->node == NULL)
    {
		ret = 2;
        printf("func SeqList_Create() error:%d\n",ret);
        return NULL;
   
    }
    
    return temp;    
}



2.求顺序表容量
//求顺序表容量
int SeqList_Capacity(SeqList *list)
{
    TSeqList * temp = NULL;
    if(list == NULL)
    {
        retrun;
    }
	temp = (TSeqList *)list;
    return temp->capacity;
}
3.求顺序表长度
//获取顺序表长度
int SeqList_Length(SeqList *list)
{
	TSeqList *temp;
    if(list == NULL)
    {
		return;   
    }
    temp = (TSeqList *)list;
    
    return temp->length;    
}
4.插入元素

增删改查是数据结构的核心操作,每种数据结构都要实现这几种最基本的操作。

在顺序表中,如果要插入元素,则需要将插入位置后的所有元素向后移动。在插入过程中,需要考虑一些特殊情况:

当顺序表已满时,表中的元素无法向后移动,需要作出特别处理(例如不插入,或者新开辟一块更大的空间来存储这些元素)。

当插入的位置在空闲区域时,需要作出相应处理。例如插入元素导致顺序表的元素不连续,破坏了顺序表的存储规则,这时就要适当修改插入元素的位置。

//插入元素
int SeqList_Insert(SeqList *list,SeqListNode *node,int pos)  //参数为顺序列表地址、要插入的元素地址、插入位置
{
	int i;
    TSeqList *temp = NULL;
    if(list == NULL || node == NULL)
    {
		return -1;
    }
    temp = (TSeqList *)list;
    if(temp->length >= temp->capacity)   //如果长度大于容量,则顺序表已满
    {
        return -2;
    }
    
    //容错
    if(pos > temp->length)    //如果给出的pos在长度后,即中间有空余
        pos = temp->length;   //就修正到最后一个元素后面
    
    for(i = temp->length; i > pos;i--)        //将插入位置的元素依次往后移动
    {
        temp->node[i] =temp->node[i-1];
    }
    temp->node[i] = (int)node;        //然后往腾出的位置插入新元素结点
    temp->length ++;                  //插入成功后,长度加1
    
    return 0;
    
}
5.删除元素

从顺序表中删除某一个元素,则将元素删除后,需要将后面的元素依次向前移动来补齐空位。

删除过程相对来说没有插入过程那么复杂,不必考虑内存不足的“溢出”问题但因为要移动元素,效率还是较低的。

//删除元素
SeqList * SeqList_Delete(SeqList * list,int pos)
{
    int i;
    
    //先作健壮性判断
    TSeqList * tlist = NULL;
    SeqListNode * temp = NULL;
    tlist = (TSeqList *)list;
    if(list ==NULL || pos < 0 || pos >= tlist->capacity)
    {
        printf("SeqList_Delete () error\n");
        return NULL;   
    }
   
    temp = (SeqListNode *)tlist->node[pos];   //要删除的元素
    
    for(i = pos+1; i < tlist->length;i--)     //将删除元素位置后的所有元素向前移动
    {
        tlist->node[i-1] = tlist->node[i];
    }
    tlist->length--;                          //删除元素后,长度要减1
    return temp;

}
6.查找某个位置上的元素

在顺序表中查找某个元素是非常方便的,因为顺序表在底层是以数组来实现的,每个存储单元都有索引标注,要查找某个位置的上的元素,直接按索引来查找即可。

//查找元素
SeqList *SeqList_Get(SeqList *list,int pos)
{
    //先作健壮性判断
    TSeqList *tlist = NULL;
    SeqListNode *temp = NULL;
    tlist = (TSeqList *)list;
    
    if(tlist == NULL || pos<0 || pos >= tlist->capacity)
    {
        printf("SeqList_Get() error\n");
        return NULL;
    }
    
	temp = (SeqListNode *)tlist->node[pos];      //将表中的pos位置的结点指针赋给temp;
    return temp;
}
7.清空表

清空顺序表是将表中的内容分全部置0。

//清空表
void SeqList_Clear(SeqList *list)
{
    TSeqList *temp;
    if(list == NULL)
    {
        return;
    }
    temp = (TSeqList *)list;
    temp->length = 0;
    memset(temp->node,0,(temp->capacity * sizeof(void *)));     //将顺序表全部归0
    return;
    
}
8.销毁表
//销毁表
void SeqList_Destory(SeqList *list)
{
    TSeqList *temp = NULL;
    if(list == NULL)
    {
        return;
    }
    
    temp = (TSeqList * )list;
    
    if(temp->node != NULL)
    {
        free(temp->node);       //先释放头结点中的指针数组
    }
    free(temp);                 //再释放头结点
    return;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
第一个模块——主函数main()的功能是:根据选单的选项调用各函数,并完成相应的功能。 
   第二个模块——Menu()的功能是:显示提示选单。 
   第三个模块——Quit()的功能是:退出选单。 
   第四个模块——Create()的功能是:创建新的数据记录。 
   第五个模块——Add()的功能是:增加新的数据记录,并返回选单。 
   第六个模块——Find()的功能是:按要求查询相关的信息,如果找到了,则显示该信息,如果未找到,则提示文件中没有该信息,并返回选单。 
   第七个模块——Alter()[的功能是:修改某条记录的信息,如果未找到要修改的记录,则提示系统中无此记录,并返回选单。 
   第八个模块——Delete()的功能是:删除某条记录,如果未找到要删除的记录,则提示通讯录中没有,并返回选单。 
   第九个模块——List()的功能是:显示所有记录。 一、用链表或者顺序表实现以下系统,完成线性表的建立(至少包括10个结点),以及线性表中信息(结点)的插入、查找、删除、修改、输出等操作,具体的模块要求见上方的“总的模块要求”。建议用“文件”存储数据。 1.通讯录管理系统的设计与实现 (1)通讯者信息包括:编号(char num[10])、姓名(char name[10])、性别(char sex[10])、电话(char phone[20]) (2)除了总的模块要求外,还需统计通讯录中男性人数及女性人数,并求出通讯录中的第一个模块——主函数main()的功能是:根据选单的选项调用各函数,并完成相应的功能。 
   第二个模块——Menu()的功能是:显示提示选单。 
   第三个模块——Quit()的功能是:退出选单。 
   第四个模块——Create()的功能是:创建新的数据记录。 
   第五个模块——Add()的功能是:增加新的数据记录,并返回选单。 
   第六个模块——Find()的功能是:按要求查询相关的信息,如果找到了,则显示该信息,如果未找到,则提示文件中没有该信息,并返回选单。 
   第七个模块——Alter()[的功能是:修改某条记录的信息,如果未找到要修改的记录,则提示系统中无此记录,并返回选单。 
   第八个模块——Delete()的功能是:删除某条记录,如果未找到要删除的记录,则提示通讯录中没有,并返回选单。 
   第九个模块——List()的功能是:显示所有记录。 一、用链表或者顺序表实现以下系统,完成线性表的建立(至少包括10个结点),以及线性表中信息(结点)的插入、查找、删除、修改、输出等操作,具体的模块要求见上方的“总的模块要求”。建议用“文件”存储数据。 1.通讯录管理系统的设计与实现 (1)通讯者信息包括:编号(char num[10])、姓名(char name[10])、性别(char sex[10])、电话(char phone[20]) (2)除了总的模块要求外,还需统计通讯录中男性人数及女性人数,并求出通讯录中的男女比例。 男女比例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

%Zero%

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值