当前位置: 首页 > news >正文

数据结构(一)顺序表

目录

  • 一、概念
    • (一)数据结构的三元素
      • 1. 逻辑结构
        • (1)线性结构
        • (2)非线性结构
      • 2. 存储结构
        • (1)顺序存储
        • (2)链式存储
        • (3)索引存储
      • 3. 运算
    • (二)时间复杂度
      • 1. 线性阶
      • 2. 常数阶
      • 3. 平方阶
      • 4. 三次方阶
      • 5. 对数阶
      • 6. 时间复杂度排序
  • 二、顺序表
    • (一)逻辑结构
    • (二)存储结构
    • (三)操作
      • 1. 创建顺序表
        • (1)返回值是创建的顺序表
        • (2)参数传入想要创建的顺序表
          • ① 函数声明
          • ② 注意点:
          • ③代码实现
      • 2. 插入元素(尾插、任意位置插入)
        • (1)尾插
          • ① 函数声明
          • ② 注意点:
          • ③代码实现
        • (2)任意位置插入
          • ① 函数声明
          • ② 注意点:
          • ③代码实现
      • 3. 删除元素(尾删、任意位置删除)
        • (1)尾删
          • ① 函数声明
          • ② 注意点:
          • ③代码实现
        • (2)任意位置删除
          • ① 函数声明
          • ② 注意点:
          • ③代码实现
      • 4. 修改指定位置
          • ① 函数声明
          • ② 注意点:
          • ③代码实现
      • 5. 查找指定位置
          • ① 函数声明
          • ② 注意点:
          • ③代码实现
      • 6. 清空顺序表
          • ① 函数声明
          • ② 注意点:
          • ③代码实现
      • 7. 销毁顺序表
          • ① 函数声明
          • ② 注意点:
          • ③代码实现
      • 8. 排序
          • ① 函数声明
          • ② 注意点:
          • ③代码实现
      • 9. 翻转
          • ① 函数声明
          • ② 注意点:
          • ③代码实现
      • 10. 剔重
          • ① 函数声明
          • ② 注意点:
          • ③代码实现
      • 11. 打印所有元素
          • ① 函数声明
          • ② 注意点:
          • ③代码实现
    • (四)使用C语言实现的顺序表的源代码已上传资源

一、概念

可以更合理使用内存
提高程序的执行效率

C语言本质是操作内存

数据对象、数据元素、数据项
图片

(一)数据结构的三元素

1. 逻辑结构

(1)线性结构

一对一的关系
数据连续

(2)非线性结构

树型:
一对多

图:
多对多

2. 存储结构

数据在计算机尤其是内存中的存储方式

(1)顺序存储
(2)链式存储
(3)索引存储

3. 运算

算法:有限步骤内解决问题的方法
算法不依赖于编程语言
特点:

  1. 有穷性
  2. 确定性
  3. 可行性
  4. 有0个或多个输入,有一个或多个输出

标准:

  1. 正确性
  2. 易读性
  3. 健壮性:对非法数据的处理能力
  4. 高效性
  5. 低存储

(二)时间复杂度

算法的时间复杂度定义为算法中可执行语句的频度之和 记作 T(n)
语句频度是指同一代码执行的次数
T(n)是算法所需时间的一种估值,n 表示问题的规模

算法的时间复杂度的表示方式为:
O(频度); ----------称为 大 O 表示法

假设有三段代码:
a 的时间复杂度为 2
b 的时间复杂度为 2n
c 的时间复杂度为2n^2
如果a、b、c组成一段程序,
那么算法的时间复杂度为
T(n) =T (2+2n+2n^2)
业内表示方法 还需T (2+2n+2n^2)要对进行简化

使用大O表示法的简化流程:
1.去掉运行时间中的所有常数项。
(例如 2+2n+2n^2,直接变为 2n+2n^2)
2.保留最高次幂项。
(2n^2+2n 变成 2n^2)
3.最高项存在但是系数不是1,则把系数置为1。
(2n^2 系数为2 去掉系数 n^2 )

所以,最终a、b和c合并而成的代码的时间复杂度为O(n^2)。

1. 线性阶

O(n)

2. 常数阶

O(1)

3. 平方阶

O(n^2)

4. 三次方阶

O(n^3)

5. 对数阶

O(logn)

6. 时间复杂度排序

