前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >顺序表揭秘:掌握数据存储的基础艺术

顺序表揭秘:掌握数据存储的基础艺术

作者头像
平凡之路.
发布于 2025-06-02 04:21:46
发布于 2025-06-02 04:21:46
9100
代码可运行
举报
文章被收录于专栏:学习学习
运行总次数:0
代码可运行

一、引言

在计算机科学中,数据结构是存储和组织数据以使插入、删除和访问更高效的重要方式。顺序表(Array List) 是一种基本且常用的数据结构,其利用内存的连续性来存储元素,为我们提供了简洁高效的数据操作手段。在学习数据结构时,顺序表是非常适合初学者的一个起点,因为它简明的实现可以帮助我们更好地理解数组的底层机制和数据的操作过程。

本文将详细介绍顺序表的基本概念、实现方法、应用场景,并展示如何用 C 语言编写动态顺序表代码。你将了解顺序表的不同类型以及如何高效地执行插入、删除等操作。如果你想更加深入地理解顺序表,并掌握它的实现细节,这篇文章会是你的好帮手。

二、顺序表的基本概念与结构

1.概念

顺序表(也称为线性表)是一种线性数据结构,其中元素按照顺序在内存中连续存储。 顺序表的底层结构是数组,它对数组进行了封装,提供了常用的增、删、改、查接口。这种结构的优点在于能够高效地实现随机访问,但也存在插入和删除操作效率较低的缺点,尤其是在数组中间进行操作时。 它的主要特点包括: 连续存储:所有元素在内存中占据一块连续的空间。 索引访问:可以通过索引快速访问任意元素。 固定大小:在静态实现中,顺序表的大小在创建时确定,无法动态调整。

2.基本结构

在C语言中,顺序表通常用一个数组来实现。以下是一个顺序表的基本结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//静态顺序表
typedef int DataType;重定义类型名字
#define MAX_SIZE 100
typedef struct {
    DataType data[MAX_SIZE];//定长数组
    int size; // 有效数据个数
} SL;

三、顺序表的分类

顺序表可以根据存储方式和动态变化的特性进行分类,包括静态顺序表和动态顺序表。静态顺序表在编译时分配固定的存储空间,而动态顺序表则允许在运行时根据需要调整大小,从而提供更大的灵活性。

1.静态顺序表 定义:使用静态数组实现的顺序表,其存储空间在编译时分配,大小固定不变。 特点: 空间分配在栈区或全局数据区。 容量固定,不易扩展。

2.动态顺序表 定义:使用动态数组实现的顺序表,其存储空间在运行时动态分配,可以根据需要进行扩展或缩减。 特点: 空间分配在堆区。 容量可变,通过 malloc 、 realloc 和 free 等操作进行管理。

四、动态顺序表的实现

1.结构定义

动态顺序表的结构定义如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef struct SeqList
{
	DataType* arr;
	int size;//有效数据个数
	int capacity;//容量
}SL;

在这个定义中,arr是一个指向动态数组的指针,size记录当前已存储的数据数量,而capacity则表示数组的总容量。通过这种方式,动态顺序表能够根据实际存储情况灵活调整内存使用。

2.相关功能实现

1.初始化

初始化函数用于设置动态顺序表的初始状态:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 初始化顺序表
void SLInit(SL* p)
{
    // 初始化顺序表,使其容量和大小均为0,数据指针为NULL
    p->arr = NULL;
    p->size = p->capacity = 0;
}

该函数将顺序表的arr指针初始化为NULL,并将sizecapacity设置为0,以便在后续操作中动态分配内存。

2.销毁

销毁函数用于释放动态顺序表占用的内存:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 销毁顺序表
void SLDestroy(SL* p)
{
    // 如果数组存在,释放内存
    if (p->arr)
    {
        free(p->arr);
    }
    // 将指针和容量大小重置为0,防止野指针
    p->arr = NULL;
    p->size = p->capacity = 0;
}

