数据结构(基本概念及顺序表)
基本概念:
1、引入
程序=数据结构+算法
数据:
数值数据:能够直接参加运算的数据(数值,字符)
非数值数据:不能够直接参加运算的数据(字符串、图片等)
数据即是信息的载体,能够被输入到计算机中存储,识别和处理的符号总称;
数据元素:
数据的一个基本单位,又叫做记录;
数据类型:
数据元素决定了数据的存储范围以及计算方法;例如:short x;则这个x的取值范围【-32768,+32767】,限定计算{+ - * / %}
数据结构:
数据结构就是去探讨数据元素与数据元素之间的相互关系的学科;
2、基本概念
逻辑结构:数据元素之间的抽象关系(相邻/隶属)
存储结构:在计算机中的具体实现方法
数据运算:对数据进行的操作,例如:增删改查
3、逻辑结构
集合(gather):数据元素在同一范围内部,无其他关系
表(list):一对一,例如:线性表,队列,栈
树(tree):一对多
图(graph):多对多
4、存储结构
存储结构又叫做物理结构,存放到地址上的关系;
顺序存储(sequence):在存储器上按照顺序存放
链式存储(link):利用元素存储地址的指针来描述元素之间的关系
索引存储:(index):在存储数据时额外提供一张索引表
散列存储(hash):先提供一个散列函数,利用散列函数去计算存储位置
数据的逻辑结构与存储结构关系密切
算法的设计:取决于决定的逻辑结构
算法的实现:依赖与采用的存储结构
5、算法
算法是一个有穷规则(语句、命令)的有序集合,它确定了解决某一个问题的一个运算序列。对于问题的初始输入,通过算法的有限步的运行,产生一个或多个输出。
算法的特性:
1)有穷性——算法执行的步骤是有限的
2)确定性——每一个计算步骤是唯一的
3)可行性——每个计算步骤能在有效的时间内完成
4)输入——算法可以有零个或者多个外部输入
5)输出——算法有一个或多个输出
算法的优劣:
1)消耗的时间的多少
2)消耗的存储空间的多少
3)容易理解,容易实现调试和维护是否容易
6、时间复杂度T(n)
通过问题的规模,算法所消耗的时间的多少
#include <stdio.h>
int main(int argc, char *argv[])
{for(int i=0;i<n-1;i++) //=>n-1{for(int j=0;j<n-1-i;j++) //=>(n-1)/2{}}return 0;
}
频度:语句执行的次数
每一条语句的频度之和就是这个算法的时间复杂度
上述代码的时间复杂度为:(n-1)*(n-1)/2 ==>n²/2 - n + 1/2 (当n趋于无穷大时和n²为同阶无穷大)
冒泡排序的时间复杂度(o(n²))
7、空间复杂度D(n)
通过问题规模的扩大,所需要的额外空间的量
8、线性表
线性表的特征:
1)对于非空表而言,a0表头没有前驱
2)an-1表尾,没有后继
3)对于其它的每一个元素ai有且仅有一个直接前驱和直接后继
9、数据结构创建表时之所以常在堆区开空间,主要基于以下几点原因:
1. 灵活性和动态性
-
动态内存分配:堆区允许程序员在运行时动态地分配和释放内存,这意味着可以根据实际需要调整数据结构的大小,而无需在编译时就确定其大小。这对于链表、动态数组等需要频繁调整大小的数据结构尤为重要。
-
避免栈溢出:栈区通常用于存储局部变量和函数调用信息,其空间有限。如果数据结构过大或复杂,可能会导致栈溢出。而在堆区分配内存可以避免这一问题,因为堆区的空间相对较大,且由程序员控制释放。
2. 内存管理灵活性
-
手动管理内存:在堆区分配的内存需要程序员手动释放(使用如
free
等函数),这提供了更大的内存管理灵活性。程序员可以根据需要决定何时释放内存,从而优化内存使用。 -
生命周期控制:堆区分配的内存的生命周期由程序员控制,这意味着可以在数据结构不再需要时立即释放内存,减少内存泄漏的风险。
3. 链表等特殊数据结构的需要
-
链表节点:链表节点通常需要在堆区分配内存,因为链表节点的数量和位置在运行时是动态变化的。每个节点都包含数据域和指针域(指向下一个节点的指针),这些节点在内存中的位置不连续,因此适合在堆区分配。
-
内存碎片化:链表等数据结构能够很好地适应内存碎片化的情况,因为它们在堆区分配内存时不需要连续的内存块。
4. 性能优化
-
局部性原理:虽然堆区分配的内存可能不如栈区分配的内存那样具有局部性(即内存访问的集中性),但对于某些数据结构(如哈希表、红黑树等),其内存访问模式可能更适合在堆区分配内存。
-
减少栈空间占用:将大型数据结构放在堆区可以减少栈空间的占用,从而降低栈溢出的风险,并提高程序的稳定性。
顺序表
顺序存储的线性表
顺序存储结构的特点:
1)逻辑上相邻的元素ai,ai+1,其存储位置也是相邻的;
2)对数据元素ai的存取为随机存取或按地址存取
3)存储密度高,存储密度=(数据结构中元素所占存储空间)/(整个数据结构所占空间)
顺序存储结构的不足:
1)对表的插入和删除等运算的时间复杂度较差
2)要求系统提供一片较大的连续存储空间
3)插入、删除等运算耗时,且存在元素在存储器中成片移动的现象
#ifndef _SEQLIST_H
#define _SEQLIST_H#include <stdio.h>
#include <stdlib.h>typedef int Type; //声明顺序表的数据类型
#define LEN 10 //顺序表的大小
#define OUT(A) {printf("%d ",A);} //宏函数最好加;和{}typedef struct{Type data[LEN]; //表的存储空间int count; //记录表的已存元素量
}list; //线性表结构体//创建
list *create_list(); //结构体指针
//判满(满为0,不满为1,错误为-1)
int full_list(list *l);
//判空(空为0,非空为1,错误为-1)
int null_list(list *l);void whether_full(int a);//初始化
void init_list(list *l);
//求长度
int length_list(list *l);
//首插入
void head_insert_list(list *l,Type data);
//插入(尾插)
void insert_list(list *l,Type data);
//查找 按值找,把找到值的下标返回
int search_list(list *l,Type data);
//更新 按值更新,把原值改为新值
void update_list(list *l,Type oldData,Type newData);
//删除
void delete_list(list *l,Type data);
//遍历
void traverse_list(list *l);
//回收
void free_list(list **l);#endif
顺序表的代码较多,所以使用多文件封装来写比较清晰;顺序表的存储既然是要连续的空间地址,那么我们就使用数组来存储,因为数组中的元素就是连续存储的;一个顺序表中除了数组来存储元素外,还需要一个变量来存储数组的长度,因此我定义了一个结构体来存放这两个成员,将结构体重命名为list方便后续使用。
#include "seqlist.h"
//创建
list *create_list()
{list *p = (list *)malloc(sizeof(list));if(NULL == p){perror("create malloc");return NULL;}return p;
}
//判满(满为0,不满为1,错误为-1)
int full_list(list *l)
{if(NULL == l){puts("list is NULL");return -1;}else if(LEN == l->count){puts("表已放满");return 0;}else{//puts("表未满");return 1;}
}
//判空(空为0,非空为1,错误为-1)
int null_list(list *l)
{if(NULL == l){puts("list is NULL");return -1;}return l->count==0?0:1;
}void whether_full(int a)
{if(0 == a)puts("表已满");else if(1 == a)puts("表未满");
}
//初始化
void init_list(list *l)
{if(NULL == l){puts("list is NULL");return;}l->count=0;
}
//求长度
int length_list(list *l)
{if(NULL == l){puts("list is NULL");return -1;}return l->count;// printf("index:%d\n",l->count);
}
//首插入
void head_insert_list(list *l,Type data)
{if(0 == full_list(l))return;int n = l->count;while(n){l->data[n] = l->data[n-1];n--;}l->data[0] = data;l->count++;
}
//插入(尾插)
void insert_list(list *l,Type data)
{if(0 == full_list(l))return;//if(full_list(l))//{//l->data[l->count] = data;//l->count++;//}l->data[l->count] = data;l->count++;
}
//查找 按值找,把找到值的下标返回
int search_list(list *l,Type data)
{if(NULL == l){puts("list is NULL");return -1;}for(int i=0;i<l->count;i++){//memcmp(&data,&l->data[i],sizeof(Type))==0;if(data == l->data[i])return i;}return -1;
}
//更新 按值更新,把原值改为新值
void update_list(list *l,Type oldData,Type newData)
{
#if 1if(NULL == l){puts("list is NULL");return;}for(int i=0;i<l->count;i++){if(oldData==l->data[i])l->data[i]=newData;//break;}
#elseint t;while((t=search_list(l,oldData))!=-1)l->data[t]=newData;
#endif
}
//删除
void delete_list(list *l,Type data)
{if(NULL == l){puts("list is NULL");return;}
#if 0for(int i=0;i<l->count;i++){if(data == l->data[i])for(int j=i;j<l->count-1;j++){l->data[j] = l->data[j+1]}l->count--;i--;}
#elif 1int index = 0;for(int i=0;i<l->count;i++){if(data != l->data[i]) //不是要删的值就赋值,是要删的就不赋,直到是不删的数再把它放到之前要删那个数的位置,相当于是以覆盖的形式删除{l->data[index++]=l->data[i];}}l->count = index;
#endif
}
//遍历
void traverse_list(list *l)
{if(NULL == l){puts("list is NULL");return;}for(int i=0;i<l->count;i++){OUT(l->data[i]);}puts("");
}
//回收
void free_list(list **l) //传二级指针是为了让开辟空间所用的指针指向空 传参传指针的地址
{if(NULL == l){puts("list is NULL");return;}free(*l);*l=NULL;
}
创建:list *create_list()
创建一个顺序表,在堆区开空间,并且创建完之后我们需要拿到表的首地址,因此函数的类型为list *型,创建空间的大小就是结构体的大小,结构体有多大就开多大的空间,开完空间之后我们需要做一个简单的判断,让我们知道开辟空间是否开辟成功,不成功返回NULL,成功返回首地址。
判断表是否放满:int full_list(list *l)
对于顺序表来说,因为在结构体里面我们有一个专门用来记录表中元素个数的变量,因此判断表是否放满直接判断这个变量的值是否等于表的长度LEN即可,满返回一个0,不满返回一个1。
判断表是否为空:int null_list(list *l)
判空跟判满其实差不多,也是判断记录个数的变量的值是否为0,为0就是空,不为0就是非空。
顺序表的初始化和求长度也是跟判空一样的操作,都是操作变量count,初始化就直接把count置零就可以,因为在后续插入内容的时候会将以前的内容覆盖;求长度其实就是直接将count的值当做函数返回值反出去即可。
头部插入:void head_insert_list(list *l,Type data)
对于插入函数来说,我们需要操作表因此需要传参传入表的地址,还有我们需要插入的元素,首先需要判断这个表是否放满,如果放满那就不可以继续再插入,此时直接return即可;为放满那就可以插入,因为是头部插入,因此在插入之前,我们需要给要插入的元素把第一个位置空出来,所以我们需要把表中已有的元素全部往后移动一位,通过一个循环从最后一个元素开始移动,有几个元素就移动几次,移动完之后就可以把要放入的元素放入第一个位置,之后一定不要忘记count要自增1。
尾部插入:void insert_list(list *l,Type data)
尾部插入相对于头部插入就简单得多,首先也是需要判断表满没满,没满之后直接再最后一个元素后面放入要插入的元素即可,l->data[l->count] = data;之后count自增1。
查找:int search_list(list *l,Type data)
查找传入的也是两个参数,表和要查找的值,返回值为该值的下标,通过一个循环遍历的方式来查找我们所需要的元素的下标,找到这个元素循环就结束,如果循环结束都没有找到这个数,那就返回一个-1代表表中没有这个数。
更新:void update_list(list *l,Type oldData,Type newData)
更新函数不需要返回值,传参的话就是表,原值以及需要修改的值,还是跟查找一样的使用循环的方法,找到需要修改的值就直接将这个值修改为更新后的值即可;在这里如果只想要更新查找到的第一个值的话就在循环里面加一个break即可,这样查找到第一个之后就会结束循环。
删除:void delete_list(list *l,Type data)
对于顺序表的删除,我们有两个办法,但是都需要使用到循环;第一种方法是找到要删除的值之后就将它后面的每一个元素都往前移动一位,将这个删除的值直接覆盖掉;第二种方法也是覆盖,首先定义一个变量作为赋值下标,然后判断的条件是当元素不是我要删除的那个数时,就给数组中的数赋值,l->data[index++]=l->data[i];这里的index和i都是从0开始,对于相同的值,再赋值一遍也不会产生影响,但是要是这个数是我们要删除的数,那就不进行这一个赋值操作,这时index的值就不会增加,会停留在要删除的值的前一个,但是i每次都会自增,当下一次循环时,i所对应的元素就是要删除的元素的后一个元素,这时再将这个元素赋值给index下标对应的位置,就可以将要删除的元素覆盖掉;切记一定要在删除的同时count的值也要发生改变。
遍历:void traverse_list(list *l)
顺序表的遍历其实也就是数组的遍历,通过循环遍历数组再输出即可。
回收:void free_list(list **l)
在回收的传参这里,我们只传这个表是不行的,我们需要释放这片空间地址,并且还需要将指向这片空间的指针指向空,因此必须传参传入指针的地址,也就是传一个二级指针,将这个空间free之后还需要将指针指向NULL,这样回收才算结束。
#include "seqlist.h"
int main(int argc, char *argv[])
{list *p = create_list();insert_list(p,1);insert_list(p,2);insert_list(p,3);puts("尾插入后");traverse_list(p);head_insert_list(p,4);head_insert_list(p,5);head_insert_list(p,6);puts("首插入后");traverse_list(p);printf("length=%d\n",length_list(p));whether_full(full_list(p));printf("3的下标为:%d\n",search_list(p,3));update_list(p,4,8);puts("将4更改为8后:");traverse_list(p);delete_list(p,5);puts("删除5之后:");traverse_list(p);puts("回收");free_list(&p);printf("p=%p\n",p);return 0;
}
相关文章:

数据结构(基本概念及顺序表)
基本概念: 1、引入 程序数据结构算法 数据: 数值数据:能够直接参加运算的数据(数值,字符) 非数值数据:不能够直接参加运算的数据(字符串、图片等) 数据即是信息的载…...

【全面系统性介绍】虚拟机VM中CentOS 7 安装和网络配置指南
一、CentOS 7下载源 华为源:https://mirrors.huaweicloud.com/centos/7/isos/x86_64/ 阿里云源:centos-vault-7.9.2009-isos-x86_64安装包下载_开源镜像站-阿里云 百度网盘源:https://pan.baidu.com/s/1MjFPWS2P2pIRMLA2ioDlVg?pwdfudi &…...

html + css 自适应首页布局案例
文章目录 前言一、组成二、代码1. css 样式2. body 内容3.全部整体 三、效果 前言 一个自适应的html布局 一、组成 整体居中,宽度1200px,小屏幕宽度100% 二、代码 1. css 样式 代码如下(示例): <style>* {…...

时钟之CSS+JS版
写在前面 此版本绘制的时钟基于CSSJS模式。 优点操作简单,缺点当然是不够灵活。下一篇会基于HTML5的canvas标签,使用JS绘制。会更灵活,元素更加丰富。 HTML代码 <div class"box"><article class"clock"><…...

ubuntu18.04 配置安卓编译环境
目前有个项目,验收时有个要求是在linux中进行编译打包生成apk文件。我平时都是在windows环境android studio中进行打包的,花了半天时间研究了一下,记录如下: 安装安卓sdk cd /opt wget https://dl.google.com/android/reposito…...

pycharm分支提交操作
一、Pycharm拉取Git远程仓库代码 1、点击VCS > Get from Version Control 2、输入git的url,选择自己的项目路径 3、点击Clone,就拉取成功了 默认签出分支为main 选择develop签出即可进行开发工作 二、创建分支(非必要可以不使用…...

ESP32-C3 开发笔记 之 arduino 正常上传 串口乱码2024/11/15
ESP32-C3 开发笔记 之 arduino 正常上传 串口乱码 ESP32-C3 开发笔记 之 arduino 正常上传程序 但是打开串口,串口快速刷新 芯片一直处于重启状态 找了很久的原因没找到,用Mixly 上传就正常 最后看到这篇 文章https://blog.csdn.net/luooove/article/details/132351398修改了Fl…...

Ubuntu 的 ROS 操作系统 turtlebot3 SLAM仿真
引言 SLAM(同步定位与地图构建)在Gazebo仿真环境中的应用能够模拟真实机器人进行环境建图和导航。通过SLAM仿真,开发者可以在虚拟环境中测试算法,而不必依赖真实硬件,便于调试与优化。 Gazebo提供了多个虚拟环境&…...

2024年11月15日
1.计算机网络 逻辑右移 做加减法 定点乘法 原码乘法运算 一位乘 计组 2.英语六级...

websocket初始化
websocket初始化 前言 上一集我们HTTP的ping操作就可以跑通了,那么我们还有一个协议---websocket,我们在这一集就要去完成我们websocket的初始化。 分析 我们在初始化websocket的之前,我们考虑一下,我们什么时候就要初始化我们…...

uniapp ios app以framwork形式接入sentry
一、下载Sentry mac终端输入:vim Podfile修改Podfile: platform :ios, 11.0 target YourApp douse_frameworks! # This is importantpod Sentry, :git > https://github.com/getsentry/sentry-cocoa.git, :tag > 8.40.1 end执行:pod install下载…...

⾃动化运维利器Ansible-基础
Ansible基础 一、工作原理二、快速入门2.1 测试所有资产的网络连通性2.2 发布文件到被管理节点(资产) 三、资产(被管理节点)3.1 静态资产3.1.1 自定义资产3.1.2 自定义资产的使用3.1.3 资产选择器 四、Ansible Ad-Hoc 命令4.1 模块类型4.1.1 command & shell 模块4.1.2 cop…...

若依笔记(十一):芋道多租户限制与修改
目录 多租户实现 哪些表是多租户的? YudaoTenant自动装载类 租户隔离的sql在哪? 如何修改成无租户隔离 全局修改 表级别 请求RUL级别 芋道比若依多了租户概念,这也是因为它增加很多业务系统,首先后台管理系统肯定是多租户的,这意味着如商城系统的产品管理SPU、库存…...

hive 统计各项目下排名前5的问题种类
实现指定某项目下的数据效果图如下所示: 其中 ABCDE 为前5名的问题种类,其中A问题有124个(出现了124次) 数据说明: 整个数据集 包含很多项目一个项目 包含很多问题一个问题 选项 可认为是 类别值,所有出…...

HBase 安装与基本操作指南
以下是关于 Apache HBase 安装、配置以及简单操作的详细指南: HBase 简介 Apache HBase 是一个基于 Hadoop 的分布式数据库,擅长处理大规模、结构化的海量数据。它采用行列式存储方式,与 Hadoop 和 HDFS 紧密结合,是支持大数据实…...

Spring Boot应用中的文件压缩与解压技术实践
在构建Spring Boot应用时,文件压缩与解压是处理大量数据、优化存储和传输速度的常用技术。本文旨在深入探讨Spring Boot应用中文件压缩与解压的实现方法,包括常见压缩算法的选择、Spring Boot中的实现策略以及实际应用场景中的最佳实践。 引言 随着大数…...

D69【 python 接口自动化学习】- python 基础之数据库
day69 Python 执行 SQL 语句 学习日期:20241115 学习目标: MySQL 数据库﹣- Python连接redis 学习笔记: redis数据库的用途 使用Python访问redis数据库 使用Python对redis数据库进行读写操作 总结 1. redis是一款高性能的键…...

410. 分割数组的最大值
目录 题目解法 题目 给定一个非负整数数组 nums 和一个整数 k ,你需要将这个数组分成 k 个非空的连续子数组,使得这 k 个子数组各自和的最大值 最小。 返回分割后最小的和的最大值。 子数组 是数组中连续的部份。 解法 int splitArray(vector<in…...

Azure pipeline 通过git命令修改文件
步骤及解释 设置git用户名 git config --global user.email "useremail" git config --global user.name "username" 获取branch $branch "$(Build.SourceBranch)" -replace "refs/heads/" "$(Build.SourceBranch)"&a…...

LeetCode74. 搜索二维矩阵(2024冬季每日一题 6)
给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。…...

BPMN 2.0详细介绍
BPMN 2.0(Business Process Model and Notation 2.0)是一个标准化的图形化建模语言,用于描述业务流程和工作流。它是由 Object Management Group (OMG) 制定的,旨在提供一种标准化的方式,帮助企业和开发者清晰地建模、…...

web——upload-labs——第四关——.htaccess文件绕过
先尝试直接上传一个普通的一句话木马 显示此文件不允许上传,这道题并没有提示不允许上传什么后缀的文件,经过尝试,基本上所有后缀能够被解析为php语句执行的文件都不能成功上传。试试正常的图片能不能上传: 我们再来试试图片马能不…...

36.矩阵格式的等差数列 C语言
第一行,每个数差2,之后是3、4、5,最后一行是10 仅仅是练习目的 #define _CRT_SECURE_NO_WARNINGS // 禁用在 Visual Studio 中有关不安全函数的警告 #include <stdio.h> // 引入标准输入输出库int main() {int i; // 外层循环的变量…...

Java 语言的强大特性
一、面向对象 面向对象编程(OOP)是一种编程范式,Java 完全遵循这一范式,并具备封装、继承和多态三大核心特性。 1. 封装 封装是将数据和操作封装在类中,通过访问修饰符(如 public、private、protected&am…...

ElementUI的日期组件中禁止选择小时、分钟、秒
分不同版本,如果你是elementplus,也就是vue3版本,你就直接可用方案1;如果你是vue2版本(扒拉了一下源码,组间不支持),方案2、3都行,具体看自己需求。 1、使用:disable-…...

4.2 Android NDK 基础概念
1 JavaVM和JNIEnv JNI 定义了两个关键数据结构,JavaVM和JNIEnv。这两者本质上都是指向函数表指针的指针。(在 C 版本中,它们是具有指向函数表的指针的类,以及指向该表的每个 JNI 函数的成员函数。)JavaVM提供了“调用接…...

PIL包在Python图像处理中的应用
诸神缄默不语-个人CSDN博文目录 PIL(Python Imaging Library)是Python中一个强大的图像处理库,尽管其已不再更新,但其后续版本Pillow提供了更多的功能和更好的兼容性。本文将重点介绍Pillow库中的open()函数、fromarray()函数以及…...

ArcGIS Pro ADCore DAML
ArcGIS Pro ADCore DAML ArcGIS Pro SDK - ADCore.daml https://download.csdn.net/download/szy13323042191/89997391...

Clip结合Faiss+Flask简易版文搜图服务
一、实现 使用目录结构: templates ---upload.html faiss_app.py 前端代码:upload.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content&quo…...

【机器学习】数学知识:欧式距离(Euclidean Distance)和曼哈顿距离(Manhattan Distance)
欧式距离和曼哈顿距离是两种常用的距离度量方法,用于衡量两点之间的相似性或差异性。它们在几何分析、数据挖掘、机器学习等领域有广泛应用。 1. 欧式距离 概念 欧式距离(Euclidean Distance)是最常见的直线距离度量方法,源于欧…...