数据结构C语言版 —— 顺序表增删改查实现

news2024/11/29 0:34:11

文章目录

  • 顺序表
    • 1. 线性表
    • 2. 顺序表
    • 3. 顺序表基本概念
    • 4. 顺序表实现
      • 顺序表初始化
      • 顺序表的扩容
      • 顺序表的插入
      • 顺序表的删除
      • 顺序表的查找
      • 顺序表的修改
      • 顺序表的销毁
    • 5. 顺序表总结


顺序表

1. 线性表

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

数据结构中报考逻辑结构物理结构两个层次

  • 逻辑结构

    数据的逻辑结构是从逻辑关系上描述数据,它与数据的存储无关,是独立与计算机的。所以,数据的逻辑结构可以看作是从具体问题抽象出来的数学模型。

    数据的逻辑结构有两个要素:一是数据元素,二是关系。数据元素的含义如前所述,关系是指数据元素之间的逻辑关系。它根据元素之间关系的不同特性,通常有4类基本结构。

在这里插入图片描述

  • 集合结构

    数据元素之间除了属于同一个集合的关系外,没有其它关系。

  • 线性结构

    数据元素之间存在这一对一的关系,比如将一些学生的信息按照它的学号按照先后顺序排序,组成一个线性结构

  • 树结构

    数据元素之间存在着一对多的关系,比如在班级管理体系中,班长管理多个组长,每个组长管理多名组员

  • 图结构

    数据元素之间存在着多对多的关系,比如多位同学之间的朋友关系,任何两个同学都可以是朋友,从何构成图结构。

在这里插入图片描述

  • 物理结构

    数据对象在计算机中的存储表示称为存储结构,也称为物理结构。把数据对象存储到计算机时,通常要求既要存储数据元素的数据,又要存储数据元素之间的逻辑关系,数据元素在计算机内用一个节点来表示。

    物理结构又可以分为顺序存储和链式存储。顺序表和链表就是典型代表。

2. 顺序表

3. 顺序表基本概念

顺序表使用一段连续物理地址的存储单元依次存储数据元素的一种线性结构,简单来说就是一个数组,一个可以动态增长的数组,并且要求里面存储的数据必须是从左往右是连续的。然后在这个数组上完成增删改查。顺序表的特点是逻辑上相邻的数据元素,物理上也是相邻的

顺序表的缺陷

  1. 动态扩容有性能消耗
  2. 如果在头部插入数据,需要挪动元素

顺序表的存储结构

typedef int SeqDataType;
typedef struct SeqList 
{
	SeqDataType* arr;//指向动态开辟数组首元素
	size_t size;//存放元素个数
	size_t capacity;//容量
}SeqList;

在这里插入图片描述

4. 顺序表实现

静态的顺序表只适合用于知道需要存储多少数据的场景,如果静态的顺序表定义的数组太大就会出现浪费,而定义的太小就会不够用。所以使用动态的顺序表会更加合理,通过动态分配空间来实现顺序表。

typedef int SeqDataType;
typedef struct SeqList 
{
	SeqDataType* arr;
	size_t size;//存放元素个数
	size_t capacity;//容量
}SeqList;

//初始化顺序表
void SeqListInit(SeqList* pq);
//销毁顺序表
void SeqListDestory(SeqList* pq);
//打印顺序表元素
void SeqListPrint(SeqList* pq);
//判断顺序表是否为空
int SeqListEmpty(SeqList* pq);
//获取顺序表元素个数
size_t SeqListSize(SeqList* pq);
//判断扩容顺序表
int CheckCapacity(SeqList* pq);
//尾插
void SeqListPushBack(SeqList* pq, SeqDataType data);
//头插
void SeqListPushFront(SeqList* pq, SeqDataType data);
//删除末尾元素
void SeqListPopBack(SeqList* pq);
//删除头部元素
void SeqListPopFront(SeqList* pq);
//在顺序表中查找元素
SeqDataType SeqListFind(SeqList* pq, SeqDataType data);
//获取指定位置的数据元素
SeqDataType SeqListGet(SeqList* pq, size_t pos);
//在顺序表pos位置插入数据
void SeqListInsert(SeqList* pq, size_t pos, SeqDataType data);
//删除顺序表中pos位置的元素
void SeqListErase(SeqList* pq, size_t pos);
//修该顺序表pos位置的元素
void SeqListModify(SeqList* pq, size_t pos, SeqDataType target);

这里我只实现比价关键的接口