O(1)< O(logn) < O(n) < O(nlogn) < O(n^2) <O(n^3) <O(2^n) <O(n!) < O(n^n)

可以带一个数测试,如问题规模n是16
1 < 4 < 16 < 64 < 256 < 4096 < 65536 < 16! < 16^16

二、顺序表

(一)逻辑结构

线性结构

(二)存储结构

顺序存储
内存中连续的空间

(三)操作

  • 目的:封装成函数,供他人使用
  • 结构体定义:
//节点结构体定义
typedef struct node
{int data; //此处以int为例,可自行添加其他成员
}Nd_t;
//列表结构体定义
typedef struct list
{int count; //记录当前存入了多少个值Nd_t listArr[MAX_SIZE]; 
}Ls_t;

1. 创建顺序表

(1)返回值是创建的顺序表

list_t *create_list_1();

(2)参数传入想要创建的顺序表
① 函数声明

int create_list(Ls_t **list);

② 注意点:
  1. 参数必须传入二级指针(需要改变main函数中的指针的值)
  2. 首先需要判定传入函数的指针是否为一个空指针(因为接下来第一件事是要使用*list来接malloc的返回值,如果传入的是一个空指针,会报段错误,所以需要提前检查)
  3. 需要判定申请空间是否成功(申请失败会返回NULL)
③代码实现
//创建顺序表并初始化
int create_list(Ls_t **list)
{if(NULL==list)//判定传入的指针是否是一个空指针{printf("申请空间失败\n");return -1;}//申请内存空间*list=(Ls_t *)malloc(sizeof(Ls_t));if(NULL==*list)//申请空间失败{printf("申请空间失败\n");return -1;}//初始化(*list)->count=0; memset(*list,0,sizeof(Ls_t));return 0;
}
  • 补充:memset函数
#include <string.h>
void *memset(void *s, int c, size_t n);
//s 要置值的内存首地址
//c 用于置值的值
//n 置值的大小

2. 插入元素(尾插、任意位置插入)

(1)尾插
① 函数声明

int insert_list_by_tail(Ls_t *list,int num);

② 注意点:
  1. 需要判定传入的顺序表指针是否是空指针
  2. 需要判定顺序表是否已满
  3. 插入成功后,count++
③代码实现
//在尾部插入数据
int insert_list_by_tail(Ls_t *list,int num)
{if(NULL == list) {printf("操作的表不存在\n");return -1;}if(MAX_SIZE == list->count){printf("顺序表已满\n");return -1;}//插入数据list->listArr[list->count].data=num;//顺序表存入数据的数量+1list->count++;return 0;
}
(2)任意位置插入
① 函数声明

int insert_list(Ls_t *list,int pos,int num);

② 注意点:
  1. 需要判定传入的顺序表指针是否是空指针
  2. 需要判定顺序表是否已满
  3. 判定插入位置是否合法,需要大于零,且需要保证顺序表内存空间连续
  4. 插入成功后,count++
③代码实现
int insert_list(Ls_t *list,int pos,int num)
{if(NULL == list) {printf("操作的表不存在\n");return -1;}if(MAX_SIZE == list->count){printf("顺序表已满\n");return -1;}if(pos < 0 || pos > list->count){printf("插入位置违法\n");return -1;}//从后往前,依次向后移动一位,直到到达插入位置int i=list->count;while(i!=pos){list->listArr[i]=list->listArr[i-1];i--;}//插入数据list->listArr[pos].data=num;//顺序表存入数据的数量+1list->count++;return 0;
}

3. 删除元素(尾删、任意位置删除)

(1)尾删
① 函数声明

int delete_list_by_tail(Ls_t *list);

② 注意点:
  1. 需要判定传入的顺序表指针是否是空指针
  2. 需要判定顺序表是否已满
  3. 直接count–即可,不必去清空值,此时原来的位置相当于已经声明可以继续写入数据
③代码实现
int delete_list_by_tail(Ls_t *list)
{if(NULL == list) {printf("操作的表不存在\n");return -1;}if(0==list->count){printf("顺序表为空\n");return -1;}list->count--;return 0;
}
(2)任意位置删除
① 函数声明

int delete_list(Ls_t *list,int pos);

