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

手撕顺序表

> 作者简介:დ旧言~,目前大一,现在学习Java,c,c++,Python等
> 座右铭:松树千年终是朽,槿花一日自为荣。
> 望小伙伴们点赞👍收藏✨加关注哟💕💕       

 🌟前言       

        梦回数组,当我们开辟了一个数组,数组的大小就已经确定了,不能括容,也不能减容,为了解决这个问题,在数据结构有一个这样的知识--《顺序表》。顺序表连续开辟一个空间,能括容,也能减容,今天我们手撕顺序表。

🌙主体

咱们从三个方面实现顺序表,动态管理,头插头删尾插尾删,增删查改。

在程序中为了实现顺序表,需要创建头文件SeqList.h ,创建源文件test.c,SeqList.c。

 🌠动态管理

💤初始化动态顺序表

  1. 首先定义一个结构体(在源文件中),结构体里面有可变数组(a),数组初始长度(size),初始空间(capacity)。
  2. 初始化动态顺序表(SeqList.h中),需要开辟空间,再判断空间是否为空,再初始化数组长度,空间。
//动态顺序表
typedef int SLDataType;
typedef struct SeqList
{//定义一个可变数组SLDataType* a;//定义数组初始长度int size;//定义空间大小int capacity;
}SL;//初始化动态顺序表
void SLInit(SL* ps)
{//开辟空间ps->a = (SLDataType*)malloc(sizeof(SLDataType*) * 4);//判断空间是否为空if (ps->a == NULL){perror("malloc failed");exit(-1);}//初始化ps->size = 0;ps->capacity = 4;
}

1.防止一直创建结构体,为了一劳永逸,我们把动态顺序表放在源文件中。

2.这里我们用typedef int SLDataType,给数据类型重定义名字,这样就可以防止修改数据类型。

💤扩容顺序表空间

数组初始长度(size),初始空间(capacity)相同时,这里们就需要扩容,这里我们扩容两倍。(在头文件中SeqList.h中)

//扩容空间
void SLCheckCapacity(SL* ps)
{//如果size和capacity相同if (ps->size == ps->capacity){//扩大两倍SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDataType));//判断tmp是否为空if (tmp == NULL){perror("realloc failed");exit(-1);}//赋值ps->a = tmp;ps->capacity = ps->capacity * 2;}
}

💤释放顺序表内存

可变数组(a)置为(NULL),数组长度(size)置为(0),初始空间(capacity)置为(0)。

//释放内存
void SLDestroy(SL* ps)
{//断言assert(ps);free(ps->a);ps->a = NULL;ps->size = 0;ps->capacity = 0;
}

 🌠头插头删尾插尾删

💤添加元素

首先需要断言防止顺序表为空。这里需要注意空间是否满了。这里的实现和在pos位置插入x有类似,等我们实现这个函数,就可以直接调用这个函数,更加简便。(在头文件中SeqList.h中)

//添加元素
void SLPushBack(SL* ps, SLDataType x)
{//断言assert(ps);//判断空间是否满了,需要调用函数SLCheckCapacity(ps);//添加元素ps->a[ps->size] = x;ps->size++;//在pos位置插入x//SLInsert(ps, ps->size, x);
}

💤打印元素

打印元素太简单啦,直接用for循环就行。(在头文件中SeqList.h中)

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

💤尾删

直接在末尾删除就行,之后这里只要size减减就好了,后面的元素会覆盖。这里的实现和在pos位置插入x有类似,等我们实现这个函数,就可以直接调用这个函数,更加简便。(在头文件中SeqList.h中)

//尾删
void SLPopBack(SL* ps)
{//断言assert(ps);// 温柔的检查//if (ps->size == 0)//return;// 暴力的检查assert(ps->size > 0);//ps->a[ps->size - 1] = 0;//这里只要size减减就好了,后面的元素会覆盖ps->size--;//删除pos位置的值//SLErase(ps, ps->size - 1);
}

💤头插(重点)

这里需要注意要让ps->size加加这里的实现和在pos位置插入x有类似,等我们实现这个函数,就可以直接调用这个函数,更加简便。(在头文件中SeqList.h中)

//头插
void SLPushFront(SL* ps, SLDataType x)
{//断言assert(ps);//定义最后一个元素int end = ps->size - 1;//循环while (end >= 0){ps->a[end + 1] = ps->a[end];end--;}//x赋给最前的数字ps->a[0] = x;//指向下一个数字ps->size++;//在pos位置插入x//SLInsert(ps, 0, x);
}

💤头删(重点)

这里需要注意要让ps->size减减这里的实现和删除pos位置的值相似,等我们实现这个函数,就可以直接调用这个函数,更加简便。(在头文件中SeqList.h中)

//头删
void SLPopFront(SL* ps)
{//断言assert(ps);//断言(指向不能为零)assert(ps);//指向头前面的那个数字int begin = 1;//循环while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;//删除pos位置的值//SLErase(ps, 0);
}

  🌠增删查改

💤在pos位置插入x

首先这里需要判断pos是否在数组空间内,其次判断空间是否充足,然后循环,最后ps->size++

