【C数据结构】动态顺序表_SeqList

目录

 【1】数据结构概述

【1.1】什么是数据结构?

【1.2】数据结构分类

【1.3】数据结构术语

【2】数据结构特点

【2】动态顺序表

【2.1】动态顺序表定义数据结构和接口

【2.1】动态顺序表创建初始化

【2.2】动态顺序表初始化

【2.3】动态顺序表内存释放

【2.4】动态顺序表检测扩容

【2.5】动态顺序表头插入

【2.6】动态顺序表尾插入

【2.7】动态顺序表指定位置前插入

【2.8】动态顺序表指定位置后插入

【2.9】动态顺序表头删除

【2.10】动态顺序表尾巴删除

【2.11】态顺序表指定位置前删除

【2.12】动态顺序表指定位置后删除

【2.13】动态顺序表有效数据个数

【2.14】动态顺序表查找

【2.14】动态顺序表修改

【2.15】动态顺序表打印

【2.16】动态顺序表判断空


 【1】数据结构概述

【1.1】什么是数据结构?

官方解释:数据结构是一门研究非数值计算的程序设计问题中的操作对象,以及他们之间的关系和操作等相关问题的学科。

大白话:数据结构就是把数据元素按照一定的关系组织起来的集合,用来组织和存储数据。

【1.2】数据结构分类

逻辑结构分类:

逻辑结构是从具体问题中抽象出来的模型,是抽象意义上的结构,按照对象中数据元素之间的相互关系分类,也是我们后面课题中需要关注和讨论的问题。

  • 集合结构:

结合结构中数据元素出了属于同一集合外,他们之间没有任何其他关系。

  • 线性结构:

线性结构中的数据元素之间存在一对一的关系。

  • 树形结构:

树形结构中的数据元素之间存在多对一的层次关系。

  • 图形结构:

图形结构的数据元素是多对多的关系。

物理结构分类:

        逻辑结构在计算机中真正的表示方式(又称映像)称为物理结构,也可以叫做存储结构,常见的物理结构有顺序存储结构、链式存储结构。

顺序存储结构:

        逻辑结构在计算机中真正的表示方式(又称映像)称为物理结构,也可以叫做存储结构,常见的物理结构有顺序存储结构、链式存储结构。

        顺序存储结构存在一定的弊端,就想生活中排队时,会有人插队也有可能有人突然离开,这时候整个结构都处于变化之中,此时就需要链式存储结构。

        是把数据元素存放在任意的存储单元里面,这组存储单元可以是连续的,也可以是不连续的。此时,数据元素之间的关系,并不能反映元素间的逻辑关系,因此链式存储中引进了一个指针存放数据元素的地址,这样通过地址就可以找到相关联数据元素的位置。

【1.3】数据结构术语

        抽象数据类型:(Abstract Data Type,简称ADT)是指一个数学模型以及定义在该模型上的一组操作。抽象数据类型的定义仅取决于它的一组逻辑特性,而与其在计算机内部如何表示和实现无关,即不论其内部结构如何变化,只要它的数学特性不变,都不影响其外部的使用。

        抽象数据类型和数据类型实质上是一个概念。例如,各个计算机都拥有的“整数”类型是一个抽象数据类型,尽管它们在不同处理器上实现的方法可以不同,但由于其定义的数学特性相同,在用户看来都是相同的。因此,“抽象”的意义在于数据类型的数学抽象特性。

        数据结构的表示(存储结构)类型定义( typedef)描述。数据元素类型约定为Data。

【2】数据结构特点

线性结构的特点是:

        在数据元素的非空有限集合中。

  • 存在唯一的一个被称为"第一个"的数据元素
  • 存在唯一的一个被称为“最后一个”的数据元素
  • 除了第一个之外,结合中的每个数据元素均只有一个前驱
  • 除了最后一个之外,集合中每个数据元素均只有一个后继

        顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

        线性表示一个相当灵活的数据结构,它的长度可以根据需要增长或缩短,即对线性表的数据元素不仅可以进行访问,还可以进行插入和删除等。

