【C语言|数据结构】数据结构顺序表

目录

一、数据结构

1.1概念

1.2总结

1.3为什么需要数据结构?

二、顺序表

1.顺序表的概念及结构

1.1线性表

2.顺序表分类

2.1顺序表和数组的区别

2.2顺序表的分类

2.2.1静态顺序表

2.2.1.1概念

2.2.1.2缺陷

2.2.2动态顺序表

三、动态顺序表的实现

3.1新建项目

3.2 SeqList.h

3.3SeqList.c

3.3.1初始化

3.3.2销毁

3.3.3打印

3.3.4扩容

3.3.4.1扩容原则选择

3.3.4.2扩容代码呈现

3.3.5尾插

3.3.6头插

3.3.7尾删

3.3.8头删

3.3.9指定位置之前插入数据

3.3.10指定位置之前删除数据

3.3.11查找

3.3.12 SeqList.c


一、数据结构

1.1概念

  • 数据结构是计算机存储、组织数据的⽅式。
  • 数据结构是指相互之间存在⼀种或多种特定关系的数据元素的集合。数据结构反映数据的内部构成,即数据由那部分构成,以什么⽅式构成,以及数据元素之间呈现的结构。

1.2总结

  • 1)能够存储数据(如顺序表、链表等结构)
  • 2)存储的数据能够⽅便查找

1.3为什么需要数据结构?

  • 程序中如果不对数据进⾏管理,可能会导致数据丢失、操作数据困难、野指针等情况。 通过数据结构,能够有效将数据组织和管理在⼀起。按照我们的⽅式任意对数据进⾏增删改查等操作。
  • 最基础的数据结构:数组。
  • 【思考】有了数组,为什么还要学习其他的数据结构?
  • 假定数组有10个空间,已经使⽤了5个,向数组中插⼊数据步骤: 求数组的⻓度,求数组的有效数据个数,向下标为数据有效个数的位置插⼊数据(注意:这⾥是 否要判断数组是否满了,满了还能继续插⼊吗)..... 假设数据量⾮常庞⼤,频繁的获取数组有效数据个数会影响程序执⾏效率。
  • 结论:最基础的数据结构能够提供的操作已经不能完全满⾜复杂算法实现。

二、顺序表

1.顺序表的概念及结构

1.1线性表
  • 线性表(linear list)是n个具有相同特性的数据元素的有限序列。
  • 线性表是⼀种在实际中⼴泛使 ⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串..
  •  线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。

2.顺序表分类

2.1顺序表和数组的区别
  • 顺序表的底层结构是数组,对数组的封装,实现了常⽤的增删改查等接⼝
2.2顺序表的分类
2.2.1静态顺序表
2.2.1.1概念
  • 使⽤定⻓数组存储元素
2.2.1.2缺陷
  • 空间给少了不够⽤,给多了造成空间浪费

2.2.2动态顺序表

三、动态顺序表的实现

3.1新建项目

3.2 SeqList.h

//C语言
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int SLDataType;//不仅限于int类型 便于后续替换


//动态顺序表
typedef struct SeqList
{
	SLDataType* arr;   //存储数据的底层结构
	int capacity;      //记录顺序表的空间大小
	int size;          //记录顺便当前有效的数据个数

}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);

//指定位置之前插入/删除数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLDataType x);

3.3SeqList.c

3.3.1初始化

void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->capacity = 0;
	ps->size = 0;

}

3.3.2销毁


void SLDestroy(SL* ps)
{
	free(ps->arr);
	ps->arr = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

3.3.3打印

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

3.3.4扩容

3.3.4.1扩容原则选择
  • 一次扩充一个空间:插入一个元素还不会造成空间浪费 ✖ 程序执行效率低下
  • 一次扩充固定个大小的空间(10、100)✖ 小了:造成频繁扩容,会造成程序运行低下;大了:造成空间浪费
  • 成倍数的扩增(1.5倍、2倍)✅相对高效:数据插入的越多,扩容的大小越来越大即插入数据的数量与扩容大小成近似真相关
3.3.4.2扩容代码呈现
  1. 首先判断动态数组的元素个数(size)是否等于容量(capacity)。
  2. 若相等,则需要进行扩容操作。
  3. 计算新的容量大小,如果原容量为0,则新容量为4,否则新容量为原容量的两倍。
  4. 调用realloc函数重新分配内存空间,将原动态数组的元素拷贝到新的内存空间中。
  5. 如果内存分配失败(temp为NULL),则输出错误信息并退出程序。
  6. 如果内存分配成功,则将新的内存空间地址赋值给动态数组指针arr,同时更新容量为新的容量大小。
//扩容
void SLCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* temp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		
		if (temp == NULL)
		{
			perror("realloc fail!");//扩容失败
			exit(1);//退出
		}
		//扩容成功
		ps->arr = temp;
		ps->capacity = newCapacity;

	}

}