顺序表初始化

顺序表初始化比较简单,只需要通过malloc开辟一块合适的空间就好.

  1. 判断结构体是否为空
  2. 初始化容量为10
  3. 使用malloc函数开辟空间
//初始化顺序表
void SeqListInit(SeqList* pq)
{
	assert(pq);
	pq->capacity = 10;
	pq->arr = (SeqDataType*)malloc(sizeof(int) * pq->capacity);
	if (pq->arr == NULL)
	{
		printf("初始化失败\n");
		exit(1);
	}
	memset(pq->arr, 0, sizeof(int) * pq->capacity);//给顺序表初始化
	pq->size = 0;
}

顺序表的扩容

如果在插入数据元素的时候发现满了就要进行扩容,通过realloc来对数组进行扩容,需要进行扩容的数组进行判空。

  1. 如果当前元素个数等于数组容量就进行扩容
  2. 使用realloc对数组进行二倍扩容
  3. 如果扩容失败,则什么都不做
  4. 扩容成功就把结构体数组指向扩容空间的首地址
//判断扩容顺序表
int CheckCapacity(SeqList* pq)
{
	if (pq->size == pq->capacity)
	{
		//二倍扩容
		pq->capacity = pq->capacity * 2;
		SeqDataType* ptr = (SeqDataType*)(realloc(pq->arr, sizeof(int) * pq->capacity));
		if (ptr == NULL)
		{
			printf("扩容失败\n");
			pq->capacity = pq->capacity / 2;
			return 1;
		}
		pq->arr = ptr;
		printf("扩容成功\n");
	}

	return 0;
}

顺序表的插入

顺序表元素插入分为3种,从头部插入、从末尾插入、从指定位置插入。其实只要实现了从指定位置插入,头插和尾插都可以调用指定位置插入的接口。指定位置插入思路。

  1. 首先得判NULL和是否越界
  2. 判断是否需要扩容
  3. 从最后一个元素位置开始,将元素从前往后移动
//在顺序表pos位置插入数据
void SeqListInsert(SeqList* pq, size_t pos, SeqDataType data)
{
	assert(pq);
	assert(pos <= pq->size);//越界判断
	CheckCapacity(pq);
	size_t index = pq->size;
	while (index > pos)
	{
		pq->arr[index] = pq->arr[index - 1];
		index--;
	}
	pq->arr[pos] = data;
	pq->size++;

}

比如要在下标为2的位置插入元素

在这里插入图片描述

实现了指定位置插入之后,头插和尾插就比较简单了

头插

//头插
void SeqListPushFront(SeqList* pq, SeqDataType data)
{
	assert(pq);
	
	SeqListInsert(pq, 0, data);
}

尾插

//尾插
void SeqListPushBack(SeqList* pq, SeqDataType data)
{
	assert(pq);

	SeqListInsert(pq, pq->size, data);
}

顺序表插入元素的时间复杂度是 O ( N ) O(N) O(N)

顺序表的删除

顺序表的删除分为头删、尾删和指定位置删除,和插入类似,只需要从后往前挪动元素将要删除的元素覆盖即可。

  1. 判NULL和是否越界
  2. 将pos位置的元素全部往前挪动
  3. 元素个数减1
//删除顺序表中pos位置的元素
void SeqListErase(SeqList* pq, size_t pos)
{
	assert(pq);
	assert(pos < pq->size);
	size_t index = pos;
	while (index < pq->size - 1)
	{
		pq->arr[index] = pq->arr[index + 1];
		index++;
	}
	pq->size--;
}

在这里插入图片描述

完成了指定位置删除就可以,调用它完成头删和尾删了

头删

//删除头部元素
void SeqListPopFront(SeqList* pq)
{
	assert(pq);

	SeqListErase(pq, 0);
}

尾删

//删除末尾元素
void SeqListPopBack(SeqList* pq)
{
	assert(pq);
	assert(pq->size != 0);
	
	SeqListErase(pq, pq->size-1);
}

顺序表删除的时间复杂为 O ( N ) O(N) O(N)

顺序表的查找

顺序表的查找分两种,一种是查找指定数据元素返回下标,另外一种是直接获取某个下标的元素

查找元素

//在顺序表中查找元素
SeqDataType SeqListFind(SeqList* pq, SeqDataType data)
{
	assert(pq);
	size_t i = 0;
	for (i = 0; i < pq->size; i++)
	{
		if (pq->arr[i] == data)
		{
			//返回第一个找到的元素的下标
			return i;
		}
	}

	return -1;
}