【2】动态顺序表

【2.1】动态顺序表定义数据结构和接口

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
​
/* 动态顺序表-数据结构 */ 
typedef int SEQLDataType;
typedef struct SequenceList {
    SEQLDataType* _data;            // 数组类型:存储容器.
    size_t _size;                   // 有效数据个数.
    size_t _capacity;               // 有效容器容量.
}SeqList;
​
/* 动态顺序表-创建初始化函数 */
SeqList* SequenceListCreateInitialize();
​
/* 动态顺序表-初始化函数 */
void SequenceListInitialize(SeqList* pSL);
​
/* 动态顺序表-释放内存 */
void SequenceListDestory(SeqList* pSL);
​
/* 动态顺序表-检测容量 */
void SequenceListCheakCapacity(SeqList* pSL);
​
/* 动态顺序表-头部插入 */
void SequenceListPushFront(SeqList* pSL, SEQLDataType val);
​
/* 动态顺序表-尾部插入 */
void SequenceListPushBack(SeqList* pSL, SEQLDataType val);
​
/* 动态顺序表-指定位置前插入 */
void SequenceListPushInsterFront(SeqList* pSL, size_t pos, SEQLDataType val);
​
/* 动态顺序表-指定位置后插入 */
void SequenceListPushInsterBack(SeqList* pSL, size_t pos, SEQLDataType val);
​
/* 动态顺序表-头部删除 */
void SequenceListPopFront(SeqList* pSL);
​
/* 动态顺序表-尾部删除 */
void SequenceListPopBack(SeqList* pSL);
​
/* 动态顺序表-指定位置前删除 */
void SequenceListPopEraseFront(SeqList* pSL, size_t pos);
​
/* 动态顺序表-指定位置后删除 */
void SequenceListPopEraseBack(SeqList* pSL, size_t pos);
​
/* 动态顺序表-大小 */
size_t SequenceListSize(SeqList* pSL);
​
/* 动态顺序表-查找 */
int SequenceListFind(SeqList* pSQL, SEQLDataType val);
​
/* 动态顺序表-修改 */
void SequenceListModification(SeqList* pSQL, size_t pos, SEQLDataType val);
​
/* 动态顺序表-打印 */
void SequenceListPrint(SeqList* pSQL);
​
/* 动态顺序表-判空 */
bool SequenceListEmpty(SeqList* pSQL);

【2.1】动态顺序表创建初始化

创建结构体指针,对其进行初始话。

/* 动态顺序表-创建初始化函数 */
SeqList* SequenceListCreateInitialize() {
    // 创建SeqList指针对象,初始化后返回指针.
    SeqList* pTemp = (SeqList*)malloc(sizeof(SeqList));
    if (pTemp == NULL) {
        perror("SequenceListCreateInitialize malloc fail!\n");
        exit(-1);
    }
​
    // 处理数据.
    pTemp->_data = NULL;
    pTemp->_size = pTemp->_capacity = 0;
    return pTemp;
}

【2.2】动态顺序表初始化

/* 动态顺序表-初始化函数 */
void SequenceListInitialize(SeqList* pSL) {
    // 断言保护指针数据.
    assert(pSL);

    // 处理数据.
    pSL->_data = NULL;
    pSL->_size = pSL->_capacity = 0;
}

【2.3】动态顺序表内存释放

/* 动态顺序表-释放内存 */
void SequenceListDestory(SeqList* pSL) {
    // 断言保护指针数据.
    assert(pSL);

    free(pSL->_data);
    pSL->_data = NULL;
    free(pSL);
    pSL = NULL;
}

【2.4】动态顺序表检测扩容

        这个检测扩容的函数提前拿出来说一下,在每次进行添加数据的时候,都要进行检测扩容,如果数据不足的话就应该进行扩容了,值得注意的是,此程序没有初始化的开辟内存,当容量和数据个数相等的时候,会自己判断是否是第一次扩容。