3.3.5尾插

//尾插
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);//断言,确保不为空

	//空间不够直接插入
	SLCheckCapacity(ps);

	//空间足够直接插入
	ps->arr[ps->size] = x;
	ps->size++;
}

3.3.6头插


//头插
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);

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


}

3.3.7尾删

//尾删
void SLPopBack(SL* ps)
{
	//顺序表为空
	assert(ps);
	assert(ps->size);

	//顺序表不为空
	ps->size--;
}

3.3.8头删

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

3.3.9指定位置之前插入数据

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

	SLCheckCapacity(ps);

	//pos及之后的数据挪动一位
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];

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

}

3.3.10指定位置之前删除数据

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

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

3.3.11查找

int SLFind(SL* ps, SLDataType x)
{
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1; // 表示未找到
}

3.3.12 SeqList.c

#include"SeqList.h"


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

}

void SLDestroy(SL* ps)
{
	free(ps->arr);
	ps->arr = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

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


//扩容
void SLCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* temp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		
		if (temp == NULL)
		{
			perror("realloc fail!");//扩容失败
			exit(1);//退出
		}
		//扩容成功
		ps->arr = temp;
		ps->capacity = newCapacity;

	}

}

//尾插
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);//断言,确保不为空

	//空间不够直接插入
	SLCheckCapacity(ps);

	//空间足够直接插入
	ps->arr[ps->size] = x;
	ps->size++;
}


//头插
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(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);
	assert(ps->size);

	//顺序表不为空
	ps->size--;
}

//头删
void SLPopFront(SL* ps) 
{
	assert(ps);
	assert(ps->size);
	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->arr);

	SLCheckCapacity(ps);

	//pos及之后的数据挪动一位
	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(ps >= 0 && pos < ps->size);

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

int SLFind(SL* ps, SLDataType x)
{
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1; // 表示未找到
}

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

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

相关文章

Pandas文本数据处理技术指南—从查找到时间序列分析【第66篇—python:文本数据处理】

文章目录 Pandas文本数据处理技术指南引言 1. 查找文本数据2. 替换文本数据3. 拼接文本数据4. 正则表达式操作5. 虚拟变量6. 处理缺失值7. 分割文本数据8. 字符串处理方法9. 文本数据的合并与连接10. 文本数据的排序11. 文本数据的统计分析12. 文本数据的分组与聚合13. 文本数据…

使用Softing edgeConnector模块将云轻松连接到Siemens PLC

一 工业边缘的连接解决方案 云服务提供商 (CSP) 引入了服务和功能&#xff0c;以简化基于云的工业物联网解决方案的实施。Azure Industrial IoT Platform或AWS IoT SiteWise支持标准协议和接口&#xff0c;例如OPC UA或MQTT。但是&#xff0c;如果您希望在典型的旧改项目中连接…

【代理模式】

定义&#xff1a;代理模式是一种结构型设计模式&#xff0c;它允许我们创建一个代理对象&#xff0c;用于控制对另一个对象的访问。 代理对象充当了被代理对象&#xff08;目标对象&#xff09;的代表&#xff0c;与被代理对象实现相同的接口&#xff0c;从而实现对被代理对象…

【PowerShell】修改Windows网络配置的常用命令

PowerShell&#xff08;PS&#xff09;是一种强大的任务自动化和管理框架&#xff0c;具有丰富的命令和语法&#xff0c;可以用于编写脚本来管理Windows操作系统和其他应用程序。它的开放式架构和跨平台支持使得它成为一个灵活和可扩展的工具。 在网络配置方面&#xff0c;Powe…

C++ 日期计算器

日期计算器 概要 Date类的规划Date类的实现Date 构造函数Date 拷贝构造函数~Date 析构函数GetMonthDay 求某年某月的天数operator 赋值操作符重载operator 加等操作符重载operator 加号操作符重载operator- 减等操作符重载operator- 减法操作符重载 &#xff08;日期 - 天数&am…

分享66个行业PPT,总有一款适合您

分享66个行业PPT&#xff0c;总有一款适合您 66个行业PPT下载链接&#xff1a;https://pan.baidu.com/s/1kcUOfR_xtH9CAJC12prcTw?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易。知…

算法学习——华为机考题库3(HJ21 - HJ25)

算法学习——华为机考题库3&#xff08;HJ21 - HJ30&#xff09; HJ21 简单密码 描述 现在有一种密码变换算法。 九键手机键盘上的数字与字母的对应&#xff1a; 1–1&#xff0c; abc–2, def–3, ghi–4, jkl–5, mno–6, pqrs–7, tuv–8 wxyz–9, 0–0&#xff0c;把密码…

