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

news2024/12/28 18:05:21

目录

 【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;
}

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

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

相关文章

【Express.js】处理请求数据

处理请求数据 本节将具体介绍express后端处理请求源携带数据的一些方法和技巧 动态路径 很多时候我们需要处理一些类似但有操作差别或不同对象的业务&#xff0c;我们可以监听一段基本路径&#xff0c;将其中某一个段或者某几段路径作为变量&#xff0c;在接口中根据不同的路…

大学计算机专业实习心得报告13篇

大学计算机专业实习心得报告&#xff08;篇1&#xff09; 通过理论联系实际&#xff0c;巩固所学的知识&#xff0c;提高处理实际问题的能力&#xff0c;为顺利毕业进行做好充分的准备&#xff0c;并为自己能顺利与社会环境接轨做准备。通过这次实习&#xff0c;使我们进一步理…

chatgpt赋能python:如何用Python创建优秀的项目

如何用Python创建优秀的项目 Python是一种功能强大的编程语言&#xff0c;可用于创建各种不同类型的项目。本文将介绍如何使用Python创建优秀的项目&#xff0c;并包括一些有用的技巧和工具。在本文中&#xff0c;我们将着重讨论如何优化我们的Python项目以获得更好的SEO排名。…

Gitlab 服务器搭建

引言 GitLab 是一个用于仓库管理系统的开源项目&#xff0c;使用Git作为代码管理工具&#xff0c;并在此基础上搭建起来的Web服务。安装方法是参考GitLab在GitHub上的Wiki页面。Gitlab是被广泛使用的基于git的开源代码管理平台, 基于Ruby on Rails构建, 主要针对软件开发过程中…

C语言:求输入的两个数的最小公倍数

题目&#xff1a; 求输入的两个数的最小公倍数 思路一&#xff1a;普通方法 &#xff08;思路简单&#xff0c;效率较低&#xff09; 总体思路&#xff1a; &#xff08;一&#xff09;. 输入两个数&#xff1a;a 和 b&#xff0c; 使用 三目表达式 把较大值 取出 &#xff…

[元带你学: eMMC协议详解 17] eMMC 安全方案 之 RPMB(Replay Protected Memory Block 重放保护内存块)

依JEDEC eMMC 5.1及经验辛苦整理&#xff0c;付费内容&#xff0c;禁止转载。 所在专栏 《元带你学: eMMC协议详解》 内容摘要 全文 6300 字&#xff0c; 主要内容有 目录 1 概念 2 容量大小 3 重放保护的原理 4 不同访问类型流程 4.1. 写认证密钥&#xff08;write Au…

coder oss 真正私有化部署的云端开发环境,nas也可以装

先看效果&#xff1a; 主界面&#xff0c;显示了你有那些工作空间 某个工作空间&#xff0c;我这里集成了web版vscode&#xff0c;也可以使用本地的vscode和其他开发IDE 有独立的终端和集成webide 以后就可以一个ipad都可以写代码了&#xff1b; 下面是平台搭建过程&#xff0…

C语言入门基础知识(万字笔记)

一、前言部分 本篇文章&#xff0c;将会主要介绍c语言的基本数据类型、基本运算符、语句&#xff0c;三大结构、数组、指针、宏定义等内容 二、具体部分 1、基本数据类型 1、基本数据类型 在C语言中&#xff0c;承载一系列信息的数字或中字符都属于数据类型&#xff0c;计算…

产品设计.B端产品vsC端产品

一、用户群体 01、B端&#xff1a;一般是多角色群体、多维度&#xff0c;一般是3个维度&#xff0c;决策者&#xff08;老板&#xff09;、管理者&#xff08;财务、业务部门负责人&#xff09;和执行者&#xff08;使用的用户&#xff09;。 02、C端&#xff1a;群体相对单一…

K8s 中 port, targetPort, NodePort的区别

看1个例子&#xff1a; 我们用下面命令去创建1个pod2&#xff0c; 里面运行的是1个nginx kubectl create deployment pod2 --imagenginx当这个POD被创建后&#xff0c; 其实并不能被外部访问&#xff0c; 因为端口映射并没有完成. 我们用下面这个命令去创建1个svc &#xff…

msvcp140.dll是什么?怎么解决电脑提示msvcp140.dll丢失的问题?(分享解决方法)

