数据结构与算法学习笔记十三---数组的顺序表示和实现(C语言)

news2025/1/22 20:59:19

目录

前言

一、什么是数组

二、数组的顺序存储

1.定义

2.初始化

3.销毁数组

4.获取指定下标的数据元素

5.给数组中的数据元素赋值

6.完整代码


前言

        这篇文章主要介绍数组的顺序存储。

一、什么是数组

        数组是由类型相同的数据元素构成的有序集合,每个元素成为数组元素。数组元素在线性表中的序号称为改数据元素的下标。数组可以看成是线性表的推广,其特点是结构中的元素本身可以是某种结构的数据,但是都属于同一种数据类型。

        图1.数组示意图    

        数组的基本操作有:初始化、销毁、赋值、取值操作。    

二、数组的顺序存储

        多维数组有两种存储方式:

        1.以列为主序的存储方式

        2.以行为主序的存储方式

        两种存储方式示意图分别如下图所示:

图2.数组的两种存储方式

        多维数组的存储位置遵循以下规则:

图3.多维数组的存储关系

        数组的常用操作表示如下:

1.定义

typedef int ElemType;
typedef int Status;

#define MAX_ARRAY_DIM  8 // 假设数组维数的最大值为8

typedef struct {
    ElemType* base;     // 数组元素基址,由InitArray分配
    int dim;            // 数组维数
    int* bounds;        // 数组维界基址,由InitArray分配
    int* constants;     // 数组映像函数常量基址,由InitArray分配
} Array;

2.初始化

// 若维数dim和随后的各维度长度合法,则构造数组并返回构造成功的数组
Status InitArray(Array* arr, int dim, ...) {
    if (dim < 1 || dim > MAX_ARRAY_DIM) return 0; // 维数不合法

    // 分配内存并初始化维度信息
    arr->dim = dim;
    arr->bounds = (int*)malloc(dim * sizeof(int));
    if (!arr->bounds) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    arr->constants = (int*)malloc(dim * sizeof(int));
    if (!arr->constants) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    // 使用可变参数设置各维度长度,并计算总元素个数
    int* ptr = &dim; // 使用可变参数需要定义指针
    ptr++;           // 指向维数之后的第一个参数
    int totalElements = 1;
    for (int i = 0; i < dim; i++) {
        arr->bounds[i] = *ptr++; // 设置各维度长度
        totalElements *= arr->bounds[i]; // 计算总元素个数
    }

    // 分配内存并初始化数组元素
    arr->base = (ElemType*)malloc(totalElements * sizeof(ElemType));
    if (!arr->base) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    // 计算映像函数常量
    arr->constants[dim - 1] = 1; // 最后一个维度的映像函数常量为1
    for (int i = dim - 2; i >= 0; i--) {
        arr->constants[i] = arr->bounds[i + 1] * arr->constants[i + 1]; // 计算其他维度的映像函数常量
    }

    return 1;
}

3.销毁数组

// 销毁数组
void DestroyArray(Array* arr) {
    free(arr->base);
    free(arr->bounds);
    free(arr->constants);
}

4.获取指定下标的数据元素

// 获取数组中指定索引位置的元素值
ElemType value(const Array* arr, int indices[]) {
    int offset = 0; // 计算元素在一维数组中的偏移量

    // 根据索引计算偏移量
    for (int i = 0; i < arr->dim; i++) {
        if (indices[i] < 0 || indices[i] >= arr->bounds[i]) {
            fprintf(stderr, "Index out of bounds\n");
            exit(EXIT_FAILURE);
        }
        offset += arr->constants[i] * indices[i]; // 计算偏移量
    }

    return arr->base[offset]; // 返回对应位置的元素值
}

5.给数组中的数据元素赋值

// 将数组中指定索引位置的元素赋值为给定值
void assign(Array* arr, int indices[], ElemType value) {
    int offset = 0; // 计算元素在一维数组中的偏移量

    // 根据索引计算偏移量
    for (int i = 0; i < arr->dim; i++) {
        if (indices[i] < 0 || indices[i] >= arr->bounds[i]) {
            fprintf(stderr, "Index out of bounds\n");
            exit(EXIT_FAILURE);
        }
        offset += arr->constants[i] * indices[i]; // 计算偏移量
    }

    arr->base[offset] = value; // 将指定位置的元素赋值为给定值
}