在销毁过程中,首先检查arr是否指向有效内存,如果是,则调用free释放内存,最后将所有相关参数重置。

3.扩容

扩容功能是动态顺序表的核心,确保在需要时能够增加数组的容量:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 检查并扩充容量
void checkcapacity(SL* p)
{
    // 如果当前容量等于大小,说明需要扩充
    if (p->size == p->capacity)
    {
        // 新容量为原来的两倍,如果当前容量为0,则初始为4
        int newcapacity = p->capacity == 0 ? 4 : 2 * p->capacity;
        // 重新分配内存空间
        DataType* tmp = (DataType*)realloc(p->arr, newcapacity * sizeof(DataType));
        if (tmp == NULL)
        {
            // 重新分配失败,打印错误信息并退出程序
            perror("realloc fail");
            exit(1);
        }
        // 空间申请成功,更新数组指针和容量
        p->arr = tmp;
        p->capacity = newcapacity;
    }
}

在扩容时,首先判断当前size是否等于capacity,若相等则需要扩容。新容量设定为当前容量的两倍,初始时为4。使用realloc函数动态调整内存并更新指针。

4.打印

打印功能用于输出动态顺序表中的所有数据:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 打印顺序表
void SLPrint(SL s)
{
    // 遍历顺序表并打印每个元素
    for (int i = 0; i < s.size; i++)
    {
        printf("%d ", s.arr[i]);
    }
    printf("\n");  // 换行,方便观察输出
}

5.头插

头插:在表头插入新元素。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 顺序表头插入元素
void SLPushHead(SL* p, DataType x)
{
    assert(p);  // 确保顺序表不为空
    checkcapacity(p);  // 检查容量是否足够,不足则扩展
    // 从后向前移动元素,空出头部位置
    for (int i = p->size; i >= 1; i--)
    {
        p->arr[i] = p->arr[i - 1];
    }
    // 插入新元素到头部
    p->arr[0] = x;
    p->size++;
}

6.尾插

尾插:在表尾添加新元素。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 顺序表尾插入元素
void SLPushBack(SL* p, DataType x)
{
    assert(p);  // 确保顺序表不为空
    checkcapacity(p);  // 检查容量是否足够,不足则扩展
    // 插入新元素到尾部
    p->arr[p->size++] = x;
}

7.头删

头删:删除表头元素

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 顺序表头删除元素
void SLDelHead(SL* p)
{
    assert(p);  // 确保顺序表不为空
    assert(p->size > 0);  // 确保顺序表中有元素可以删除
    // 从前向后移动元素,覆盖掉头部元素
    for (int i = 1; i <= p->size - 1; i++)
    {
        p->arr[i - 1] = p->arr[i];
    }
    p->size--;  // 减少顺序表的大小
}

8.尾删

尾删:删除表尾元素。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 顺序表尾删除元素
void SLDelBack(SL* p)
{
    assert(p);  // 确保顺序表不为空
    assert(p->size > 0);  // 确保顺序表中有元素可以删除
    p->size--;  // 直接减少顺序表的大小
}

9.指定插入

指定位置插入:在指定位置进行插入操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 在指定位置前插入数据
void SLInsert(SL* p, int pos, DataType x)
{
    assert(p);  // 确保顺序表不为空
    assert(pos >= 0 && pos <= p->size);  // 确保插入位置合法
    checkcapacity(p);  // 检查容量是否足够,不足则扩展
    // 从后向前移动元素,空出指定位置
    for (int i = p->size - 1; i >= pos; i--)
    {
        p->arr[i + 1] = p->arr[i];
    }
    // 插入新元素到指定位置
    p->arr[pos] = x;
    p->size++;
}

10.指定删除