Swift Combine 发布者订阅者操作者 从入门到精通二

Combine 系列 Swift Combine 从入门到精通一 1. Combine核心概念 你只需要了解几个核心概念&#xff0c;就能使用好 Combine&#xff0c;但理解它们非常重要。 这些概念中的每一个都通过通用协议反映在框架中&#xff0c;以将概念转化为预期的功能。 这些核心概念是&#x…

Cocos creator 3.x 刚体组件碰撞无效

Cocos creator 3.x 刚体组件碰撞无效 问题描述&#xff1a;只有一个circleCollider2D时&#xff0c;可以在碰撞时正确输出结果&#xff0c;但是当我在外围加了一个circle之后&#xff0c;期望character进入圆圈范围时就触发方法&#xff0c;此时原代码失效 import { _decorat…

简单说网络:TCP+UDP

TCP和UPD: (1)都工作在传输层 (2)目的都是在程序之中传输数据 (3)数据可以是文本、视频或者图片(对TCP和UDP来说都是一堆二进制数没有太大区别) 一、区别:一个基于连接一个基于非连接 将人与人之间的通信比喻为进程和进程之前的通信:基本上有两种方式(1)写信;(2)打电话;这…

【51单片机】实现一个动静态数码管显示项目(前置知识铺垫,代码&图演示)(5)

前言 大家好吖&#xff0c;欢迎来到 YY 滴单片机 系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过单片机的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY…

Redis的数据类型Hash使用场景实战

Redis的数据类型Hash使用场景 常见面试题&#xff1a;redis在你们项目中是怎么用的&#xff0c;除了String数据类型还使用什么数据类型&#xff1f; 怎么保证缓存和数据一致性等问题… Hash模型使用场景 知识回顾&#xff1a; redisTemplate.opsForHash() 方法是 Redis 的 …

QAnything之BCEmbedding技术路线

QAnything和BCEmbedding简介 QAnything[github]是网易有道开源的检索增强生成式应用&#xff08;RAG&#xff09;项目&#xff0c;在有道许多商业产品实践中已经积累丰富的经验&#xff0c;比如有道速读和有道翻译。QAnything是一个支持任意格式文件或数据库的本地知识库问答系…

python的数据类型

&#x1f388;srting&#xff08;字符串&#xff09;&#xff1a; 操作符&#xff1a; &#xff1a;字符串连接 aabc befg print(ab) #输出 abcdefg * : 重复输出字符串 aabc print(a*3) #输出 abcabcabc [ : ]:截取字符串中的一部分&#xff0c;遵循左闭右开的原则&am…

vue实现购物车案例

话不多说&#xff0c;先上效果图。 安装elementui组件库&#xff0c;可直接食用。 <template><div><!-- 购物车部分 --><el-container><el-header><h1>购物车案例一条龙</h1></el-header><el-main><!-- 折叠面板…

springboot Feign方式注入注解详解

一、FeignClient注解详解 FeignClient是Spring Cloud中用于声明Feign客户端的注解&#xff0c;它使得编写HTTP客户端变得更简单。通过Feign的自动化配置机制&#xff0c;可以很容易地编写HTTP API客户端。以下是FeignClient的详解&#xff1a; 作用&#xff1a;FeignClient注解…

龙年立 Flag,Whale 帷幄 2024 的五大关键词

回顾 2023&#xff0c;AIGC 浪潮的出现&#xff0c;为各行各业带来了更多的商业可能性。在农历新年到来之际&#xff0c;我们也展望 2024&#xff0c;为打好新的硬仗做好充分的准备。 以下 5 大关键词即是「Whale 帷幄」接下来努力的方向和目标。 「盈利」 在 2024 年&#xff…

骨传导运动蓝牙耳机哪个好?五款性价比骨传导运动蓝牙耳机推荐

近两年来&#xff0c;骨传导运动蓝牙耳机在运动领域内日益流行。与传统耳机相比&#xff0c;它的显著优势是能够保持双耳开放&#xff0c;不会堵塞耳道&#xff0c;消除了入耳式耳机可能引起的不适感。此外还能避免运动时耳内出汗可能导致的各种卫生和健康问题。很多人就问了&a…

pmp报考的条件以及考试内容有分享一下的吗?

PMP 是项目管理的入门级证书&#xff0c;全称是项目管理专业人士资格认证&#xff0c;由美国项目管理协会&#xff08;PMI&#xff09;举办的&#xff0c;受到全球200多个国家的认可&#xff0c;从1999 年到现在已经有20多年发展历史了。 顾名思义&#xff0c;PMP考试就是一场…
最新文章