获取指定位置的元素

//获取指定位置的数据元素
SeqDataType SeqListGet(SeqList* pq, size_t pos)
{
	assert(pq);
	assert(pos < pq->size);

	return pq->arr[pos];
}

顺序表查找的时间复杂度为 O ( N ) O(N) O(N),但如果是给定下标获取元素则是 O ( 1 ) O(1) O(1)

顺序表的修改

顺序表的修改指定下标的元素,也是非常简单的

//修该顺序表pos位置的元素
void SeqListModify(SeqList* pq, size_t pos, SeqDataType target)
{
	assert(pq);
	assert(pos < pq->size);

	pq->arr[pos] = target;
}

顺序表的修改时间复杂度为 O ( N ) O(N) O(N)

顺序表的销毁

顺序表的销毁只需要

  1. 把元素个数容量赋值成0

  2. 将开辟的内存空间释放掉

  3. 再将数组指向NULL

//销毁顺序表
void SeqListDestory(SeqList* pq)
{
	assert(pq);
	pq->size = 0;
	pq->capacity = 0;
	free(pq->arr);
	pq->arr = NULL;
}

5. 顺序表总结

  1. 顺序表的插入和删除时间复杂度为 O ( N ) O(N) O(N)
  2. 顺序表的扩容使用的是realloc,如果后面的空间不够就会重新开辟新的空间,再把数据拷贝到新的空间,这样就会有一定的额性能消耗
  3. 顺序表存在着一定的资源浪费,比如当前顺序表的容量为200,当放满之后再插入10个元素,就会进行2倍扩容到400,此时就浪费了190个数据空间。

我们发现顺序表存在着一定缺陷,如果想不那么浪费空间就想着扩容扩少一点,但扩容小了如果有大量数据插入又会存着不断扩容的情况,那么又会有着性能的消耗。

针对以上问题,就可以引入链表。
下一篇链表博客马上发布。


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【DevOps】总结下容器方式构建Grafana-reporter生成PDF格式报告

目录 Grafana-reporter1、编写Dockerfile2、构建镜像3、运行Grafana-reporter4、在Grafana配置Link即文章:【DevOps】Prometheus+Grafana:生成pdf报表总结下Grafana-reporter镜像打包过程 最终pdf实现效果类似: Grafana-reporter 简介:“A simple http service that gen…

[附源码]Python计算机毕业设计仿咸鱼二手物品交易系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

TCP/IP 网络原理【TCP篇】

&#x1f389;&#x1f389;&#x1f389;写在前面&#xff1a; 博主主页&#xff1a;&#x1f339;&#x1f339;&#x1f339;戳一戳&#xff0c;欢迎大佬指点&#xff01; 目标梦想&#xff1a;进大厂&#xff0c;立志成为一个牛掰的Java程序猿&#xff0c;虽然现在还是一个…

joinquant量化是什么?是主流的量化平台吗?

joinquant量化是什么&#xff1f;我们做量化投资的时候&#xff0c;目前比较流行的平台&#xff0c;我推荐的是这三个&#xff0c;一个是Ricequant&#xff0c;另外一个是JoinQuant&#xff0c;还有一个QUANTOPIAN&#xff0c;国内实际上就是优矿。这几个现在比较流行&#xff…

git分支管理

分支管理&#xff08;拙见&#xff09; 1&#xff0c;首先master分支是最高级别分支。不可编辑 2&#xff0c;创建一个release分支&#xff0c;从master上拉取&#xff0c;用于上线分支 3&#xff0c;创建dev开发分支&#xff0c;从relase分支拉取&#xff0c;如果有开发环境…

裸辞美团花两月吃透这 Java 岗 798 道真题解析,定级阿里 P7

2023 的面试即将到来&#xff0c;大家准备的怎么样了呢&#xff1f;你有没有正在为此而发愁呢&#xff1f;那么一起来看看小编整理的这富含的 15 个互联网大厂 Java 高级工程师核心面试问题整理吧&#xff01;已助我在 2023 年的金三银四跳槽季中拿到阿里 P7. 内容包括&#x…

Stm32旧版库函数9——ADC读取电压值

#include <stm32f10x_lib.h> #include "adc.h" unsigned char i0; u16 ad[3]{0,0,0}; //初始化ADC //这里我们仅以规则通道为例 void Adc_init(void) { //先初始化…

Unity - Baking System - 烘焙失效的问题