指定位置删除:在指定位置进行删除操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 删除指定位置的数据
void SLErase(SL* p, int pos)
{
    assert(p);  // 确保顺序表不为空
    assert(pos >= 0 && pos < p->size);  // 确保删除位置合法
    // 从前向后移动元素,覆盖掉指定位置的数据
    for (int i = pos; i <= p->size - 2; i++)
    {
        p->arr[i] = p->arr[i + 1];
    }
    p->size--;  // 减少顺序表的大小
}

11.查找

查找操作用于在顺序表中寻找特定元素:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 顺序表的查找
int SLFind(SL* p, DataType x)
{
    assert(p);  // 确保顺序表不为空
    // 遍历顺序表查找指定元素
    for (int i = 0; i < p->size; i++)
    {
        if (p->arr[i] == x)
        {
            return i;  // 找到了,返回元素的位置
        }
    }
    return -1;  // 没有找到,返回-1
}

该函数遍历顺序表的所有有效元素,若找到匹配项则返回其索引,未找到则返回-1。

五、完整代码

1.SeqList.h

该部分放顺序表结构定义、函数的声明

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int DataType;
//动态顺序表
typedef struct SeqList
{
	DataType* arr;
	int size;//有效数据个数
	int capacity;//容量
}SL;

//初始化顺序表
void SLInit(SL* p);
//销毁顺序表
void SLDestroy(SL* p);
//打印顺序表
void SLPrint(SL s);
//顺序表头插
void SLPushHead(SL* p, DataType x);
//顺序表尾插
void SLPushBack(SL* p, DataType x);
//顺序表头删
void SLDelHead(SL* p);
//顺序表尾删
void SLDelBack(SL* p);
//在指定位置前插入数据
void SLInsert(SL* p, int pos, int x);
//删除指定位置的数据
void SLErase(SL* p, int pos);
//顺序表的查找
int  SLFind(SL* p, DataType x);

2.SeqList.c

该部分是函数功能的实现,也就是上述第四点的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"

// 初始化顺序表
void SLInit(SL* p)
{
    // 初始化顺序表,使其容量和大小均为0,数据指针为NULL
    p->arr = NULL;
    p->size = p->capacity = 0;
}

// 销毁顺序表
void SLDestroy(SL* p)
{
    // 如果数组存在,释放内存
    if (p->arr)
    {
        free(p->arr);
    }
    // 将指针和容量大小重置为0,防止野指针
    p->arr = NULL;
    p->size = p->capacity = 0;
}

// 检查并扩充容量
void checkcapacity(SL* p)
{
    // 如果当前容量等于大小,说明需要扩充
    if (p->size == p->capacity)
    {
        // 新容量为原来的两倍,如果当前容量为0,则初始为4
        int newcapacity = p->capacity == 0 ? 4 : 2 * p->capacity;
        // 重新分配内存空间
        DataType* tmp = (DataType*)realloc(p->arr, newcapacity * sizeof(DataType));
        if (tmp == NULL)
        {
            // 重新分配失败,打印错误信息并退出程序
            perror("realloc fail");
            exit(1);
        }
        // 空间申请成功,更新数组指针和容量
        p->arr = tmp;
        p->capacity = newcapacity;
    }
}

// 打印顺序表
void SLPrint(SL s)
{
    // 遍历顺序表并打印每个元素
    for (int i = 0; i < s.size; i++)
    {
        printf("%d ", s.arr[i]);
    }
    printf("\n");  // 换行,方便观察输出
}

// 顺序表头插入元素
void SLPushHead(SL* p, DataType x)
{
    assert(p);  // 确保顺序表不为空
    checkcapacity(p);  // 检查容量是否足够,不足则扩展
    // 从后向前移动元素,空出头部位置
    for (int i = p->size; i >= 1; i--)
    {
        p->arr[i] = p->arr[i - 1];
    }
    // 插入新元素到头部
    p->arr[0] = x;
    p->size++;
}

// 顺序表尾插入元素
void SLPushBack(SL* p, DataType x)
{
    assert(p);  // 确保顺序表不为空
    checkcapacity(p);  // 检查容量是否足够,不足则扩展
    // 插入新元素到尾部
    p->arr[p->size++] = x;
}