/* 动态顺序表-检测容量 */
void SequenceListCheakCapacity(SeqList* pSL) {
    // 断言保护指针数据.
    assert(pSL);
    
    // 检查扩容.
    if (pSL->_size == pSL->_capacity) {
        // 程序走到这里,说明需要进行扩容了.
        // 检查是否是第一次扩容,第一次扩容扩4个,第二次扩容扩2倍.
        size_t newCapacity = pSL->_capacity == 0 ? 4 : pSL->_capacity * 2;
        SEQLDataType* pTemp = (SEQLDataType*)realloc(pSL->_data, sizeof(SEQLDataType) * newCapacity);
        if (pTemp == NULL) {
            perror("SequenceListCheakCapacity realloc faid!\n");
            exit(-1);
        }

        // 程序走到这里说明扩容成功了,数据进行处理.
        pSL->_data = pTemp;
        pTemp = NULL;
        // 更新容量.
        pSL->_capacity = newCapacity;
    }

}

代码这里用了realloc这个函数进行扩容的,为啥不用malloc呢?

【2.5】动态顺序表头插入

        在头插前我们需要把第一位的数据空出来,注意:我们需要倒这拿数据。

/* 动态顺序表-头部插入 */
void SequenceListPushFront(SeqList* pSL, SEQLDataType val) {
    // 断言保护指针数据.
    assert(pSL);

    // 检测扩容.
    SequenceListCheakCapacity(pSL);

    // 插入数据,将数据从后往前挪动,挪动完成下标为0的数据就可以插入了.
    size_t end = SequenceListSize(pSL);
    while (end > 0) {
        pSL->_data[end] = pSL->_data[end - 1];
        --end;
    }

    // 挪动完成,将数据插入0位置.
    pSL->_data[0] = val;
    ++pSL->_size;
}

【2.6】动态顺序表尾插入

/* 动态顺序表-尾部插入 */
void SequenceListPushBack(SeqList* pSL, SEQLDataType val) {
    // 断言保护指针数据.
    assert(pSL);

    // 检测扩容.
    SequenceListCheakCapacity(pSL);

    // 挪动完成,将数据插入0位置.
    pSL->_data[SequenceListSize(pSL)] = val;
    ++pSL->_size;
}

【2.7】动态顺序表指定位置前插入

/* 动态顺序表-指定位置前插入 */
void SequenceListPushInsterFront(SeqList* pSL, size_t pos, SEQLDataType val) {
    // 断言保护指针数据.
    assert(pSL);

    // 检测扩容.
    SequenceListCheakCapacity(pSL);

    // 移动数据
    // 这里需要注意:如果顺序表没有数据的话,直接进行尾插。
    size_t end = SequenceListSize(pSL);
    while (end > pos) {
        pSL->_data[end] = pSL->_data[end - 1];
        --end;
    }
    pSL->_data[pos] = val;
    ++pSL->_size;
}

【2.8】动态顺序表指定位置后插入

        与指定位置前插入是一致的,注意:数组边界,否侧会出现访问冲突。

![1-9](E:\文档\【ShaXiang】LearningNotes\【LessonRecord】C.C++_数据结构与算法\【01】\1-9.png)/* 动态顺序表-指定位置后插入 */
void SequenceListPushInsterBack(SeqList* pSL, size_t pos, SEQLDataType val) {
    // 断言保护指针数据.
    assert(pSL);

    // 检测扩容.
    SequenceListCheakCapacity(pSL);

    // 移动数据
    // 这里需要注意:如果顺序表没有数据的话,直接进行尾插。
    if (pos == 0) {
        size_t end = SequenceListSize(pSL);
        while (end > pos + 1) {
            pSL->_data[end] = pSL->_data[end - 1];
            --end;
        }
        pSL->_data[pos + 1] = val;
        ++pSL->_size;
    }
    else {
        size_t end = SequenceListSize(pSL);
        while (end > pos) {
            pSL->_data[end] = pSL->_data[end - 1];
            --end;
        }
        pSL->_data[pos + 1] = val;
        ++pSL->_size;
    }
}