② 注意点:
  1. 需要判定列表指针是否是空指针
  2. 判断表是否为空
  3. 判定删除位置是否合法,需要大于零,且小于顺序表当前容纳值的数量;
  4. 删除成功后,count需要减一
③代码实现
int delete_list(Ls_t *list,int pos)
{if(NULL == list) {printf("操作的表不存在\n");return -1;}if(0==list->count){printf("顺序表为空\n");return -1;}if(pos<0||pos>=list->count){printf("删除位置违法\n");return -1;}for(int i=pos;i<list->count;i++){list->listArr[i]=list->listArr[i+1];}list->count--;return 0;
}

4. 修改指定位置

① 函数声明

int modify_list(Ls_t *list,int pos,int num);

② 注意点:
  1. 需要判定列表指针是否是空指针
  2. 判断表是否为空
  3. 判定修改位置是否合法,需要大于零,且小于顺序表当前容纳值的数量;
③代码实现
int modify_list(Ls_t *list,int pos,int num)
{if(NULL == list) {printf("操作的表不存在\n");return -1;}if(0==list->count){printf("顺序表为空\n");return -1;}if(pos<0||pos>=list->count){printf("修改位置违法\n");return -1;}list->listArr[pos].data=num;return 0;
}

5. 查找指定位置

① 函数声明

int search_list(Ls_t *list,int pos,int *num);

② 注意点:
  1. 需要判定列表指针是否是空指针
  2. 判定查询位置是否合法,需要大于零,且小于顺序表当前容纳值的数量;
③代码实现
int search_list(Ls_t *list,int pos,int *num)
{if(NULL == list) {printf("操作的表不存在\n");return -1;}if(0==list->count){printf("顺序表为空\n");return -1;}if(pos<0||pos>=list->count){printf("查询位置违法\n");return -1;}*num=list->listArr[pos].data;return 0;
}

6. 清空顺序表

① 函数声明

int clean_list(Ls_t *list);

② 注意点:
  1. 需要判定列表指针是否是空指针
  2. 只需将count置0即可,各函数都是根据count来进行操作,因此即使原来顺序表的值并未清空也不影响
③代码实现
int clean_list(Ls_t *list)
{if(NULL == list) {printf("操作的表不存在\n");return -1;}list->count=0;return 0;
}

7. 销毁顺序表

① 函数声明

int destroy_list(Ls_t **list);

② 注意点:
  1. 需要先确保传入的指针并非空指针,再去判断*list是否为空
  2. 释放完堆区的空间后,再将main函数中的指针置为NULL
③代码实现
int destroy_list(Ls_t **list)
{if(NULL == list) {printf("操作的指针不存在\n");return -1;}if(NULL == *list) {printf("操作的表不存在\n");return -1;}free(*list);*list=NULL;return 0;
}

8. 排序

① 函数声明

int sort_list(Ls_t *list,int s);

② 注意点:
  1. 先确保传入的指针并非空指针
  2. 判断表是否为空
  3. 第二个参数为0是正序排序,否则倒序排序
