【C项目】顺序表

简介:本系列博客为C项目系列内容,通过代码来具体实现某个经典简单项目
适宜人群:已大体了解C语法同学
作者留言:本博客相关内容如需转载请注明出处,本人学疏才浅,难免存在些许错误,望留言指正
作者博客链接:睡觉待开机

下面是本项目的大体思路梳理:
在这里插入图片描述

引言:

一般来说,顺序表作为基本的数据结构类型是不需要我们进行实现的,因为一些高级语言比如C++或者java直接具备的这样的内置数据结构,但是为了深入了解顺序表的底层,这里也是建议自己动手用C写一下,一是便于复习C学到的知识,二是更加深入了解顺序表的实现底层逻辑。


1.顺序表思路

为了明晰顺序表的实现思路,我们首先来铺垫一下我到底要在怎么写一个顺序表。

首先啥是顺序表?
一种线性表,底层是数组,只不过这个顺序表所谓的数组不单单可以放各种类型的数据,还可以有各种接口,包括增删查改操作的接口等等。

注:线性表的概念:逻辑结构上是连续的,物理结构不一定连续的数据结构称为线性表。

顺序表的概念:逻辑结构上是连续的,物理结构上也是连续的,底层是以数组为实现,有着增删查改各种接口的基本数据组织结构。
在这里插入图片描述


那么我就可以大致明白了我要写一个顺序表,这个顺序表实现了一些功能。

首先我要写一个顺序表的话,要有一个顺序表的大体类型吧,所以我就写了一个动态顺序表的类型

typedef int SLDateType;

typedef struct SeqList
{
	SLDateType* arr;
	int size;
	int capacity;
}SL;

在这里插入图片描述

然后我想要在这个顺序表中实现各种功能(接口),那这个顺序表首先得初始化吧,有初始化顺序表了那肯定对应着销毁这个接口,自然也需要顺序表销毁,然后还要有头插尾插任意插入这个”增“的功能,还有有头删尾删任意删的这个”删“的共能,然后还要有查找功能,还要修改功能,那么我针对该顺序表的每个接口专门搞一个函数

为了便于代码书写,我将各种接口以及顺序表类型本身定义在SeqList.h头文件中进行声明与定义:

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>

typedef int SLDateType;

typedef struct SeqList
{
	SLDateType* arr;
	int size;
	int capacity;
}SL;


//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);

//顺序表的头部输入/尾部输入
void SLPushBack(SL* ps,SLDateType x);
void SLPushFront(SL* ps, SLDateType x);

//顺序表的头部删除/尾部删除
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);

//指定位置放入/删除数据
void SLInsert(SL* ps, int pos, SLDateType x);
void SLErase(SL* ps, int pos);

//查找数据
int SLFind(SL* ps, SLDateType x);

//修改数据
void SLModify(SL* ps, int pos, SLDateType x);


2.具体实现各种接口

顺序表初始化接口:

