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

数据结构-->线性表-->顺序表

对我个人来说,C语言基础相关的知识基本学完了,随后就该学数据结构了,希望以后自己复习能够用上今天自己写的哈哈。

如果你不理解什么是物理结构和逻辑结构,这里附上一个链接:逻辑结构和物理结构:逻辑结构与物理结构_逻辑结构和物理结构-CSDN博客

 

看见我的备注了吗,一位不帅的帅哥。

数据结构的相关介绍

我们将数据结构拆分为两个词来理解
数据就是存储的信息,结构是组织数据的方式。
官方定义的数据结构的概念为:数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。数据结构反应数据的内部构成,即数据有哪部分构成,以什么方式构成,以及数据元素之间呈现的结构。
总结:

(1)能够存储数据(顺序表,链表等结构)
(2)存储的数据能够方便查找

数组是最基础的数据结构,我们除了数组还要学习更多数据结构的原因是:最基础的数据结构能够提供的操作已经不能完全满足复杂算法实现。

对数据结构中线性表的认识

线性表:

线性表是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列

线性表在逻辑上是线性结构,也就是说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常是以数组和链式结构的形式存储。

从顺序表开始启航

顺序表和数组的区别:顺序表的底层结构是数组,对数组的封装,实现了常用的增删查改等接口。

顺序表分为静态顺序表和动态顺序表。

对静态顺序表来说:空间给少了不够用,给多了造成空间浪费。

也就是说老年机的通讯录就是静态顺序表。

这里附上老年机,商标就打码了,怕吃官司。

 因此我们就写动态版本的顺序表了

对学校数据结构方面的忠告

 好的,其实到这里呢,我就去手搓动态顺序表了,哈哈,幸运的是我完全写出来了,没看别人的,老师说过数据结构这块呢,就是要熟悉,重要的是代码,其实我觉得呢也没有别的办法,多写才是解药。

顺序表头文件

代码的头文件

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDataType;
typedef struct SeqList
{SLDataType* a;int size;int capacity;
}SL;//初始化
void SLInit(SL* ps);
//销毁
void SLDestroy(SL* ps);
//打印
void SLPrint(SL* ps);
//扩容
void SLCheck(SL* ps);
//尾插
void SLPushBack(SL* ps, SLDataType x);
//尾删
void SLPopBack(SL* ps);
//头插
void SLPushFront(SL* ps, SLDataType x);
//头删
void SLPopFront(SL* ps);
//查找
int FindData(SL* ps, SLDataType x);
//指定位置插入
void InsertPush(SL* ps, int pos, SLDataType x);
//指定位置删除
void ErasePop(SL* ps, int pos);

初始化

这里没什么难度,就直接写就ok

//初始化
void SLInit(SL* ps)
{ps->a = NULL;ps->capacity = ps->size = 0;
}

 销毁

程序结束记得销毁,否则会发生内存泄漏,切记、切记、切记。

//销毁
void SLDestroy(SL* ps)
{free(ps->a);ps->a = NULL;ps->capacity = ps->size = 0;
}

打印

对于打印,其实就直接遍历就ok

//打印
void SLPrint(SL* ps)
{int i = 0;for (i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}
}

扩容

这里的扩容,顾名思义就是扩大空间,他的作用是为了提供足够的空间

//扩容
void SLCheck(SL* ps)
{if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLDataType* new = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));if (new == NULL){perror("REALL0C FAIL");return;}ps->a = new;ps->capacity = newcapacity;}
}

尾插

尾插我们先检查我们的空间大小够不够,对于需要插入的接口来说,我们都要检查空间是否足够,

只要空间足够,就直接插入就ok了。

//尾插
void SLPushBack(SL* ps,SLDataType x)
{assert(ps);SLCheck(ps);ps->a[ps->size++] = x;
}

尾删 

直接把size减去1就ok

//尾删
void SLPopBack(SL* ps)
{assert(ps);assert(ps->size);ps->size--;
}

头插

头插就是要把原来的数据往后挪动,但是不能从前往后挪动,因为这样会覆盖之后还没挪动的数据,因此我们需要把数据从后往前开始往后挪动 

//头插
void SLPushFront(SL* ps, SLDataType x)
{assert(ps);SLCheck(ps);for (int i = ps->size; i > 0; i--){ps->a[i] = ps->a[i - 1];}ps->a[0] = x;ps->size++;
}

头删

头删跟头插正好相反,额这算不算相当于没说

就是把数据从前往后开始往前面移动 

//头删
void SLPopFront(SL* ps)
{assert(ps);for (int i = 1; i < ps->size; i++){ps->a[i-1] = ps->a[i];}ps->size--;
}

 查找

查找就是遍历再加一层比较,值相等就返回下标

//查找
int FindData(SL* ps, SLDataType x)
{assert(ps);for (int i = 0; i < ps->size; i++){if (ps->a[i] == x){return i;}}return -1;
}

指定位置插入

其实就是类似头插,注意for循环范围别搞错了,如果你怕搞错,这里提供一种方法,就是你只比较带入for循环的最大和最小情况,如果成立,那就是正确的。

//指定位置插入
void InsertPush(SL* ps, int pos, SLDataType x)
{assert(ps);assert(ps->size);assert(pos >= 0 && pos <= ps->size);for (int i = ps->size; i > pos; i--){ps->a[i] = ps->a[i - 1];}ps->a[pos] = x;ps->size++;
}

指定位置删除

 类似头删

//指定位置删除
void ErasePop(SL* ps, int pos)
{assert(ps);assert(ps->size);assert(pos >= 0 && pos < ps->size);for (int i = pos + 1; i < ps->size; i++){ps->a[i - 1] = ps->a[i];}ps->size--;
}