6.完整代码

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;
typedef int Status;

#define MAX_ARRAY_DIM  8 // 假设数组维数的最大值为8

typedef struct {
    ElemType* base;     // 数组元素基址,由InitArray分配
    int dim;            // 数组维数
    int* bounds;        // 数组维界基址,由InitArray分配
    int* constants;     // 数组映像函数常量基址,由InitArray分配
} Array;

// 若维数dim和随后的各维度长度合法,则构造数组并返回构造成功的数组
Status InitArray(Array* arr, int dim, ...) {
    if (dim < 1 || dim > MAX_ARRAY_DIM) return 0; // 维数不合法

    // 分配内存并初始化维度信息
    arr->dim = dim;
    arr->bounds = (int*)malloc(dim * sizeof(int));
    if (!arr->bounds) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    arr->constants = (int*)malloc(dim * sizeof(int));
    if (!arr->constants) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    // 使用可变参数设置各维度长度,并计算总元素个数
    int* ptr = &dim; // 使用可变参数需要定义指针
    ptr++;           // 指向维数之后的第一个参数
    int totalElements = 1;
    for (int i = 0; i < dim; i++) {
        arr->bounds[i] = *ptr++; // 设置各维度长度
        totalElements *= arr->bounds[i]; // 计算总元素个数
    }

    // 分配内存并初始化数组元素
    arr->base = (ElemType*)malloc(totalElements * sizeof(ElemType));
    if (!arr->base) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    // 计算映像函数常量
    arr->constants[dim - 1] = 1; // 最后一个维度的映像函数常量为1
    for (int i = dim - 2; i >= 0; i--) {
        arr->constants[i] = arr->bounds[i + 1] * arr->constants[i + 1]; // 计算其他维度的映像函数常量
    }

    return 1;
}

// 销毁数组
void DestroyArray(Array* arr) {
    free(arr->base);
    free(arr->bounds);
    free(arr->constants);
}
// 获取数组中指定索引位置的元素值
ElemType value(const Array* arr, int indices[]) {
    int offset = 0; // 计算元素在一维数组中的偏移量

    // 根据索引计算偏移量
    for (int i = 0; i < arr->dim; i++) {
        if (indices[i] < 0 || indices[i] >= arr->bounds[i]) {
            fprintf(stderr, "Index out of bounds\n");
            exit(EXIT_FAILURE);
        }
        offset += arr->constants[i] * indices[i]; // 计算偏移量
    }

    return arr->base[offset]; // 返回对应位置的元素值
}

// 将数组中指定索引位置的元素赋值为给定值
void assign(Array* arr, int indices[], ElemType value) {
    int offset = 0; // 计算元素在一维数组中的偏移量

    // 根据索引计算偏移量
    for (int i = 0; i < arr->dim; i++) {
        if (indices[i] < 0 || indices[i] >= arr->bounds[i]) {
            fprintf(stderr, "Index out of bounds\n");
            exit(EXIT_FAILURE);
        }
        offset += arr->constants[i] * indices[i]; // 计算偏移量
    }

    arr->base[offset] = value; // 将指定位置的元素赋值为给定值
}