【2.9】动态顺序表头删除

/* 动态顺序表-头部删除 */
void SequenceListPopFront(SeqList* pSL) {
    // 断言保护指针数据.
    assert(pSL);

    // 检查是否还有数据存在.
    if (SequenceListEmpty(pSL)) {
        printf("SeqList Not Data!\n");
        return;
    }

    // 直接删除数据,容器数组中从元素下标0开始,依次往前覆盖数据.
    size_t begin = 0;
    while (begin < SequenceListSize(pSL) - 1) {
        pSL->_data[begin] = pSL->_data[begin + 1];
        ++begin;
    }    

    --pSL->_size;
}

【2.10】动态顺序表尾巴删除

        尾插的时候无非注意的就是,在插之前检查容量是否满足,让size指向的下表位置的数据存储要插入的数据。

/* 动态顺序表-尾部删除 */
void SequenceListPopBack(SeqList* pSL) {
    // 断言保护指针数据.
    assert(pSL);

    // 检查是否还有数据存在.
    if (SequenceListEmpty(pSL)) {
        printf("SeqList Not Data!\n");
        return;
    }

    --pSL->_size;
}

【2.11】态顺序表指定位置前删除

/* 动态顺序表-指定位置前删除 */
void SequenceListPopEraseFront(SeqList* pSL, size_t pos) {
    // 断言保护指针数据.
    assert(pSL);

    // 检查是否还有数据存在.
    if (SequenceListEmpty(pSL)) {
        printf("SeqList Not Data!\n");
        return;
    }

    // 和头删是一样的,将0的位置变为pos的位置.
    size_t begin = pos;
    while (begin < SequenceListSize(pSL)) {
        pSL->_data[begin] = pSL->_data[begin + 1];
        ++begin;
    }

    --pSL->_size;
}

【2.12】动态顺序表指定位置后删除

        指定位置后删除和指定位置前删除是一致的,注意:处理边界问题

/* 动态顺序表-指定位置后删除 */
void SequenceListPopEraseBack(SeqList* pSL, size_t pos) {
    // 断言保护指针数据.
    assert(pSL);

    // 检查是否还有数据存在.
    if (SequenceListEmpty(pSL)) {
        printf("SeqList Not Data!\n");
        return;
    }

    // 和头删是一样的,将0的位置变为pos的位置.
    size_t begin = pos + 1;
    if (begin == SequenceListSize(pSL)) {
        --pSL->_size;
    }
    else {
        while (begin < SequenceListSize(pSL)) {
            pSL->_data[begin] = pSL->_data[begin + 1];
            ++begin;
        }
    }
}

【2.13】动态顺序表有效数据个数

/* 动态顺序表-大小 */
size_t SequenceListSize(SeqList* pSL) {
    // 断言保护指针数据.
    assert(pSL);

    return pSL->_size;
}

【2.14】动态顺序表查找

/* 动态顺序表-查找 */
int SequenceListFind(SeqList* pSL, SEQLDataType val) {
    // 断言保护指针数据.
    assert(pSL);

    // 遍历查找.
    for (size_t i = 0; i < SequenceListSize(pSL); ++i) {
        if (pSL->_data[i] == val)
            return (int)i;
    }

    // 程序走到这里说明没有找到对应的值.
    return -1;
}

【2.14】动态顺序表修改

/* 动态顺序表-修改 */
void SequenceListModification(SeqList* pSL, size_t pos, SEQLDataType val) {
    // 断言保护指针数据.
    assert(pSL);
    
    // 遍历修改.
    pSL->_data[pos] = val;
}

【2.15】动态顺序表打印

/* 动态顺序表-打印 */
void SequenceListPrint(SeqList* pSL) {
    // 断言保护指针数据.
    assert(pSL);
    
    // 遍历打印.
    for (size_t i = 0; i < SequenceListSize(pSL); ++i) {
        printf("%d ", pSL->_data[i]);
    }
    printf("\n");
}

【2.16】动态顺序表判断空