void SLInit(SL* ps)
{
	assert(ps);

	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

顺序表初始化插图:
在这里插入图片描述

顺序表销毁接口:

void SLDestroy(SL* ps)
{
	assert(ps);

	if (ps->arr)
	{
		free(ps->arr);
	}

	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

顺序表销毁插图:
在这里插入图片描述

顺序表扩容接口:

void SLCheckCapacity(SL* ps)
{
	assert(ps);

	if (ps->capacity == ps->size)
	{
		//小问题:刚开始的时候,sl->capacity是0值
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDateType* temp = realloc(ps->arr,sizeof(SLDateType)*newcapacity);
		if (!temp)
		{
			perror("realloc fail!");
			return;
		}

		ps->arr = temp;
		ps->capacity = newcapacity;
	}
}

顺序表扩容插图:
在这里插入图片描述

顺序表插入接口

void SLPushBack(SL* ps,SLDateType x)
{
	assert(ps);
	//1.空间不足需要扩大容量
	//2.空间足够直接放入数据
	SLCheckCapacity(ps);

	ps->arr[ps->size] = x;
	ps->size++;
}

void SLPushFront(SL* ps, SLDateType x)
{
	assert(ps);

	SLCheckCapacity(ps);

	//挪动数据
	int i = 0;
	for (i = ps->size - 1; i >= 0; i--)
	{
		ps->arr[i+1] = ps->arr[i];
	}
	//放入数据
	*(ps->arr) = x;
	ps->size++;
}
void SLInsert(SL* ps, int pos, SLDateType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	
	SLCheckCapacity(ps);

	int i = 0;
	for (i = ps->size - 1; i >= pos; i--)
	{
		ps->arr[i+1] = ps->arr[i];
	}
	
	ps->arr[pos] = x;
	ps->size++;
}

头插的插图:
在这里插入图片描述
尾插的插图:
在这里插入图片描述
任意插入的插图:
在这里插入图片描述

顺序表删除接口:

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

void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);

	int i = 0;
	for (i = 1; i < ps->size; i++)
	{
		ps->arr[i-1] = ps->arr[i];
	}

	ps->size--;
}
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	int i = 0;
	for (i = pos + 1; i < ps->size; i++)
	{
		ps->arr[i-1] = ps->arr[i];
	}

	ps->size--;
}

头删插图:
在这里插入图片描述
尾删插图:
在这里插入图片描述
任意删插图:
在这里插入图片描述

顺序表查找接口:

int SLFind(SL* ps, SLDateType x)
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (x == ps->arr[i])
		{
			printf("%d找到了:",x);
			return i;
		}
	}
	printf("没有找到\n");
	return -1;
}

在这里插入图片描述
顺序表修改接口:

void SLModify(SL* ps, int pos, SLDateType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size - 1);

	ps->arr[pos] = x;
	printf("修改成功\n");
}

修改插图:
在这里插入图片描述

3.全部接口代码实现:

#include"SeqList.h"


void SLCheckCapacity(SL* ps)
{
	assert(ps);

	if (ps->capacity == ps->size)
	{
		//小问题:刚开始的时候,sl->capacity是0值
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDateType* temp = realloc(ps->arr,sizeof(SLDateType)*newcapacity);
		if (!temp)
		{
			perror("realloc fail!");
			return;
		}

		ps->arr = temp;
		ps->capacity = newcapacity;
	}
}


void SLInit(SL* ps)
{
	assert(ps);

	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

void SLDestroy(SL* ps)
{
	assert(ps);

	if (ps->arr)
	{
		free(ps->arr);
	}

	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

void SLPrint(SL* ps)
{
	assert(ps);

	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", *(ps->arr + i));//ps->arr[i];
	}
	printf("\n");
}

void SLPushBack(SL* ps,SLDateType x)
{
	assert(ps);
	//1.空间不足需要扩大容量
	//2.空间足够直接放入数据
	SLCheckCapacity(ps);

	ps->arr[ps->size] = x;
	ps->size++;
}

void SLPushFront(SL* ps, SLDateType x)
{
	assert(ps);

	SLCheckCapacity(ps);

	//挪动数据
	int i = 0;
	for (i = ps->size - 1; i >= 0; i--)
	{
		ps->arr[i+1] = ps->arr[i];
	}
	//放入数据
	*(ps->arr) = x;
	ps->size++;
}

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

void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);

	int i = 0;
	for (i = 1; i < ps->size; i++)
	{
		ps->arr[i-1] = ps->arr[i];
	}

	ps->size--;
}

void SLInsert(SL* ps, int pos, SLDateType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	
	SLCheckCapacity(ps);

	int i = 0;
	for (i = ps->size - 1; i >= pos; i--)
	{
		ps->arr[i+1] = ps->arr[i];
	}
	
	ps->arr[pos] = x;
	ps->size++;
}

void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	int i = 0;
	for (i = pos + 1; i < ps->size; i++)
	{
		ps->arr[i-1] = ps->arr[i];
	}

	ps->size--;
}