int main(int argc, const char *argv[]) {
    // 初始化数组
    Array arr;
    if (InitArray(&arr, 2, 3, 4)) { // 三行四列数组
        printf("Array initialized successfully!\n");

        // 给数组赋值并打印
        printf("Assigning values to array elements and printing...\n");
        for (int i = 0; i < 3; i++) { // 遍历行
            for (int j = 0; j < 4; j++) { // 遍历列
                int indices[2] = {i, j}; // 当前元素的索引
                int value = i * 10 + j; // 计算要赋的值
                assign(&arr, indices, value); // 赋值
                printf("arr[%d][%d] = %d\n", i, j, value); // 打印赋值信息
            }
        }

        // 打印数组元素
        printf("\nArray elements after assignment:\n");
        for (int i = 0; i < 3; i++) { // 遍历行
            for (int j = 0; j < 4; j++) { // 遍历列
                int indices[2] = {i, j}; // 当前元素的索引
                printf("%d ", value(&arr, indices)); // 打印当前元素的值
            }
            printf("\n"); // 换行
        }

        // 销毁数组
        DestroyArray(&arr);
        printf("\nArray destroyed!\n");
    } else {
        printf("Array initialization failed!\n");
    }

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1681612.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【CTF Web】NSSCTF 3861 [LitCTF 2023]我Flag呢?Writeup(信息收集+源码泄漏+代码审计)

[LitCTF 2023]我Flag呢&#xff1f; 奇怪&#xff0c;放哪里了&#xff0c;怎么看不见呢&#xff1f;&#xff08;初级难度&#xff09; 解法 按下 F12&#xff0c;打开开发者工具。找到 flag。 <!DOCTYPE html> <html><head><meta charset"utf-8&q…

AI应用案例:吸烟打电话行为识别推理

使用百度PaddlePaddle&#xff08;现更名为PaddlePaddle-GPU或PaddlePaddle-CPU&#xff09;框架来构建精准的人员抽烟、打电话动作识别模型&#xff0c;并将其应用于加油站监控场景&#xff0c;你可以遵循以下步骤&#xff1a; 数据准备&#xff1a; 收集抽烟和打电话行为的图…

Originx的创新解法之:应用程序故障篇

Originx并不期望做一个完整覆盖全栈的监控体系&#xff0c;而是利用北极星指标体系标准化找出故障方向&#xff0c;然后联动各种成熟的监控数据形成证据链条&#xff0c;并将各种数据融合在一个故障报告之中。更多信息请参考 Log | Metrics | Trace的联动方式探讨http://mp.wei…

【半监督学习】半监督学习中的时间集合

在本文中&#xff0c;我们提出了一种在半监督环境下训练深度神经网络的简单而高效的方法&#xff0c;在这种环境下&#xff0c;只有一小部分训练数据是有标签的。我们引入了self-ensembling技术&#xff0c;即利用网络在不同历时&#xff0c;最重要的是在不同正则化和输入增强条…

Nginx part3 创建一个https的网站

目录 HTTPS 公钥和密钥 加密解密方式&#xff1a; https搭建步骤 强调一下 1、准备环境 2、配置文件 3、制作证书 4、进行设置 HTTPS 啥是https&#xff0c;根据百度&#xff1a;HTTPS &#xff08;全称&#xff1a;Hypertext Transfer Protocol Secure&#xff09;&a…

AI大语言模型在公共服务中的应用实例

随着计算机技术的飞速发展&#xff0c;人工智能已经成为了当今科技领域的热门话题。从早期的图灵测试到现在的深度学习和神经网络&#xff0c;人工智能已经取得了令人瞩目的成就。特别是近年来&#xff0c;大数据、云计算、高性能计算等技术的发展为人工智能的研究提供了更加广…

AI预测福彩3D采取887定位大底=23策略+杀断组+杀组选+杀和尾+杀和值012缩水测试5月16日预测第2弹

昨天的88723大底测试第一次测试&#xff0c;已经成功命中! 今天继续测试&#xff0c;仍旧目标为&#xff1a;10期中至少5中期。好了&#xff0c;废话不多说了&#xff0c;直接上结果吧~ 首先&#xff0c;887定位如下&#xff1a; 百位&#xff1a;5,7,6,4,2,9,0,1…

玩转Matlab-Simscape(初级)- 08 - 基于Solidworks、Matlab Simulink、COMSOL的协同仿真(案例实战)

** 玩转Matlab-Simscape&#xff08;初级&#xff09;- 08 - 基于Solidworks、Matlab Simulink、COMSOL的协同仿真&#xff08;案例实战&#xff09; ** 目录 玩转Matlab-Simscape&#xff08;初级&#xff09;- 08 - 基于Solidworks、Matlab Simulink、COMSOL的协同仿真&…

信息安全相关内容

信息安全 安全防护体系 安全保护等级 安全防护策略 安全技术基础 安全防护体系 安全防护体系有7个等级 安全保护等级 安全保护等级有5个等级,从上到下是越来越安全的用户自主其实就是用户自己本身具有的相应的能力 安全防护策略 安全策略是对抗攻击的主要策略安全日志: …

(论文笔记)TABDDPM:使用扩散模型对表格数据进行建模

了解diffusion model&#xff1a;什么是diffusion model? 它为什么好用&#xff1f; - 知乎 摘要 去噪扩散概率模型目前正成为许多重要数据模式生成建模的主要范式。扩散模型在计算机视觉社区中最为流行&#xff0c;最近也在其他领域引起了一些关注&#xff0c;包括语音、NLP…

Spring Security实现用户认证一:简单示例

Spring Security实现用户认证一&#xff1a;简单示例 1 原理1.1 用户认证怎么进行和保存的&#xff1f;认证流程SecurityContext保存 2 创建简单的登录认证示例2.1 pom.xml依赖添加2.2 application.yaml配置2.3 创建WebSecurityConfig配置类2.4 测试 1 原理 Spring Security是…

全栈式数据统计:Flask+Pandas按年,季度,月统计显示

话不多说,有图有源码 1.实现效果: 按季度统计 按月度统计: 2.实现源码: 2.1)test_pandashtml.py from flask import Flask, render_template import pandas as pdapp Flask(__name__)# 自定义千分位格式化函数 def format_thousands(x):return f{x:,.2f}app.route(/) def …

