实现顺序表(增、删、查、改)

引言:顺序表是数据结构中的一种形式,就是存储数据的一种结构。

这里会用到动态内存开辟,指针和结构体的知识

1.什么是数据结构

数据结构就是组织和存储数据的结构。

数据结构的特性:

物理结构:在内存中存储的数据是否连续

逻辑结构:   逻辑上是否连续


2.什么是顺序表

为了更好的实现顺序表,首先的了解其的特性。

顺序表的特性:

物理结构:连续的

逻辑结构:连续的

顺序表也是线性结构的一种

线性结构的特性:

物理结构:不一定连续

逻辑结构:连续的

顺序表的底层是数组。顺序表在数组的基础上能通过调用函数实现数据的增删查改。

数组在内存中开辟的空间是连续的,所以其存储的数据在内存中也是连续的。


3.静态顺序表与动态顺序表哪个更好呢? 

顺序表又分为静态顺序表,和动态顺序表

那么哪种更好呢? 

静态顺序表和动态顺序表的结构

//静态顺序表的结构
struct SeqList
{int arr[100];//开辟的空间大小已经确定int size;//记录当前元素的个数
};
//动态顺序表的结构
struct SeqList
{int* arr;int size;//记录当前元素的个数int capacity;//记录当前能存放元素的个数,如果size=capacity时,扩容
};

动态顺序表的结构图解:

 

比较:

静态顺序表开辟的存放数据的空间:如果开辟过大,则浪费空间;若开辟过小,若想存的数据过多,则有的数据存不进去。

而动态顺序表则更灵活,不够了再开辟就可以了。

所以动态顺序表更好,这里也只会将动态顺序表的实现。


4.动态顺序表的实现

4.1通过多文件的形式实现

文件管理:

test.c进行各个接口的测试
SeqList.c实现增删查改函数的实现
SeqLst.h引用需要使用的头文件,动态顺序表结构体的定义,实现增删查改函数函数的声明,#define 定义的符号

需要实现的函数: 

初始化、销毁创建完动态顺序表的结构后应对其成员进行初始化,释放开辟的空间,并将结构体的成员初始化

有头插,尾插

任意插

头删,尾删

任意删

查找顺序表中是否有查找的元素

这里直接给出完整的SeqList.h 中的全部代码:

#pragma once//防止头文件多次包含//用到的库函数
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>//如果以后想存储的数据不再是int 只需要改这一出的int改为别的数据类型
#define SLDataType int//顺序表的结构定义
typedef struct SeqList
{SLDataType* arr;int size;int capacity;
}SL;//以下为需要实现的函数的声明
//初始化
void SLInit(SL* ps);
void SLDestory(SL* ps);
//打印
void SLPrint(SL ps);
//尾插,尾删
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
//尾删,头删
void SLPopFront(SL* ps);
void SLPopBack(SL* ps);
//任意插,任意删
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
//查找
int SLFind(SL* ps,SLDataType find);

4.2初始化和销毁注意事项

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

 一定要传定义的结构体的地址,这样才能改变所定义的结构体的值。

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

4.3尾插,头插中的一些注意事项

尾插实现函数:

void SLPushBack(SL* ps, SLData x)
{//ps不能为NULLassert(ps != NULL);//增容:1.capacity和size都为0   2.空间不够用if (ps->capacity == ps->size){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLData* tmp = (SLData*)realloc(ps->arr, newcapacity * sizeof(SLData));if (tmp == NULL){perror("realloc");exit(-1);}//开辟成功ps->arr = tmp;ps->capacity = newcapacity;}//将值写入顺序表ps->arr[ps->size] = x;//插入完顺序表中元素的个数+1ps->size++;
}

增容问题:

如果结构体中的size 和capacity 都为0,或size等于capacity(所开辟的空间都被使用完)时,就要增容。

用realloc,malloc还是用calloc开辟空间呢?

考虑到增容的问题所以用realloc开辟空间。

那么增多大呢?

这里不好解释,建议增大当前所开辟空间的2或3倍。如果开辟小了的话,很快就会被用完,就会频繁地开辟,如果是下图中realloc开辟空间中的情况2,拷贝数据很影响程序性能;若开辟过大,则浪费空间。