// 顺序表头删除元素
void SLDelHead(SL* p)
{
    assert(p);  // 确保顺序表不为空
    assert(p->size > 0);  // 确保顺序表中有元素可以删除
    // 从前向后移动元素,覆盖掉头部元素
    for (int i = 1; i <= p->size - 1; i++)
    {
        p->arr[i - 1] = p->arr[i];
    }
    p->size--;  // 减少顺序表的大小
}

// 顺序表尾删除元素
void SLDelBack(SL* p)
{
    assert(p);  // 确保顺序表不为空
    assert(p->size > 0);  // 确保顺序表中有元素可以删除
    p->size--;  // 直接减少顺序表的大小
}

// 在指定位置前插入数据
void SLInsert(SL* p, int pos, DataType x)
{
    assert(p);  // 确保顺序表不为空
    assert(pos >= 0 && pos <= p->size);  // 确保插入位置合法
    checkcapacity(p);  // 检查容量是否足够,不足则扩展
    // 从后向前移动元素,空出指定位置
    for (int i = p->size - 1; i >= pos; i--)
    {
        p->arr[i + 1] = p->arr[i];
    }
    // 插入新元素到指定位置
    p->arr[pos] = x;
    p->size++;
}

// 删除指定位置的数据
void SLErase(SL* p, int pos)
{
    assert(p);  // 确保顺序表不为空
    assert(pos >= 0 && pos < p->size);  // 确保删除位置合法
    // 从前向后移动元素,覆盖掉指定位置的数据
    for (int i = pos; i <= p->size - 2; i++)
    {
        p->arr[i] = p->arr[i + 1];
    }
    p->size--;  // 减少顺序表的大小
}

// 顺序表的查找
int SLFind(SL* p, DataType x)
{
    assert(p);  // 确保顺序表不为空
    // 遍历顺序表查找指定元素
    for (int i = 0; i < p->size; i++)
    {
        if (p->arr[i] == x)
        {
            return i;  // 找到了,返回元素的位置
        }
    }
    return -1;  // 没有找到,返回-1
}

3.test.c

该部分用来测试我们写的函数(函数的调用),可以随便改

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"
void SLtest01()//测试
{
	SL sl;
	SLInit(&sl);
	//增删查改操作
	SLPushHead(&sl,1);//头插1      1
	SLPushHead(&sl,3);//头插3      31
	SLPushBack(&sl, 5);//尾插5     315
    SLInsert(&sl,3,7);//在下标为3的位置插入7    3157
	SLErase(&sl,2);//删除下标为2的数据     317
	SLPrint(sl);
	int find = SLFind(&sl, 3);
	if (find>=0)
	{
		printf("找到了,下标为%d\n", find);
	}
	else
	{
		printf("没有找到");
	}
	SLDestroy(&sl);
}
int main()
{
	SLtest01();
	return 0;
}

六、总结