msvcp140.dll是动态链接库文件&#xff0c;是一种不可执行的二进制程序文件&#xff0c;允许程序共享执行特殊任务所需要的代码和其他资源。程序可根据DLL文件中的指令打开、启用、查询、禁用和关闭驱动程序。 很多小伙伴在使用电脑软件的时候&#xff0c;有一些问题会搞不明白…

C语言之枚举联合

一、枚举 枚举顾名思义就是&#xff1a;列举 。 即把可能的取值一一列举出来 &#xff08;一&#xff09;枚举类型的定义 这里我们直接上代码&#xff1a; //枚举类型 #include <stdio.h>enum Sex//性别 {//枚举的可能取值-常量MALE 2,FEMALE 4,SECRET 8//以上为给…

LAMP架构及搭建LAMP+Discuz论坛

LAMP架构及搭建LAMPDiscuz论坛的流程 1、LAMP架构概述2、LAMP各组件的作用3、LAMP的安装顺序4、LAMP的数据流向5、编译安装Apache5.1 关闭防火墙和slinux&#xff0c;将安装Apache所需软件包传到/opt目录下并解压5.2 安装环境依赖包5.3 选择Apache软件模块5.4 编译和安装5.5 优…

使用 Sa-Token 实现 [记住我] 模式登录、七天免登录

一、需求分析 如图所示&#xff0c;一般网站的登录界面都会有一个 [记住我] 按钮&#xff0c;当你勾选它登录后&#xff0c;即使你关闭浏览器再次打开网站&#xff0c;也依然会处于登录状态&#xff0c;无须重复验证密码&#xff1a; 本文将详细介绍在 Sa-Token中&#xff0c;…

移动机器人底盘-四轮差速模型(四轮独立)

移动机器人底盘-四轮差速模型 文章目录 移动机器人底盘-四轮差速模型1. 四轮差速模型原理2. 工程实践2.1 Python实现2.2 C实现 1. 四轮差速模型原理 四轮差速模型底盘实例如下图所示。对于底盘的前轮和后轮来说&#xff0c;其速度是同步的&#xff0c;那么在理想条件下&#x…

PHY芯片的使用(一)之基本概念讲解(MII相关)2

今天想和大家交流一下MAC和PHY之间的接口MII。 MII(Media Independent Interface )是介质无关接口。MII接口定义了在MAC层和物理层之间传送数据和控制状态等信息的接口&#xff0c;它是10M和100M兼容的接口&#xff0c;经过扩展后还可以用于1000M的MAC层与物理层的接口&#x…

【libdatachannel】Transport的设计实现

作为ice传输实现的基类 具有实际的作用。 D:\XTRANS\thunderbolt\ayame\ZHB_LIB_DATACHANNEL\src\impl\transport.cpp 最重要的是封装了对impl的调用 Transport 比较牛,抽象了传输的基础能力 发送(调用ice接口发送) send(message_ptr message);接收(通过ice收到后使用回调方…

msvcp140.dll下载,无法启动此程序,因为计算机中丢失msvcp140.dll的解决方法

msvcp140.dll是动态链接库文件&#xff0c;是一种不可执行的二进制程序文件&#xff0c;允许程序共享执行特殊任务所需要的代码和其他资源。程序可根据DLL文件中的指令打开、启用、查询、禁用和关闭驱动程序。 很多小伙伴在使用电脑软件的时候&#xff0c;有一些问题会搞不明白…

layui框架学习(27:弹出层模块_其它用法)

除了前几篇文章介绍的弹出框类型外&#xff0c;layui的layer弹出层模块还支持相册框和tab框&#xff0c;所谓相册框即点击图片或按钮后会出现一个类似相册的页面单独浏览、切换图片&#xff0c;而tab框是指弹出框的显示形式类似于Winform中的TabControl控件&#xff0c;能以选项…

如何把一个 Git 仓库的分支加入另一个无关的 Git 仓库

文章目录 笔者需要将两个无关的 Git 仓库合并&#xff0c;也就是把一个 Git 仓库的分支加入另一个无关的 Git 仓库。笔者琢磨了一下之后就实现了。方法如下。 笔者的运行环境&#xff1a; git version 2.37.0.windows.1 TortoiseGit 2.11.0.0 IntelliJ IDEA 2023.1.1 (Ultima…