因为插入会考虑到增容问题所以可以写一个实现增容的函数

void CheckSLCapacity(SL* ps)
{//如果size等于capacity说明开辟的空间已经使用完,得增容if (ps->capacity == ps->size){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLData* tmp = (SLData*)realloc(ps->arr, newcapacity * sizeof(SLData));if (tmp == NULL){perror("realloc");exit(-1);}//开辟成功ps->arr = tmp;ps->capacity = newcapacity;}
}

头插和尾插实现的代码:

//头插
void SLPushFront(SL* ps, SLData x)
{assert(ps != NULL);CheckSLCapacity(ps);//增容函数,上面的尾插的代码中的实现增容的代码也可以替换为这个函数for (int i = ps->size; i>0; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[0] = x;ps->size++;
}//头插
void SLPushBack(SL* ps, SLDataType x)
{assert(ps != NULL);CheckSLCapacity(ps);ps->arr[ps->size] = x;ps->size++;
}

 4.4 头删和尾删

实现代码:

//尾删
void SLPopBack(SL* ps)
{assert(ps != NULL);assert(ps->size > 0);ps->size--;
}//头删
void SLPopFront(SL* ps)
{assert(ps != NULL);assert(ps->size > 0);for (int i = 0; i <ps->size-1 ; i++)ps->arr[i] = ps->arr[i + 1];ps->size--;
}

注意:如果顺序表中没有数据那么就不能继续删除了, assert(ps->size > 0)防止没有数据了继续删。

尾删:只需要将size--就可以,不需要将最后的数据修改(修改也是可以的),但别忘了最后size--

头删:将除头部的其他数据整体向前挪动一位。

头删图解:

4.5 任意删和任意插

实现代码:

//任意插
//pos为想要插入的位置的下标
void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);//若pos小于0,不能插入;若想要插入的位置大于size也不能插入assert(pos >= 0 && pos <= ps->size);//考虑扩容问题CheckSLCapacity(ps);//注意赋值的顺序和 i 的范围for (int i = ps->size; i>pos ; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;ps->size++;
}//任意删
void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);for (int i = pos; i < ps->size-1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;}

注意事项:

任意插入:

对插入位置下标(pos)的限制: pos >= 0 && pos <= ps->size

图解:

通过上图可以用任意插函数实现头插和尾插

 

任意插入后挪动数据的方式:

从pos位置开始集体往后挪

 任意删除后的数据挪动方式:

从size-1 开始往前挪直到pos+1 的位置。

用任意插入和任意删除的函数实现 头插,尾插和头删,尾删

//头插、尾插
void SLPushBack1(SL* ps, SLDataType x)
{SLInsert(ps, ps->size, x);
}
void SLPushFront1(SL* ps, SLDataType x)
{SLInsert(ps, 0, x);
}
//尾删,头删
void SLPopFront1(SL* ps)
{SLErase(ps, 0);
}
void SLPopBack1(SL* ps) 
{SLErase(ps, ps->size-1);}

4.6查找 

实现函数:

int SLFind(SL* ps,SLDataType find)
{assert(ps);for (int i = 0; i < ps->size; i++){//如果找到返回下标if (ps->arr[i] == find)return i;}//没找到返回小于0 的数return -1;
}

查找函数的使用:

	int find = SLFind(&s, 6);if (find < 0)printf("找不到\n");elseprintf("%d\n", find);

为什么没找到返回小于0的数?

因为存储的数据的下标都大于等于0。


 

 5.完整代码来喽!

test.c:(这就是我自己写代码使用的一些测试用例,大家可以自己写测试用例,自己测试,则一块不是很重要)

#include "SeqList.h"
void SLTest()
{SL s;SLInit(&s);//SLPrint(s);//SLPushBack(&s, 1);//SLPrint(s);//SLPushBack(&s, 2);//SLPrint(s);	//SLPushBack(&s, 3);//SLPrint(s);//SLPushBack(&s, 4);//SLPrint(s);SLPushBack(&s, 5);SLPrint(s);/*SLPushBack(NULL, 5);*/SLPushFront(&s, 6);SLPrint(s);SLPushFront(&s, 7);SLPrint(s);/*SLPushFront(NULL, 7);*/SLPopFront(&s);SLPrint(s);SLPopBack(&s);SLPrint(s);//SLPopFront(&s);//SLPrint(s);SLPopFront(&s);SLPrint(s);SLDestory(&s);
}
void SLTest1()
{SL s;SLInit(&s);SLPushFront(&s, 1);SLPushBack(&s, 2);SLPushBack(&s, 3);SLPrint(s);SLInsert(&s, 0, 4);SLPrint(s);SLInsert(&s,4,5);SLInsert(&s,3,6);SLPrint(s);SLErase(&s, 4);SLPrint(s);SLErase(&s, 0);SLPrint(s);int find = SLFind(&s, 6);if (find < 0)printf("找不到\n");elseprintf("%d\n", find);SLDestory(&s);
}
int main()
{/*SLTest();*/SLTest1();return 0;
}

SeqList.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>#define SLDataType int
typedef struct SeqList
{SLDataType* arr;int size;int capacity;
}SL;//初始化
void SLInit(SL* ps);
void SLDestory(SL* ps);
//打印
void SLPrint(SL ps);
//尾插,尾删
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
//尾删,头删
void SLPopFront(SL* ps);
void SLPopBack(SL* ps);
//任意插,任意删
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
//查找
int SLFind(SL* ps,SLDataType find);

 

SeqList.c:

#include "SeqList.h"void CheckSLCapacity(SL* ps)
{if (ps->capacity == ps->size){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));if (tmp == NULL){perror("realloc");exit(-1);}//开辟成功ps->arr = tmp;ps->capacity = newcapacity;}
}void SLInit(SL* ps)
{ps->arr = NULL;ps->size = 0;ps->capacity = 0;
}void SLDestory(SL* ps)
{assert(ps);free(ps->arr);ps->arr = NULL;ps->size = 0;ps->capacity = 0;
}void SLPrint(SL s)
{for (int i = 0; i < s.size; i++)printf("%d ", s.arr[i]);printf("\n");
}void SLPushBack(SL* ps, SLDataType x)
{assert(ps != NULL);CheckSLCapacity(ps);ps->arr[ps->size] = x;ps->size++;
}void SLPushFront(SL* ps, SLDataType x)
{assert(ps != NULL);CheckSLCapacity(ps);for (int i = ps->size; i>0; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[0] = x;ps->size++;
}void SLPopBack(SL* ps)
{assert(ps != NULL);assert(ps->size > 0);ps->size--;
}void SLPopFront(SL* ps)
{assert(ps != NULL);assert(ps->size > 0);for (int i = 0; i <ps->size-1 ; i++)ps->arr[i] = ps->arr[i + 1];ps->size--;
}void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);CheckSLCapacity(ps);for (int i = ps->size; i>pos ; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;ps->size++;
}void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);for (int i = pos; i < ps->size-1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;}int SLFind(SL* ps,SLDataType find)
{assert(ps);for (int i = 0; i < ps->size; i++){if (ps->arr[i] == find)return i;}return -1;
}

结语:

头次写数据结构,放平心态 ,一定要写完一个接口调试一个接口,不要都写完了再去调试,若有一堆问题容易心态爆炸(boom)。

 拜拜,下一期。目标项目:通讯录。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统中的动态追踪技术

在Linux系统中&#xff0c;动态追踪技术是一种强大的工具&#xff0c;用于在运行时追踪和分析系统和应用程序的行为。动态追踪技术允许用户监视系统和应用程序的运行&#xff0c;捕获关键信息&#xff0c;以便于调试、性能优化、故障排除和安全监控。本文将介绍Linux系统中的动…

linux设置Nacos自启动

前提&#xff1a;已经安装好nacos应用 可参考&#xff1a;Nacos单机版安装-CSDN博客 1. 创建nacos.service 1.1 在 /lib/systemd/system 目录底下&#xff0c;新建nacos.service文件 [Unit] Descriptionnacos Afternetwork.target[Service]Typeforking# 单机启动方式&#…

肿瘤免疫反应瀑布图(源于The Miller Lab)