这里的插入本质和头插相似。(元素向后移动一格)

//在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x)
{//断言,这里posassert(ps);assert(pos >= 0 && pos < ps->size);//内存不够需要括容SLCheckCapacity(ps);int end = ps->size - 1;while (end >= pos){ps->a[end + 1] = ps->a[end];end--;}ps->a[pos] = x;ps->size++;
}

💤删除pos位置的值

首先这里需要判断pos是否在数组空间内,其次判断空间是否充足,然后循环,最后ps->size--

这里的删除本质和头删相似。(元素向前移动一格)

//删除pos位置的值
void SLErase(SL* ps, int pos)
{//断言assert(ps);//断言posassert(pos >= 0 && pos < ps->size);int begin = pos + 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];++begin;}ps->size--;
}

 💤修改pos位置的信息

这个实现太简单啦。

//修改pos位置的信息
void SLModify(SL* ps, int pos, SLDataType x)
{//断言assert(ps);//判断posassert(pos >= 0 && pos < ps->size);//直接换ps->a[pos] = x;
}

🌠主函数

int main()
{//定义结构体SL sl;//初始动态列表SLInit(&sl);//释放内存SLDestroy(&sl);return 0;
}

🌙代码总结

🌠主函数

//主函数(包含头文件)
#include"SeqList.h"//尾删
void TestSeqList1()
{//定义结构体SL sl;//初始化SLInit(&sl);//添加元素SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPushBack(&sl, 4);SLPushBack(&sl, 5);SLPushBack(&sl, 6);SLPushBack(&sl, 6);SLPushBack(&sl, 0);SLPushBack(&sl, 0);//打印元素SLPrint(&sl);//尾删SLPopBack(&sl);SLPopBack(&sl);//打印元素SLPrint(&sl);//尾删SLPopBack(&sl);SLPopBack(&sl);SLPopBack(&sl);SLPopBack(&sl);SLPopBack(&sl);SLPopBack(&sl);SLPopBack(&sl);//打印元素SLPrint(&sl);//添加元素SLPushBack(&sl, 1);SLPushBack(&sl, 2);//打印元素SLPrint(&sl);//释放内存SLDestroy(&sl);
}//头删
void TestSeqList2()
{//定义结构体SL sl;//初始动态列表SLInit(&sl);//添加元素SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPushBack(&sl, 4);SLPushBack(&sl, 5);//打印元素SLPrint(&sl);//头插SLPushFront(&sl, 10);SLPushFront(&sl, 20);SLPushFront(&sl, 30);SLPushFront(&sl, 40);//头删SLPopFront(&sl);SLPopFront(&sl);SLPopFront(&sl);//打印元素SLPrint(&sl);//释放内存SLDestroy(&sl);
}//在pos位置插入x
void TestSeqList3()
{//定义结构体SL sl;//初始动态列表SLInit(&sl);//添加元素SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPushBack(&sl, 4);SLPushBack(&sl, 5);//打印元素SLPrint(&sl);//在pos位置插入xint input = 0;printf("请输入插入的位置:");scanf("%d", &input);int number = 0;printf("请输入插入的数字:");scanf("%d", &number);SLInsert(&sl, input, number);//打印元素SLPrint(&sl);//释放内存SLDestroy(&sl);
}//删除pos位置的值
void TestSeqList4()
{//定义结构体SL sl;//初始动态列表SLInit(&sl);//添加元素SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPushBack(&sl, 4);SLPushBack(&sl, 5);//打印元素SLPrint(&sl);//删除pos位置的值int input = 0;printf("请输入删除的位置:");scanf("%d", &input);SLErase(&sl, input);//打印元素SLPrint(&sl);//释放内存SLDestroy(&sl);
}//删除pos位置的值
void TestSeqList5()
{//定义结构体SL sl;//初始动态列表SLInit(&sl);//添加元素SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPushBack(&sl, 4);SLPushBack(&sl, 5);//打印元素SLPrint(&sl);//修改pos位置的信息int input = 0;printf("请输入需要修改的位置:");scanf("%d", &input);int number = 0;printf("请输入需要修改的数字:");scanf("%d", &number);SLModify(&sl, input, number);//打印元素SLPrint(&sl);//释放内存SLDestroy(&sl);
}int main()
{//TestSeqList1();//TestSeqList2();//TestSeqList3();//TestSeqList4();TestSeqList5();return 0;
}

🌠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 SLCheckCapacity(SL* ps);// 头插头删 尾插尾删
void SLPushBack(SL* ps, SLDataType x);//添加元素
void SLPopBack(SL* ps);//尾删
void SLPushFront(SL* ps, SLDataType x);//头插元素
void SLPopFront(SL* ps);//头删//返回下标,没有找打返回-1
int SLFind(SL* ps, SLDataType x);
//在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x);
//删除pos位置的值
void SLErase(SL* ps, int pos);
//修改pos位置的信息
void SLModify(SL* ps, int pos, SLDataType x);

🌠SeqList.c头文件