最后附上最终代码 

总代码

SeqList.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDataType;
typedef struct SeqList
{SLDataType* a;int size;int capacity;
}SL;//初始化
void SLInit(SL* ps);
//销毁
void SLDestroy(SL* ps);
//打印
void SLPrint(SL* ps);
//扩容
void SLCheck(SL* ps);
//尾插
void SLPushBack(SL* ps, SLDataType x);
//尾删
void SLPopBack(SL* ps);
//头插
void SLPushFront(SL* ps, SLDataType x);
//头删
void SLPopFront(SL* ps);
//查找
int FindData(SL* ps, SLDataType x);
//指定位置插入
void InsertPush(SL* ps, int pos, SLDataType x);
//指定位置删除
void ErasePop(SL* ps, int pos);

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
//初始化
void SLInit(SL* ps)
{ps->a = NULL;ps->capacity = ps->size = 0;
}
//销毁
void SLDestroy(SL* ps)
{free(ps->a);ps->a = NULL;ps->capacity = ps->size = 0;
}
//打印
void SLPrint(SL* ps)
{int i = 0;for (i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}
}
//扩容
void SLCheck(SL* ps)
{if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLDataType* new = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));if (new == NULL){perror("REALL0C FAIL");return;}ps->a = new;ps->capacity = newcapacity;}
}
//尾插
void SLPushBack(SL* ps,SLDataType x)
{assert(ps);SLCheck(ps);ps->a[ps->size++] = x;
}
//尾删
void SLPopBack(SL* ps)
{assert(ps);assert(ps->size);ps->size--;
}
//头插
void SLPushFront(SL* ps, SLDataType x)
{assert(ps);SLCheck(ps);for (int i = ps->size; i > 0; i--){ps->a[i] = ps->a[i - 1];}ps->a[0] = x;ps->size++;
}
//头删
void SLPopFront(SL* ps)
{assert(ps);for (int i = 1; i < ps->size; i++){ps->a[i-1] = ps->a[i];}ps->size--;
}
//查找
int FindData(SL* ps, SLDataType x)
{assert(ps);for (int i = 0; i < ps->size; i++){if (ps->a[i] == x){return i;}}return -1;
}
//指定位置插入
void InsertPush(SL* ps, int pos, SLDataType x)
{assert(ps);assert(ps->size);assert(pos >= 0 && pos <= ps->size);for (int i = ps->size; i > pos; i--){ps->a[i] = ps->a[i - 1];}ps->a[pos] = x;ps->size++;
}
//指定位置删除
void ErasePop(SL* ps, int pos)
{assert(ps);assert(ps->size);assert(pos >= 0 && pos < ps->size);for (int i = pos + 1; i < ps->size; i++){ps->a[i - 1] = ps->a[i];}ps->size--;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
int main()
{SL s;SLInit(&s);SLPushBack(&s, 1);SLPushBack(&s, 2);//1 2SLPrint(&s);printf("\n");SLPopBack(&s);//1SLPrint(&s);printf("\n");SLPushFront(&s,2);//2 1SLPrint(&s);printf("\n");SLPopFront(&s);//1SLPrint(&s);SLDestroy(&s);return 0;
}

 运行test函数,测试各接口是否正确

运行一下test函数,检查一下

相关文章:

  • Tkinter教程21:Listbox列表框+OptionMenu选项菜单+Combobox下拉列表框控件的使用+绑定事件
  • 类与对象(终章)——友元,内部类,匿名对象
  • 【Unity3D小技巧】Unity3D中UI控制解决方案
  • 私有化部署一个吃豆人小游戏
  • powershell 接收一个端口tcp数据复制转发到多个目的
  • [linux c]linux do_div() 函数用法
  • 《数电》理论笔记-第1章-逻辑代数基础
  • 数据结构--基础知识
  • 2019年江苏省职教高考计算机技能考试——一道程序改错题的分析
  • Spring是怎么解决循环依赖的
  • U盘显示空间小于实际U盘空间的解决方案
  • chisel之scala 语法
  • pip安装tf-gpu=2.4的bug解决方案
  • Vue代理模式和Nginx反向代理(Vue代理部署不生效)
  • 第3节、电机定速转动【51单片机+L298N步进电机系列教程】
  • 时间复杂度分析经典问题——最大子序列和
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • input的行数自动增减
  • java小心机(3)| 浅析finalize()
  • orm2 中文文档 3.1 模型属性
  • swift基础之_对象 实例方法 对象方法。
  • use Google search engine
  • Vim 折腾记
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 订阅Forge Viewer所有的事件
  • 讲清楚之javascript作用域
  • 浏览器缓存机制分析
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 在Unity中实现一个简单的消息管理器
  • 阿里云服务器购买完整流程
  • ​MySQL主从复制一致性检测
  • #NOIP 2014#Day.2 T3 解方程
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (39)STM32——FLASH闪存
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (全注解开发)学习Spring-MVC的第三天
  • (三) diretfbrc详解
  • (转)Linux NTP配置详解 (Network Time Protocol)
  • (转)mysql使用Navicat 导出和导入数据库
  • (转)负载均衡,回话保持,cookie
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .gitignore文件_Git:.gitignore
  • .NET C#版本和.NET版本以及VS版本的对应关系
  • .NET CF命令行调试器MDbg入门(三) 进程控制
  • .NET Compact Framework 3.5 支持 WCF 的子集
  • .NET CORE使用Redis分布式锁续命(续期)问题
  • .NET Core中Emit的使用
  • .NetCore Flurl.Http 升级到4.0后 https 无法建立SSL连接
  • .Net程序猿乐Android发展---(10)框架布局FrameLayout
  • .NET框架