文章目录环境问题解决方法环境 unity : 2020.2.5f1, 2020.3.37f1 pipeline : BRP 问题 我之前有去搜索过场景烘焙失效的问题&#xff0c;都是 unity 发包后和 unity Editor 下运行不同&#xff1a;发包后丢失 烘焙效果&#xff0c;一般都是说&#xff1a;shader 中的 Lightma…

【Hive】分隔符 『 单字节分隔符 | 多字节分隔符』

文章目录1. 概述2. 单字节分隔符方法&#xff1a;使用delimited关键字3. 其它复杂情况方式一&#xff1a;写MR程序进行字符替换转为单字节分隔符问题&#xff08;不推荐&#xff09;方式二&#xff1a;自定义InputFormat转为单字节分隔符问题&#xff08;不推荐&#xff09;方式…

矩阵

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 车车的爱之矩阵是一个行数为 n&#xff0c;列数为 m 的矩阵并满足以下条件: 111. 矩阵元素 xij​ 为整数并满足 0<∣xij​∣⩽114514。 222. 对于在矩阵边界的元素&#xff0c;即 iii 为 1 或…

[附源码]Node.js计算机毕业设计非处方药的查询与推荐系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

Flutter - ScrollController 滚动监听及控制

1 ScrollController jumpTo(double offset)、animateTo(double offset,…)&#xff1a;这两个方法用于跳转到指定的位置&#xff0c;它们不同之处在于&#xff0c;后者在跳转时会执行一个动画&#xff0c;而前者不会。 实例 点击按钮返回顶部 ,且按钮在list滑动一定距离后才…

事务·数据库

事务就是一个完整的业务逻辑 举例&#xff1a; a账户转账至b账户&#xff0c;该操作是一个工作单元&#xff0c;要么同时成功要么同时失败&#xff0c;不可再分。 只有DML(INSERT DELETE UPDATE)语句才会有和事务有关系&#xff0c;因为这三个是操作数据库表中数据进行增删改的…

磨金石教育兴趣技能分享||运用好透视规律,就不会为大场面拍摄发愁了

许多摄影初学者&#xff0c;在拍摄简单的单独景物照或人物照时&#xff0c;经过简单的练习往往很快就能得心应手。 当画面稍微大一些&#xff0c;各种景物元素增多&#xff0c;空间立体感变强时&#xff0c;就会不知所措。拍出的照片不协调&#xff0c;而且杂乱。 这时候&…

2.专题. 逻辑层次结构——树

1. 树结构概述 现实生活中&#xff0c;具有很多层次关系&#xff1a;归纳为一种树状结构&#xff08;一种层级结构&#xff09; 2. 二叉树 2.2 二叉树分类 3.1.2.1 满二叉树 高度为4的满二叉树 3.1.2.2 完全二叉树 若一棵二叉树至多只有最下面两层的结点的度数可以小于2…

保护私密文件夹,可以这样设置隐藏起来

很多小伙伴在工作或生活中&#xff0c;都会有一些文件资料&#xff0c;不希望被让人随意看到&#xff0c;想要隐藏起来。其实只需要一个简单的操作&#xff0c;就可以把文件隐藏起来&#xff0c;不让人发现。 首先&#xff0c;我们可以先将需要隐藏的文件都放在一个文件夹里&a…

java常见的遍历

日常遍历的几种方式 首先我们先了解一下集合容器中日常遍历的几种方式&#xff1a; List集合遍历方式&#xff08;ArrayList&#xff09; // 遍历list集合private static void listTest() {List<String> list new ArrayList<String>();list.add("liubei&quo…

【Redis】新增数据结构

BitMap位图 Redis提供了Bitmaps这个“数据类型”可以实现对位的操作&#xff1a; &#xff08;1&#xff09; Bitmaps本身不是一种数据类型&#xff0c; 实际上它就是字符串&#xff08;key-value&#xff09; &#xff0c; 但是它可以对字符串的位进行操作。 &#xff08;2…

操作系统学习笔记_3 管程;死锁;内存

管程 信号量挺琐碎的&#xff0c;而且容易出错&#xff0c;顺序错了都会影响结果。 管程内的数据只有在管程内的过程&#xff08;函数&#xff09;才能访问&#xff1b;一次只允许一个进程进入管程。 monitor 是 java 语法的管程&#xff0c;每次只允许一个进程访问&#xff0…

[附源码]Python计算机毕业设计房屋租赁系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…