顺序表是一种简单而强大的数据结构,通过使用连续内存存储实现高效的随机访问。根据不同的需求,开发者可以选择静态顺序表或动态顺序表以适应各种应用场景。动态顺序表的灵活性和效率使其在实际应用中更具优势。希望本文能帮助您更好地理解顺序表及其实现方式,从而在未来的学习和项目中得心应手。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
美团闪电仓能否破解即时零售的四大困境?
那么,通过什么关键数据指标来明确用户的需求并制定相应的战略和执行方案呢?不同的商业模式存在着差别。
庄帅
2022/07/09
3510
美团闪电仓能否破解即时零售的四大困境?
“新消费”风口下的休闲食品行业,是这样布局的
网红经济是以年轻貌美的时尚达人为形象代表,以红人的品味和眼光为主导,进行选款和视觉推广,在社交媒体上聚集人气,依托庞大的粉丝群体进行定向营销,从而将粉丝转化为购买力的一个过程。
庄帅
2020/06/17
5610
“新消费”风口下的休闲食品行业,是这样布局的
商品分析是什么?该怎么做(入门版)
商品分析曾经是数据分析的最早形态。现代数据分析以及数据模型的大部分思路,都是从这里演化出来的。可能是因为它太过传统,可能是因为互联网公司不需要挣钱养自己,总之,现在介绍商品分析的文章非常少。今天我们就先开个头,简单介绍一下商品分析的基本概念。
接地气的陈老师
2020/06/19
7940
商品分析是什么?该怎么做(入门版)
复工后的消费反弹潮
“疫情过后,我们一起看樱花”、“疫情过后我一定要使劲吃,到处逛”,网上到处都充满了对疫情结束后的种种向往,那么疫情过后究竟会不会掀起消费狂潮?富国大通认为,狂潮不好说,但一定会有一波明显反弹。
庄帅
2020/03/09
5490
复工后的消费反弹潮
响铃:苏宁易购实现逆势增长,但它的非电业务更超出意料
2月26日,苏宁易购在南京举行了“全民焕新节媒体发布会”,在发布会中多次提及苏宁正在打造全场景、全品类的战略思想。
曾响铃
2019/03/18
4090
人货匹配模型没搞懂?互联网行业都在讨论它
多数据分析书本、文章都提过人货场模型,但对于其中最核心的人货如何匹配,没有详细介绍。人货匹配是非常底层的分析理论,涉及到转化率分析、用户分群、推荐算法训练等重要议题,无论互联网的电商、O2O、短视频、直播等产品都会考虑这点。废话不多说,今天详细介绍一下。
接地气的陈老师
2021/07/23
7400
同城零售模型与规模化增长困境
在角色上,同城零售主要还是以同城的零售商和品牌商的实物销售为主;O2O则以餐饮和生活服务的实体店为主;新零售则以零售商的数字化为主。
庄帅
2020/10/13
5320
同城零售模型与规模化增长困境
“宅经济”激活新消费,生鲜电商崛起逻辑
进入2020年,“宅”是第一个主题词。为抗击新冠疫情,全国各地自 1 月 20日以来相继实施较为严格的居家隔离措施,这一过程中生鲜电商的需求随即井喷。
庄帅
2020/04/10
4790
“宅经济”激活新消费,生鲜电商崛起逻辑
洞察|你不在乎的三四线城市,数据却看到了万亿商机
「小镇青年」听上去有些调侃意味。 星巴克、沃尔玛和 711 便利店尚未成为日常关键词,生活 在 比上不足、比下有余的地界。 关于低线城市消费升级的 4 个问题 在外闯荡多年,逢年过节返乡时,你一定听过这样的段子: 北上广深 CBD 里的 Michael 和 Mary,回家就成了亲友口中的狗蛋和翠花,成为标准的小镇青年。 本篇低线城市消费升级报告或许将让你感到意外:三线及以下城市的年轻人,很可能比大都市中的白领阶层拥有更多的可自由支配财产和更高的消费力。 他们不必面对房贷压力,日常开销低,工作压力小,拥有较
灯塔大数据
2018/04/04
2K0
洞察|你不在乎的三四线城市,数据却看到了万亿商机
消费券背后的乘数效应,基于日本消费“世代变迁”的启示
受新冠肺炎疫情影响,提振消费、促活经济是当下各地政府和企业的共同愿望,各界协力施策。
庄帅
2020/04/16
4040
消费券背后的乘数效应,基于日本消费“世代变迁”的启示
互联网金融再掀争夺战:巨头抢筹消费金融
 互联网金融这个时下热门的产业,除了第三方支付、理财、小贷等多个维度外,亦包括生态链条的上下游延伸,而消费金融则成为该产业发展路上的“高地”。   而未来消费金融的发展方向会是什么?目前,互联网巨头们利用所掌握的海量大数据优势,挖掘需求、创新设计新产品则成为大势所趋。   今年,京东商城推出了一项名为“京东白条”的会员增值服务,为符合条件的京东优质会员提供在京东商城“先消费,后付款”的赊购服务。近日,京东消费金融业务高级总监许凌如此指出:“未来消费金融将在扩大用户覆盖面、拓展消费场景上部署,并重点