int SLFind(SL* ps, SLDateType x)
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (x == ps->arr[i])
		{
			printf("%d找到了:",x);
			return i;
		}
	}
	printf("没有找到\n");
	return -1;
}

void SLModify(SL* ps, int pos, SLDateType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size - 1);

	ps->arr[pos] = x;
	printf("修改成功\n");
}


完。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

spark-cannot resolve overloaded method

使用split方法&#xff0c;出现错误&#xff1a;cannot resolve overloaded method 解决方法:那个regex应该是自动生成&#xff0c;所以split括号中输入空引号即可。 入门学习人的愚笨&#xff0c;也要继续坚持&#xff0c;加油&#xff01;

R语言基础学习-02 (此语言用途小众 用于数学 生物领域 基因分析)

变量 R 语言的有效的变量名称由字母&#xff0c;数字以及点号 . 或下划线 _ 组成。 变量名称以字母或点开头。 变量名是否正确原因var_name2.正确字符开头&#xff0c;并由字母、数字、下划线和点号组成var_name%错误% 是非法字符2var_name错误不能数字开头 .var_name, var.…

CISAW和CISP-PTE证书选择指南

&#x1f4e3;在信息安全领域&#xff0c;选择合适的证书可以为你的职业生涯增添光彩。很多从事信息渗透行业的朋友经常讨论CISP-PTE和CISAW之间的选择问题。今天就从4个方面带你详细了解这两张证书&#xff0c;帮你做出明智的选择&#xff01; 1️⃣证书的行业前景 &#x1f4…

八斗学习笔记

1 初始环境安装 Anaconda安装(一款可以同时创建跟管理多个python环境的软件) https://blog.csdn.net/run_success/article/details/134656460 Anaconda创建一个新python环境(安装人工智能常用的第三方python包&#xff0c;如&#xff1a;tensorflow、keras、pytorch) https://…

k8s的operator基石:controller-runtime源码解析

写在之前 今天开始开更controller-runtime的源码阅读&#xff0c;笔者建议大家在阅读前了解以下知识&#xff0c;可能会帮助大家更好的理解源码逻辑。 1.client-go的基础使用 2. 使用kubebuilder搭建一个简单的controller-runtime环境 3.informer的基本思想 1.源码环境搭建 参…

热仿真中稳态与瞬态的区别

对于热仿真&#xff0c;根据是否随时间变化&#xff0c;可分为稳态&#xff08;steady&#xff09;仿真和瞬态&#xff08;transient&#xff09;仿真两类。 从数学计算的角度&#xff0c;所谓稳态是指物理量不随时间变化的定常过程&#xff0c;即计算域中所有物理量均满足关系…

鸿蒙会取代Android吗?听风就是雨

现在说取代还谈不上&#xff0c;毕竟这需要时间。安卓作为全球第一的手机操作系统&#xff0c;短时间内还无法取代。持平iOS甚至超过iOS有很大可能&#xff0c;最终会呈现“三足鼎立”有望超过安卓基数。 作为全新的鸿蒙操作系统&#xff0c;其现在已经是全栈自研底座。按照鸿…

讯飞星火V3.5发布,一场大模型的奇幻之旅(深度体验讯飞星火V3.5)

在去年的人工智能领域&#xff0c;大模型无疑是最炙手可热的技术话题。其强大的数据处理和深度学习能力&#xff0c;为众多领域带来了革命性的变革。而其中&#xff0c;讯飞星火表现尤为出色&#xff0c;成为了行业的翘楚&#xff0c;得到了大量的用户认可&#xff0c;其中&…

负载均衡下的webshell上传+nginx解析漏洞

负载均衡下的webshell上传 一&#xff0c;负载均衡下webshell上传的四大难点 难点一&#xff1a;需要在每一台节点的相同位置上传相同内容的webshell 我们需要在每一台节点的相同位置都上传相同内容的 WebShell一旦有一台机器上没有&#xff0c;那么在请求轮到这台机器上的时…

【Linux】线程池的简易实现(懒汉模式)