JVS物联网模拟点位:如何配置并自动生成点位数据全教程

模拟点位 功能描述 模拟点位常用于业务的调试或数据展示&#xff0c;通过配置对应点位实现自动生成点位数据的功能。 界面操作 如下图所示&#xff0c;从模拟点位菜单进入模拟点位管理界面 模拟点位新增 点击新增按钮&#xff0c;如下图所示&#xff1a; ①&#xff1a;用户…

一键解锁!贸易行业实现银行与财务系统秒级对接,效率飙升!

客户介绍 某贸易有限公司是一家实力雄厚的工贸一体跨国集团企业。作为行业内的佼佼者&#xff0c;该公司以出口家纺产品和生产销售建材洁具为核心业务。公司始终坚持以市场为导向&#xff0c;不断创新和优化产品和服务&#xff0c;以满足不断变化的市场需求。 客户痛点 以往&…

猛兽派对是什么游戏 猛兽派对攻略大全 苹果电脑怎么玩《猛兽派对》?

猛兽派对是多人派对类型的游戏&#xff0c;该款游戏的动作基于物理原理设计的&#xff0c;体验游戏玩家可以选择自己喜欢的小动物角色参加派对&#xff0c;游戏内具有很多不同的关卡可供挑战。 在steam平台上&#xff0c;猛兽派对对应英文名称是PartyAnimals&#xff0c;官方正…

服务器数据恢复—服务器重装系统导致分区丢失的数据恢复案例

服务器数据恢复环境&#xff1a; 一台服务器MD1200磁盘柜通过RAID卡创建了一组RAID5阵列并分配一个LUN。在Linux系统层面将该LUN划分了sdc1和sdc2两个分区。通过LVM扩容的方式将sdc1分区加入到了卷组中的一个逻辑卷中&#xff0c;sdc2分区格式化为XFS文件系统使用。Linux操作系…

Qt编译和使用freetype矢量字库方法

在之前讲过QT中利用freetype提取字库生成图片的方法&#xff1a; #QT利用freetype提取字库图片_qt freetype-CSDN博客文章浏览阅读1.2k次。这是某个项目中要用到的片段&#xff0c;结合上一篇文章#QT从字体名获取字库文件路径使用// 保存位图int SaveBitmapToFile(HBITMAP hBi…

一行代码实现vip标志的显示

需求说明 在项目中&#xff0c;后期添加了一种用户类型。需要再用户头像右下角显示一个vip的标志。问题是只要有头像的地方都要显示。而有头像的地方很多&#xff0c;设置到的接口也很多。后面考虑通过一个工具类&#xff0c;将这个功能外挂到原来的业务需要的地方。 实现效果…

二进制部署Kubernetes集群——单Master和Node组件

前言 本文将介绍如何使用二进制文件手动搭建 Kubernetes v1.20 集群。通过这种方法&#xff0c;我们可以更好地理解 Kubernetes 的内部工作原理&#xff0c;并具备更大的灵活性和控制权。下面将逐步构建 Kubernetes 集群&#xff0c;并进一步了解其各个组件之间的交互和配置。…