腾讯研究院
2018/03/13
9130
消费升级里的中国:电商消费大数据勾勒在线商业版图
<数据猿导读> 以互联网经济为代表的新经济,凭借业态先进、较少的流通环节,大大降低了流通成本,由此带动了消费升级,电商成为主流,这股线上大消费热潮的背后,还伴随着全民消费习惯的转变。电商大数据报告带你
数据猿
2018/04/19
7710
消费升级里的中国:电商消费大数据勾勒在线商业版图
从李佳琦、一条到诚品书店,内容带货背后的真相是什么?
走到今天,大的流量红利时代已经过去,内容作为流量的一种新的收纳器,对于品牌和零售的价值正不断提升。
浪潮新消费
2020/12/23
4160
直播电商“人、货、场”的解读和趋势预测
直播电商的产业链环节包括平台、用户、主播、MCN 机构、供应链、品牌方、内容电商整合营销机构和服务支持共 9 个环节。
庄帅
2020/05/09
1.3K0
崛起or阵亡?数据新玩法教你打好新零售之仗
大数据如何赋能新零售?DT君上周请到了《新零售:吹响第四次零售革命的号角》一书的作者范鹏老师,从新零售的诞生、商业模式的分析、到真实案例的探讨,让你看懂新零售的本质。本文为嘉宾的直播实录整理,感兴趣的朋友不要错过哦~
DT数据侠
2018/09/21
6040
崛起or阵亡?数据新玩法教你打好新零售之仗
指标体系构建-03-交易型的数据指标体系
人货场模型搭建 有了三个维度的基础理解,就能用来综合解释问题。回到开头的“生鲜电商复购率低”的问题。可以先从人货场角度建立分析假设:
IT从业者张某某
2023/12/25
4680
指标体系构建-03-交易型的数据指标体系
B2B快消品传统通路亟待数字化赋能激活,打通高效营销链路
快消品顾名思义就是快速消费品,主要包括食品、个人卫生用品、烟酒、饮料等使用寿命较短的产品,因此快消品的使用迭代周期会更快,高频次和易重复的使用率通过拉动消耗,维持市场规模化的产需扩张。
盈鱼MA
2021/03/11
6590
B2B快消品传统通路亟待数字化赋能激活,打通高效营销链路
研究了每日优鲜和叮咚买菜后,我总结出生鲜电商的两个盈利模型和盈利公式
国内生鲜电商市场规模增长迅速。根据艾瑞咨询数据,截至2018年底生鲜电商市场规模已经达到2045亿,2013~2018年复合增长率高达74%。
庄帅
2020/03/31
1.1K1
研究了每日优鲜和叮咚买菜后,我总结出生鲜电商的两个盈利模型和盈利公式
AARRR模型的使用注意事项【防坑提醒】
在面试的时候,被问到:你如何搭建分析思路,很多同学脱口而出:我用AARRR模型。这么回答本身没什么问题,可后续的解释却经常漏洞百出,甚至犯一些原则性的错误,今天系统性解答一下,到底AARRR适合干什么,不适合干什么。
接地气的陈老师
2019/12/09
6860
【干货】新消费品冷启动的三板斧
大家好,我是白蓓,感谢泛零售小圆桌的信任和邀请,今天,我给大家分享近期关于“新品牌如何完成冷启动”的一些观察和实践。
iCDO互联网数据官
2020/02/26
1.2K0
【干货】新消费品冷启动的三板斧
推荐阅读
相关推荐
美团闪电仓能否破解即时零售的四大困境?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档