目录 数据格式 绘图 ①根据剂量 ②根据type ③根据治疗响应度 添加水平线 数据格式 肿瘤免疫响应数据 rm(list ls()) library(tidyverse) library(dplyr) library(knitr)#模拟数据 # We will randomly assign the two doses, 80 mg or 150 mg, to the 56 subjects Me…

c语言游戏实战(7):扫雷(下)

前言&#xff1a; 扫雷是一款经典的单人益智游戏&#xff0c;它的目标是在一个方格矩阵中找出所有的地雷&#xff0c;而不触碰到任何一颗地雷。在计算机编程领域&#xff0c;扫雷也是一个非常受欢迎的项目&#xff0c;因为它涉及到许多重要的编程概念&#xff0c;如数组、循环…

VSCode安装及Python、Jupyter插件安装使用

VSCode 介绍 Visual Studio Code&#xff08;简称VSCode&#xff09;是一个由微软开发的免费、开源的代码编辑器。VSCode是一个轻量级但是非常强大的代码编辑器&#xff0c;它支持多种编程语言&#xff08;如C,C#&#xff0c;Java&#xff0c;Python&#xff0c;PHP&#xff0…

计算机视觉之三维重建(5)---双目立体视觉

文章目录 一、平行视图1.1 示意图1.2 平行视图的基础矩阵1.3 平行视图的极几何1.4 平行视图的三角测量 二、图像校正三、对应点问题3.1 相关匹配法3.2 归一化相关匹配法3.3 窗口问题3.4 相关法存在的问题3.5 约束问题 一、平行视图 1.1 示意图 如下图即是一个平行视图。特点&a…

权限提升技术:攻防实战与技巧

本次活动赠书1本&#xff0c;包邮到家。参与方式&#xff1a;点赞收藏文章即可。获奖者将以私信方式告知。 网络安全已经成为当今社会非常重要的话题&#xff0c;尤其是近几年来&#xff0c;我们目睹了越来越多的网络攻击事件&#xff0c;例如公民个人信息泄露&#xff0c;企业…

zip解压异常java.lang.IllegalArgumentException: MALFORMED处理

使用hutool解压zip包时出错&#xff1a; //压缩包解压到固定目录 ZipUtil.unzip(tempZipFile,dir);在解压文件的时候报错&#xff0c;原因是压缩文件中有中文&#xff1b;导致错误&#xff0c;解决办法是设置编码&#xff1a; ZipFile tempZipFile new ZipFile(zipFile, Cha…

Windows10下安装wget

文章目录 1. 查看是否安装2. 通过exe安装3. 通过解压缩包 wget 是一个从网络上自动下载文件的自由工具&#xff0c;支持通过 HTTP、HTTPS、FTP 三个最常见的 TCP/IP协议 下载&#xff0c;并可以使用 HTTP 代理。“wget” 这个名称来源于 “World Wide Web” 与 “get” 的结合。…

内存管理是如何影响系统的性能的

大家好&#xff0c;今天给大家介绍内存管理是如何影响系统的性能的&#xff0c;文章末尾附有分享大家一个资料包&#xff0c;差不多150多G。里面学习内容、面经、项目都比较新也比较全&#xff01;可进群免费领取。 内存管理对系统性能的影响至关重要&#xff0c;主要体现在以下…

Zabbix6 - Centos7部署Grafana可视化图形监控系统配置手册手册

Zabbix6 - Centos7部署Grafana可视化图形监控系统配置手册手册 概述&#xff1a; Grafana是一个开源的数据可视化和监控平台。其特点&#xff1a; 1&#xff09;丰富的可视化显示插件&#xff0c;包括热图、折线图、饼图&#xff0c;表格等&#xff1b; 2&#xff09;支持多数据…

Windows系统基于WSL子系统的torchquantum安装记录GPU版本

子系统需要的环境&#xff1a; anaconda/miniconda、pip换源(清华源) 1.准备 torchquantum最新版本可以从github上找到&#xff0c;直接clone/下载整个project&#xff0c;查看环境要求&#xff0c;需要安装pytorch和tensorflow 新建一个conda环境&#xff0c;注意python最…