③代码实现
int sort_list(Ls_t *list,int s)
{if(NULL == list) {printf("操作的表不存在\n");return -1;}if(0==list->count){printf("顺序表为空\n");return -1;}int flag=0;for(int i=0;i<list->count-1;i++){flag=0;for(int j=0;j<list->count-1-i;j++){if(0==s){ //正序排序if(list->listArr[j].data>list->listArr[j+1].data){Nd_t temp=list->listArr[j];list->listArr[j]=list->listArr[j+1];list->listArr[j+1]=temp;flag=1;}}else{if(list->listArr[j].data<list->listArr[j+1].data){Nd_t temp=list->listArr[j];list->listArr[j]=list->listArr[j+1];list->listArr[j+1]=temp;flag=1;}}}if(0==flag) break;}return 0;
}

9. 翻转

① 函数声明

int overturn_list(Ls_t *list);

② 注意点:
  1. 先确保传入的指针并非空指针
  2. 判断表是否为空
③代码实现
int overturn_list(Ls_t *list){if(NULL == list) {printf("操作的表不存在\n");return -1;}if(0==list->count){printf("顺序表为空\n");return -1;}int i=0,j=list->count-1;Nd_t temp;while(i<j){temp=list->listArr[i];list->listArr[i]=list->listArr[j];list->listArr[j]=temp;i++;j--;}printf("翻转完成\n");return 0;
}

10. 剔重

① 函数声明

int dedup_list(Ls_t *list);

② 注意点:
  1. 先确保传入的指针并非空指针
  2. 判断表是否为空
  3. 两侧遍历,第一层是从第一个元素遍历到倒数第二个元素(j=i+1);第二层是从第i+1个开始遍历,然后比较与当前第i个元素是否相等,相等就删除第j个元素,后面的元素依次向前移动一个位置,此时j无需再自加1
③代码实现
int dedup_list(Ls_t *list)
{if(NULL == list) {printf("操作的表不存在\n");return -1;}if(0==list->count){printf("顺序表为空\n");return -1;}int i,j;for(i=0;i<list->count-1;i++){for(j=i+1;j<list->count;j){if(list->listArr[j].data==list->listArr[i].data){for(int k=j;k<list->count-1;k++){list->listArr[k]=list->listArr[k+1];}list->count--;}else{j++;}}}return 0;
}

11. 打印所有元素

① 函数声明

int show_list(Ls_t *list);

② 注意点:
  1. 需要判定列表指针是否是空指针
③代码实现
int show_list(Ls_t *list)
{if(NULL == list) {printf("操作的表不存在\n");return -1;}for(int i=0;i<list->count;i++){printf("%d ",list->listArr[i].data);}putchar(10);return 0;
}

(四)使用C语言实现的顺序表的源代码已上传资源

相关文章:

  • HTML-JavaWeb
  • 一致性hash算法原理图和负载均衡原理-urlhash与least_conn案例
  • 开源博客项目Blog .NET Core源码学习(27:App.Hosting项目结构分析-15)
  • 宝塔PHP环境安装配置Xdebug
  • Golang实现根据文件后缀删除文件和递归删除文件
  • spring session+redis存储session,实现用户登录功能,并在拦截器里面判断用户session是否过期,过期就跳转到登录页面
  • HarmonyOS interface router scale pageTransition SlideEffect.Left ArkTS ArkUI
  • python -【五】数据容器
  • [双指针] --- 快乐数 盛最多水的容器
  • react记录部署
  • 信息学奥赛初赛天天练-15-阅读程序-深入解析二进制原码、反码、补码,位运算技巧,以及lowbit的神奇应用
  • c++编程(15)——list的模拟实现
  • Spring:IoC容器(基于XML管理bean)
  • J.搬砖【蓝桥杯】/01背包+贪心
  • Redis 常用基本命令
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • css选择器
  • Java多线程(4):使用线程池执行定时任务
  • js ES6 求数组的交集,并集,还有差集
  • Linux各目录及每个目录的详细介绍
  • Spring声明式事务管理之一:五大属性分析
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 对话 CTO〡听神策数据 CTO 曹犟描绘数据分析行业的无限可能
  • 分享一份非常强势的Android面试题
  • 工作中总结前端开发流程--vue项目
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 聊一聊前端的监控
  • 用element的upload组件实现多图片上传和压缩
  • 用Visual Studio开发以太坊智能合约
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • Nginx实现动静分离
  • 阿里云重庆大学大数据训练营落地分享
  • 正则表达式-基础知识Review
  • ​​​【收录 Hello 算法】10.4 哈希优化策略
  • ​TypeScript都不会用,也敢说会前端?
  • # SpringBoot 如何让指定的Bean先加载
  • #1014 : Trie树
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (javascript)再说document.body.scrollTop的使用问题
  • (搬运以学习)flask 上下文的实现
  • (二)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (附源码)spring boot网络空间安全实验教学示范中心网站 毕业设计 111454
  • (附源码)计算机毕业设计ssm电影分享网站
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (十八)SpringBoot之发送QQ邮件
  • (四)【Jmeter】 JMeter的界面布局与组件概述
  • (原創) 是否该学PetShop将Model和BLL分开? (.NET) (N-Tier) (PetShop) (OO)
  • (转)AS3正则:元子符,元序列,标志,数量表达符
  • .360、.halo勒索病毒的最新威胁:如何恢复您的数据?
  • .gitignore文件—git忽略文件
  • .NET 8 中引入新的 IHostedLifecycleService 接口 实现定时任务
  • .NET HttpWebRequest、WebClient、HttpClient
  • .NET Standard 的管理策略
  • .Net 垃圾回收机制原理(二)
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)...