数据结构 手撕顺序表(动态版)+代码详解

news2024/12/26 12:21:08

⭐️ 顺序表介绍

顺序表是线性表的一种。

🌠什么是线性表呢?

线性表是数据结构的一种,一个线性表是 n n n个具有相同特性的数据元素的有限序列。常见的线性表:顺序表、链表、栈、队列、字符串…

🌠什么是顺序表呢?

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。顺序表与数组的不同点是:数组可以任意的放入元素,不管元素与元素之间是否连续。而顺序表不仅物理地址连续,元素与元素之间也要连续存放。

图1:
在这里插入图片描述
而顺序表又分为:静态顺序表动态顺序表

  1. 静态顺序表:使用长度固定的数组存储元素。
    • 缺陷: (不推荐)长度不自由,当长度给的太大而数据较少时,浪费空间。长度太小,而数据较多,数据又放不下。
    • 类型定义:
// 顺序表默认大小
#define SequenceListSize 100
// 顺序表数据的类型
typedef int SequenceListType;
// 顺序表结构
typedef struct SequenceList {
	SequenceListType data[SequenceListSize]; // 顺序表数据的类型的数组
	int size;	// 数据表当前的大小
}SequenceList;

  1. 动态顺序表:(推荐)第一次初始化后,可根据数据多少动态的分配空间大小。
    • 类型定义:
// 顺序表数据的类型
typedef int SequenceListType;
// 顺序表结构
typedef struct SequenceList {
	SequenceListType* data;	// 顺序表数据的类型的指针
	int size;	// 数据表当前的大小
	int capacity;	// 数据表的容量
}SequenceList;


⭐️ 手撕顺序表(动态版)

🌠 顺序表的类型声明:

// 使用到的头文件
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

// 顺序表数据的类型
typedef int SequenceListType;
// 顺序表结构
typedef struct SequenceList {
	SequenceListType* data;	// 顺序表数据的类型的指针
	int size;	// 数据表当前的大小
	int capacity;	// 数据表的容量
}SequenceList;

typedef int SequenceListType; 顺序表的类型不能写死,因为管理的数据可以是任意类型 charintdouble...,所以这里使用 typedef 声明出一个顺序表类型,方便后期修改。

🌠 顺序表的接口实现

⭕️ 初始化顺序表:

声明:

void SequenceListInit(SequenceList * ps);

代码实现:

void SequenceListInit(SequenceList* ps) {
	assert(ps != NULL);

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

⭕️ 顺序表检查是否增容:

声明:

void SequenceListCheckCapacity(SequenceList* ps);

代码实现:

void SequenceListCheckCapacity(SequenceList* ps) {
	assert(ps != NULL);

	if (ps->size == ps->capacity) {
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SequenceListType* newData = (SequenceListType*)realloc(ps->data , newCapacity * sizeof(SequenceListType));
		if (newData == NULL) {
			perror("SequenceListCheckCapacity_Function_realloc:");
			exit(-1);
		}
		ps->data = newData;
		ps->capacity = newCapacity;
	}
}

✨往期文章:C语言动态开辟内存函数的使用。

⭕️ 顺序表尾插:

声明:

void SequenceListPushBack(SequenceList* ps , SequenceListType node);

代码实现:

void SequenceListPushBack(SequenceList* ps, SequenceListType node) {
	assert(ps != NULL);

	// 检查容量
	SequenceListCheckCapacity(ps);

	ps->data[ps->size] = node;
	ps->size++;
}

⭕️ 顺序表尾删:

声明:

void SequenceListPopBack(SequenceList* ps);

代码实现:

void SequenceListPopBack(SequenceList* ps) {
	assert(ps != NULL);

	// 检查顺序表不为空
	assert(ps->size > 0);

	ps->size--;
}

⭕️ 顺序表头插:

声明:

void SequenceListPushFront(SequenceList* ps , SequenceListType node);

代码实现:

void SequenceListPushFront(SequenceList* ps, SequenceListType node) {
	assert(ps != NULL);

	// 检查容量
	SequenceListCheckCapacity(ps);

	// 从尾部向后挪动数据 也可以使用memmove()
	for (int end = ps->size - 1; end >= 0; end--) {
		ps->data[end + 1] = ps->data[end];
	}

	ps->data[0] = node;
	ps->size++;

}

⭕️ 顺序表头删:

声明:

void SequenceListPopFront(SequenceList* ps);

代码实现:

void SequenceListPopFront(SequenceList* ps) {
	assert(ps != NULL);

	// 检查顺序表不为空
	assert(ps->size > 0);

	for (int start = 1; start < ps->size; start++) {
		ps->data[start - 1] = ps->data[start];
	}

	ps->size--;
}

⭕️ 顺序表在某一位置插入:

声明:

void SequenceListInsert(SequenceList* ps , int pos , SequenceListType node);

代码实现:

void SequenceListInsert(SequenceList* ps, int pos, SequenceListType node) {
	assert(ps != NULL);

	// 检查插入顺序表元素边界
	assert(pos >= 0 && pos <= ps->size);

	// 检查增容
	SequenceListCheckCapacity(ps);

	for (int end = ps->size - 1; end >= pos; end--) {
		ps->data[end + 1] = ps->data[end];
	}

	ps->data[pos] = node;
	ps->size++;
}

注: 当有了 Insert 函数,顺序表的 PushBackPushFront 就可以复用 Insert 接口。

void SequenceListPushBack(SequenceList* ps, SequenceListType node) {
	// 复用
	SequenceListInsert(ps , ps->size , node);
}

void SequenceListPushFront(SequenceList* ps, SequenceListType node) {
	// 复用
	 SequenceListInsert(ps , 0 , node);
}

⭕️ 顺序表在某一位置删除:

声明:

void SequenceListErase(SequenceList* ps , int pos);

代码实现:

void SequenceListErase(SequenceList* ps, int pos) {
	assert(ps);

	// 检查删除顺序表元素边界
	assert(pos >= 0 && pos < ps->size);

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

	ps->size--;

}

注: 当有了 Erase 函数,顺序表的 PopBackPopFront 就可以复用 Erase 接口。

void SequenceListPopBack(SequenceList* ps) {
	// 复用
	SequenceListErase(ps , ps->size - 1);
}

void SequenceListPopFront(SequenceList* ps) {
	// 复用
	 SequenceListErase(ps , 0);
}

结论: 如果想要在短时间内实现一个顺序表,只需要实现 InsertErase 函数,PushBackPushFrontPopBackPopFront 只需要复用这两个接口即可。

⭕️ 顺序表查找元素:

声明:

int SequenceListFind(SequenceList* ps ,  SequenceListType node);

代码实现:

int SequenceListFind(SequenceList* ps, SequenceListType node) {
	assert(ps);

	for (int i = 0; i < ps->size; i++) {
		if (ps->data[i] == node) {
			return i;
		}
	}

	return -1;
}

⭕️ 顺序表修改元素:

声明:

void SequenceListModify(SequenceList* ps , int pos , SequenceListType node);

代码实现:

void SequenceListModify(SequenceList* ps, int pos, SequenceListType node) {
	assert(ps != NULL);

	// 检查pos范围
	assert(pos >= 0 && pos < ps->size);

	ps->data[pos] = node;
}

⭕️ 顺序表打印元素:

声明:

void SequenceListPrint(SequenceList* ps);

代码实现:

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

⭕️ 顺序表销毁:

声明:

void SequenceListDestroy(SequenceList* ps);

代码实现:

void SequenceListDestroy(SequenceList* ps) {
	assert(ps);

	if (ps->data != NULL) {
		free(ps->data);
		ps->data = NULL;
		ps->capacity = ps->size = 0;
	}
}

数据结构和算法的概念以及时间复杂度空间复杂度详解。
C语言动态开辟内存函数的使用。
leetcode189.轮转数组。

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

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

相关文章

Docker + Wasm = 王炸!!!

Docker 宣布推出与 WebAssembly 集成 (DockerWasm) 的首个技术预览版&#xff0c;并表示公司已加入字节码联盟 (Bytecode Alliance)&#xff0c;成为投票成员。 Bytecode Alliance&#xff08;字节码联盟&#xff09;由 Mozilla、Fastly、Intel 与 Red Hat 联合成立&#xff0c…

Redis的优化(二)

Redis的高可用 一、主从复制优化主从复制的作用主从复制流程主从复制实验 二、Redis 哨兵模式哨兵模式的作用故障转移机制主节点的选举原则哨兵模式的实验 三、Redis群集模式集群的作用Redis集群的数据分片搭建Redis群集模式实验 ●主从复制&#xff1a;主从复制是高可用Redis的…

路由协议基本术语

文章目录 1、自治系统AS2、EGP和IGP3、度量标准和度量值4、管理距离5、路由协议与路由算法6、路由环路问题 1、自治系统AS Internet中&#xff0c;自治系统就是处于同一个管理机构&#xff08;如一个ISP&#xff09;控制下的路由器和网络群组 在同一个自治系统中的所有路由器…

Python3 标准库概览 | 菜鸟教程(十八)

目录 一、Python3 标准库中的模块 &#xff08;一&#xff09;os 模块 &#xff08;二&#xff09;sys 模块 &#xff08;三&#xff09;time 模块 &#xff08;四&#xff09;datetime 模块 &#xff08;五&#xff09;random 模块 &#xff08;六&#xff09;math 模块…

RabbitMQ笔记(持续更新中~)

1.消息队列 1.1 MQ的相关概念 1.1.1 什么是MQ MQ&#xff08;message queue&#xff09;&#xff0c;从字面上看&#xff0c;本质是个队列&#xff0c;FIFO先进先出&#xff0c;只不过队列中存放的内容是消息而已&#xff0c;还是一种跨进程的通信机制&#xff0c;用于上下游…

Pandas之Series(一)

Hi&#x1f60a;&#x1f60a;~大家好呀~最近两天釉色酱在学习python中的数据分析的一个基本库——pandas。今天就先学习pandas中最基本的数据结构Series。下面我们一起进入Series的世界吧&#xff01;&#x1f61d; Pandas简介&#xff1a; Pandas是一种基于Python语言的快速…

sklearn.model_selection模块介绍

数据集划分方法 train_test_split train_test_split(*arrays, test_sizeNone, train_sizeNone, random_stateNone, shuffleTrue, stratifyNone)参数包括&#xff1a; test_size&#xff1a;可选参数&#xff0c;表示测试集的大小。可以是一个表示比例的浮点数&#xff08;例…

Android:ViewPager2

简介 ViewPager2内部使用RecyclerView实现&#xff0c;并提供了增强功能 特性 支持水平、垂直方向布局 android:orientation “vertical” 支持从右到左 android:layoutDirection “rtl” 禁止滑动 setUserInputEnabled() 可修改Fragment集合 对可修改的Fragment集合进行分…

深入探究Bean生命周期的扩展点:Bean Post Processor

概要 在Spring框架中&#xff0c;Bean生命周期的管理是非常重要的一部分。在Bean的创建、初始化和销毁过程中&#xff0c;Spring提供了一系列的扩展点&#xff0c;使开发者能够在不破坏原有功能的基础上&#xff0c;对Bean的生命周期进行定制化操作。其中&#xff0c;Bean Post…

LLM记录202304-202306

RLHF RAFT RAFT: Reward rAnked FineTuning for Generative Foundation Model Alignment code RRHF RRHF: Rank Responses to Align Language Models with Human Feedback without tears code p i = ∑ t lo

English Learning - L3 作业打卡 Lesson7 Day53 2023.6.28 周三

English Learning - L3 作业打卡 Lesson7 Day53 2023.6.28 周三 引言&#x1f349;句1: It was this moment that I asked myself that life-defining question:成分划分同化连读爆破语调 &#x1f349;句2: If my life were a book and I were the author, how would I want t…

基于Web的小学学科数字教学资源管理系统

摘要 小学学科数字教学资源管理是一个典型的学习项目&#xff0c;从教学资源、教材信息的统计和分析&#xff0c;在过程中会产生大量的、各种各样的数据。本文以小学学科数字教学资源管理系统为目标&#xff0c;采用B/S模式&#xff0c;以Springboot为开发框架&#xff0c;java…

计算机网络面经之TCP三次握手和四次挥手的详解

常见问题 1.详细描述三次握手和四次挥手的过程。 2.三次握手可以变成两次握手吗&#xff1f; 3.简述 TCP 连接和关闭的状态转移。 4.简述TCP 四次挥手的 TIME_WAIT状态&#xff0c;以及为什么需要有这个状态 重要的字段定义与作用 &#xff08;1&#xff09;序号(sequence nu…

循环双链表

目录 双向循环链表结构体初始化函数添加数据头插删除数据显示函数示例程序一(简易版本)&#xff1a;运行结果&#xff1a;示例程序二输出结果&#xff1a; 双向循环链表 结构图示&#xff1a; 结构体 typedef struct node {int data;struct node* pre; //指向前驱struct …

C++迭代器

目录 1.iterator 2.数组 1.iterator 迭代器就是个内置指针&#xff0c;可以 -- &#xff0c;可以解引用。 迭代器分两种类型 iterator 和const_iterator&#xff08;只读&#xff0c;不能修改&#xff09; 迭代器要用作用域限定类型 vector<int>::iterator it; 如果不限制…

Yarn的实现原理详解

概要 Yarn作为分布式集群的资源调度框架&#xff0c;它的出现伴随着Hadoop的发展&#xff0c;使Hadoop从一个单一的大数据计算引擎&#xff0c;成为一个集存储、计算、资源管理为一体的完整大数据平台&#xff0c;进而发展出自己的生态体系&#xff0c;成为大数据的代名词。 Ya…

C++11新特性 智能指针

智能指针 nuique_ptr特点不允许拷贝构造和赋值运算符重载-> () *unique_ptr 删除器仿写删除文件删除普通对象 shared_ptr特点示意图仿写shared_ptr删除器部分特化拷贝构造 移动构造 && 左值赋值 和移动赋值完整实现 weak_ptr特点weak_ptr 实现解决循环引用弱指针一个…

java: 警告: 源发行版 11 需要目标发行版 11解决方案

出现这样的问题首先检查一下自己的项目结构是否使用的对应的jdk 如果这里是正确的&#xff0c;之后查看一下自己的pom文件中是否指定了正确的jdk 这里的时候你改完运行就会发现还会报错&#xff0c;一定要记得刷新一下maven 再重新启动项目&#xff0c;即解决

剑指 Offer 63: 股票的最大利润

最标准答案 不可以有前一项的影响&#xff0c;只能用来对比并不叠加 这里max设置0就会导致先行进入大于max的判断语句&#xff01; 无语了&#xff0c;自己把问题想的太复杂了&#xff01; class Solution {public int maxProfit(int[] prices) {if(prices.length<2) retur…

十二个常用化学文献检索网站

一、Royal Society of Chemistry英国皇家化学学会 英国皇家化学学会&#xff08;Royal Society of Chemistry&#xff0c;简称RSC&#xff09;&#xff0c;是一个国际权威的学术机构&#xff0c;是化学信息的一个主要传播机构和出版商&#xff0c;其出版的期刊及资料库一向是化…