/* 动态顺序表-判空 */
bool SequenceListEmpty(SeqList* pSL) {
    // 断言保护指针数据.
    assert(pSL);

    return pSL->_size == 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mac电脑储存内存越来越小如何清理释放空间?

如果你是一位Mac系统的用户&#xff0c;可能会发现你的电脑储存空间越来越小。虽然Mac系统设计得非常优秀&#xff0c;但是系统数据和垃圾文件也会占据大量的储存空间。在这篇文章中&#xff0c;我们将探讨mac系统数据怎么这么大&#xff0c;以及mac清理系统数据怎么清理。 一…

万字详解常用设计模式

本文是博主在工作中对常用设计模式的使用经验总结归纳而来分享给大家。 设计模式一共有23种&#xff0c;本文讲解涉及如下&#xff1a; 责任链模式 模板方法模式 发布订阅模式 策略模式 三大分类 业界一般将设计模式分为三大类&#xff1a; 创建型模式&#xff1a;对类的实…

5、产品经理的工作职责OR主要工作技能和工具

1、产品经理的工作职责 我们通过一个案例来了解产品经理的工作职责。 老板让你给他点餐&#xff0c;你应该怎么做&#xff1f;你需要考虑哪一些方面的问题&#xff1f; 例如&#xff1a;你预算多少&#xff0c;预算是十块钱还是100块还是1000块。有没有忌口&#xff0c;口味…

Kafka详解(一)

第1章 Kafka概述 1.1 定义 1.2 消息队列 目前企业中比较常见的消息队列产品主要有Kafka、ActiveMQ、RabbitMQ、RocketMQ等。Message Queue ② 在大数据场景主要采用Kafka作为消息队列 ② 在JavaEE开发中主要采用ActiveMQ、RabbitMQ、RocketMQ Kafka存储数据&#xff0c;且保证…

「网络编程」第一讲:初识网络_网络基础1

「前言」文章是关于网络编程方面的&#xff0c;今天内容大致是网络基础&#xff0c;讲解下面开始&#xff01; 「归属专栏」网络编程 「笔者」枫叶先生(fy) 「座右铭」前行路上修真我 「枫叶先生有点文青病」 「每篇一句」 青山不改&#xff0c;绿水长流 ——白居易 目录 一、…

新手快速搭建springboot项目

一、创建项目 1.1、创建项目 1.2、配置编码 1.3、取消无用提示 1.4、取消无用参数提示 二、添加POM父依赖 <!-- 两种方式添加父依赖或者import方式 --> <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-p…

微信小程序触底加载scroll-view

微信小程序触底加载 scroll-view 了解什么是触底加载&#xff1f; 需求&#xff1a;有个固定高度的容器&#xff0c;实现容器里面的内容触底加载 1、内容盒子的高度 2、盒子里内容的总高度 3、滚动条的scrollTop 触底加载的原理就是 当里面的容器触底的时候进行分页&#xff0…

Ansible-playbook-roles安装lnmp

使用roles安装lnmp 1、准备四台主机 192.168.142.10 192.168.142.20 192.168.142.30 192.168.142.40 2、10作为ansible管理端 首先ssh连接剩下三台主机 3、vim/etc/ansible/hosts 添加[nginxservers]配置nginx ip,[phpservers]php ip,[mysqlservers]mysql ip 4、cd /etc/ansibl…

0基础学习VR全景平台篇第42篇:编辑器底部菜单-分组管理

大家好&#xff0c;欢迎观看蛙色VR官方系列——后台使用课程&#xff01; 本期为大家带来蛙色VR平台&#xff0c;底部菜单—分组管理功能操作。 功能位置示意 一、本功能将用在哪里&#xff1f; 分组管理&#xff0c;指观看者可点击不同分组&#xff0c;查看不同类型全景内容…

【ROS】ROS+Gazebo强化学习:训练

1、安装ROS1 【ROS】Ubuntu20.04安装ROS1 2、安装Anaconda 【AI】PyTorch入门&#xff08;一&#xff09;&#xff1a;通过Anaconda安装PyTorch 【PyThon】Anaconda常用命令 3、源码下载 使用论文 Goal-Driven Autonomous Exploration Through Deep Reinforcement Learnin…

Springboot整合Camunda工作流引擎实现审批流程实例

环境&#xff1a;Spingboot2.6.14 camunda-spring-boot-starter7.18.0 环境配置 依赖配置 <camunda.version>7.18.0</camunda.version> <dependency><groupId>org.camunda.bpm.springboot</groupId><artifactId>camunda-bpm-spring-boo…

Redis-缓存

新增或者更新数据时,创建以后顺便存到redis中去【维护缓存】 获取的时候先从redis缓存中拿数据 如果拿数据的时候为空,则到数据库中拿数据,后再存到redis缓存中去 大量的商品【包括冷门商品】都进行上面的缓存,那么就很耗内存 针对每个数据进行缓存的时候 维护一个过期时间…

计算服务资源调度管理

文章目录 前言总体架构“ULT”和“KLT”抽象“内核”“容器”“虚容器” 内存抽象虚拟存储&#xff08;容器调用&#xff09; 多机器调度 前言 今天复习了一下操作系统&#xff0c;系统过了一下&#xff0c;感觉还有点时间&#xff0c;那么顺便来讨论一下&#xff0c;关于我的…

使用VScode + clangd 阅读 c/c++ 源码环境搭建

使用Vscode clangd 阅读c/c源码 一、需求 在嵌入式软件开发的工作中&#xff0c;我们常常需要分析C/C代码&#xff0c;比如linux kernel 的代码&#xff0c;而公司的代码一般都会存放在服务器中&#xff0c;服务器一般是linux&#xff0c;且无法联网&#xff0c;我们只能通过…

qt creator使用问题

qt creator 多版本安装需要(单独下载qtcreator安装版本)&#xff0c;安装目录默认在Qt目录下&#xff08;qt的sdk也在qt目录下&#xff09; 编译过程中遇到一些很奇怪问题&#xff0c;建议优先重新编译。 issue qtcreator inappropriate for the inferior 构建套件&#x…

我准备蓝桥杯的这一年

我准备蓝桥杯的这一年 文章目录 我准备蓝桥杯的这一年起步和目标确定渐入佳境焦虑疲惫&#xff0c;一天又一天国赛我来力总结 我将我这段 流水账分为四个阶段。谨以此文&#xff0c;祭奠我这一年来的焦虑、白发~ &#xff0c;最终也取得了预期的成绩。不知未来再看此章会作何感…

网络编程重点

1>OIS 7层模型 用户空间&#xff1a;应用层 7>提供各种网络接口 表示层 6>数据表示&#xff0c;加密与压缩 会话层 5>主机之间会话管理 内核空间&#xff1a;传输层 4&…

【Java基础学习打卡05】命令提示符

目录 前言一、命令提示符是什么二、命令提示符常用命令1.打开命令提示符2.命令演示3.常用命令 总结 前言 知道命令提示符是什么&#xff0c;熟练打开命令提示符&#xff0c;熟练使用常用命令&#xff0c;并自行尝试其他命令。本文只是对命令提示符进行简单介绍和使用。 一、命…

chatgpt赋能python:Python截取指定字符操作:让你的SEO优化变得更简单

Python截取指定字符操作&#xff1a;让你的SEO优化变得更简单 在SEO优化中&#xff0c;截取指定字符是一个非常常见的操作。Python作为一款开源的高级编程语言&#xff0c;提供了许多方便的函数和方法来处理文本操作&#xff0c;包括截取指定字符。在本文中&#xff0c;我们将…

在线DDL操作踩坑记录

官方地址&#xff1a;GitHub - github/gh-ost: GitHubs Online Schema-migration Tool for MySQL 使用ghost方式在线对mysql表进行ddl ghost原理&#xff1a; 要对表A进行DDL&#xff0c;在主库建立一个ghost表 A1在表A1上进行alter操作伪装成一个mysql的从库&#xff0c;监…