#include"SeqList.h"//初始化动态顺序表
void SLInit(SL* ps)
{//开辟空间ps->a = (SLDataType*)malloc(sizeof(SLDataType*) * 4);//判断空间是否为空if (ps->a == NULL){perror("malloc failed");exit(-1);}//初始化ps->size = 0;ps->capacity = 4;
}//释放内存
void SLDestroy(SL* ps)
{//断言assert(ps);free(ps->a);ps->a = NULL;ps->size = 0;ps->capacity = 0;
}//打印数组
void SLPrint(SL* ps) 
{for (int i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");
}//扩容空间
void SLCheckCapacity(SL* ps)
{//如果size和capacity相同if (ps->size == ps->capacity){//扩大两倍SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDataType));//判断tmp是否为空if (tmp == NULL){perror("realloc failed");exit(-1);}//赋值ps->a = tmp;ps->capacity = ps->capacity * 2;}
}//添加元素
void SLPushBack(SL* ps, SLDataType x)
{//断言assert(ps);/*//判断空间是否满了,需要调用函数SLCheckCapacity(ps);//添加元素ps->a[ps->size] = x;ps->size++;*///在pos位置插入xSLInsert(ps, ps->size, x);
}//尾删
void SLPopBack(SL* ps)
{//断言assert(ps);/*// 温柔的检查//if (ps->size == 0)//return;// 暴力的检查assert(ps->size > 0);//ps->a[ps->size - 1] = 0;//这里只要size减减就好了,后面的会覆盖ps->size--;*///删除pos位置的值SLErase(ps, ps->size - 1);
}//头插
void SLPushFront(SL* ps, SLDataType x)
{//断言assert(ps);/*//定义最后一个元素int end = ps->size - 1;//循环while (end >= 0){ps->a[end + 1] = ps->a[end];end--;}//x赋给最前的数字ps->a[0] = x;//指向下一个数字ps->size++;*///在pos位置插入xSLInsert(ps, 0, x);
}//头删
void SLPopFront(SL* ps)
{//断言assert(ps);/*//断言(指向不能为零)assert(ps);//指向头前面的那个数字int begin = 1;//循环while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;*///删除pos位置的值SLErase(ps, 0);
}//返回下标,没有找打返回-1
int SLFind(SL* ps, SLDataType x)
{//断言assert(ps);//遍历for (int i = 0; i < ps->size; i++){if (ps->a[i] == x){return i;}}return -1;
}//在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x)
{//断言,这里posassert(ps);assert(pos >= 0 && pos < ps->size);//内存不够需要括容SLCheckCapacity(ps);int end = ps->size - 1;while (end >= pos){ps->a[end + 1] = ps->a[end];end--;}ps->a[pos] = x;ps->size++;
}//删除pos位置的值
void SLErase(SL* ps, int pos)
{//断言assert(ps);//断言posassert(pos >= 0 && pos < ps->size);int begin = pos + 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];++begin;}ps->size--;
}//修改pos位置的信息
void SLModify(SL* ps, int pos, SLDataType x)
{//断言assert(ps);//判断posassert(pos >= 0 && pos < ps->size);//直接换ps->a[pos] = x;
}

🌟结束语

今天内容就到这里啦,时间过得很快,大家沉下心来好好学习,会有一定的收获的,大家多多坚持,嘻嘻,成功路上注定孤独,因为坚持的人不多。那请大家举起自己的小说手给博主一键三连,有你们的支持是我最大的动力💞💞💞,回见。

 

http://www.lryc.cn/news/98383.html

相关文章:

  • Python实战项目——旅游数据分析(四)
  • 前端CryptoJS-AES加解密 对应php的AES-128-CBC加解密踩坑(java也相同加解密)
  • Python解码张三的法外狂徒之旅,揭秘视频背后的真相!【含jS逆向解密】
  • 【解析】对比学习和孪生网络的关系
  • Java版本企业工程项目管理系统平台源码(三控:进度组织、质量安全、预算资金成本、二平台:招采、设计管理)
  • 智能井盖:科技赋能城市脚下安全
  • wangeditor编辑器配置
  • Sqlite使用WAL模式指南
  • 一套高质量可靠的 React Hooks 库
  • 集合---list接口及实现类
  • JVM简述
  • 7.25训练总结
  • java注解@FeignClient修饰的类路径不在spring boot入口类所在的包下,有哪几种处理方式?
  • 神经网络随记-参数矩阵、剪枝、模型压缩、大小匹配、、
  • 4、Kubernetes 集群 YAML 文件详解
  • leetcode93. 复原 IP 地址(java)
  • 极光Java 版本服务器端实现别名消息推送
  • 【Lua学习笔记】Lua进阶——Table(4)继承,封装,多态
  • 安全性证明(四)Practical Identity-Based Encryption Without Random Oracles
  • Linux中常用的指令
  • 【java】【面对对象高级4】内部类、枚举、泛型
  • Python的用处到底是什么?(三)
  • 【Nodejs】Express基本使用
  • k8s集群安装v1.20.9
  • Staples Drop Ship EDI 需求分析
  • 模型调参及优化
  • 多数据源数据转换和同步的ETL工具推荐
  • 配置 gitlab https 访问
  • Kepware Modbus驱动简介
  • 从零开始学习CTF——CTF是什么