文章目录 前言一、懒汉方式1.普通模式1.线程安全模式 二、源代码1.Task.hpp(要执行的任务)2.ThreadPool.hpp(线程池)3.Main.cpp 前言 线程池: 一种线程使用模式。线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&#xff0c;等待着监…

【Qt】—— Qt Creator 创建项目

目录 &#xff08;一&#xff09;Qt Creator概览 &#xff08;二&#xff09;使⽤Qt Creator新建项⽬ &#xff08;一&#xff09;Qt Creator概览 从开始菜单或者快捷⽅式打开Qt Creator集成开发环境&#xff0c;启动之后看到类似下⾯的界⾯&#xff1a; 【解释说明】 菜单栏…

一体化设计:兼容多种OS系统Linux网关楼宇DDC

在工业物联网&#xff08;IIoT&#xff09;和智能建筑领域&#xff0c;钡铼网关具备高度灵活性与强大计算能力的边缘网关产品正逐渐成为推动行业智能化转型的关键要素。本文将详细介绍的基于Linux系统的4G工业智能网关&#xff0c;不仅拥有NXP i.MX8M Mini四核64位处理器的强大…

容器算法迭代器初识

#include<iostream> using namespace std; #include<vector> //vetor容器存放内置数据类型 void test01() {//创建了一个vector容器&#xff0c;数组 vector<int> v;//向容器中插入数据v.push_back (10);//尾插 v.push_back (20);v.push_back (30);v.push_ba…

Springboot使用数据库连接池druid

springboot框架中可以使用druid进行数据库连接池&#xff0c;下面介绍druid在springboot中使用和参数配置介绍。 数据库连接池&#xff08;Druid&#xff09;是一种用于管理数据库连接的机制&#xff0c;其工作原理和常见使用方法如下&#xff1a; 原理&#xff1a;数据库连接…

异步任务的一些思考

前言 XXL-Job部署教程 项目中&#xff0c;必然少不了数据的导入导出&#xff0c;针对数据的导入导出简单复盘一下。 为了不占用资源消耗时间&#xff0c;影响用户体验&#xff0c;大量数据的导入导出一般都是异步执行 导入的时候&#xff0c;如果数据量很大&#xff0c;一次…

C#使用RabbitMQ-4_路由模式(直连交换机)

简介 RabbitMQ中的路由模式是一种根据Routing Key有条件地将消息筛选后发送给消费者的模式。在路由模式中&#xff0c;生产者向交换机发送消息时&#xff0c;会指定一个Routing Key。交换机接收生产者的消息后&#xff0c;根据消息的Routing Key将其路由到与Routing Key完全匹…

Centos7——下载——安装

解释 CentOS 7是CentOS项目发布的开源类服务器操作系统&#xff0c;于2014年7月7日正式发布。CentOS 7是一个企业级的Linux发行版本&#xff0c;它源于RedHat免费公开的源代码进行再发行。CentOS 7内核更新至3.10.0、支持Linux容器、支持Open VMware Tools及3D图像即装即用、支…

代码随想录算法训练营第二二天| 二叉搜索树的最近公共祖先、二叉搜索树中的插入操作、删除二叉搜索树中的节点

目录 二叉搜索树的最近公共祖先二叉搜索树中的插入操作删除二叉搜索树中的节点普通二叉树的删除方式 LeetCode 235. 二叉搜索树的最近公共祖先 LeetCode 701.二叉搜索树中的插入操作 LeetCode 450.删除二叉搜索树中的节点 二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到…

【Linux】多线程(线程概念+线程控制)

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

Bootloader简单说明

文章目录 一、简单架构1.CAN驱动2.Flash驱动3.传输层4.诊断层5.看门狗&#xff08;Watch Dog&#xff09;6.加密算法 二、主要功能三、启动顺序与转换流程1.启动流程图2.启动顺序与转换流程说明 一、简单架构 1.CAN驱动 实现CAN报文的收发和CAN控制器硬件的操作。特点&#x…