【C++】数据结构 顺序表的实现(详解)

本篇博客给大家带来的是用C++语言来实现数据结构的顺序表

🐟🐟文章专栏:C++

🚀🚀若有问题评论区下讨论,我会及时回答

❤❤欢迎大家点赞、收藏、分享

你们的支持就是我创造的动力

今日思想:如果你不能承受孤独,就不要追逐梦想!

一、线性表

在说顺序表之前我们先聊聊线性表,为什么呢??举个例子:苹果和菠萝统称水果。而线性表就是就是顺序表和单链表等的统称。

线性表在逻辑结构(想象出来的数据在内存存储的地址是连续的)是线性的,物理结构(数据在内存存储的地址)不一定是线性的。

二、顺序表

顺序表是线性表的一种,它在逻辑结构是线性的,物理结构也是线性的。

顺序表的底层是数组,说到底跟数组差不多,只是加了一点东西罢了。

顺序表也分为静态顺序表(内存的大小固定)和动态顺序表(内存的大小可以变化)。

1、静态顺序表

静态顺序表是使用数组来存储数据,但是数组的大小固定了,如果存储用户的数据满了,无法及时调整数组的大小,导致丢失用户数据,给企业带来巨大的损失。

代码实例:

cpp 复制代码
typedef int SLDatatype;//用户的数据的类型不一样,所以重命名方便程序员根据用户数据的类型来修改
#define M 20 //数组的大小固定
struct SqeList
{
	SLDatatype arr[M];//使用数组来存储用户的数据
	int size;//有效数据个数(有多少个用户的数据,不是每个内存都存储着用户的数据)
};

缺陷:空间给少了不够用,给多了浪费空间。

2、动态顺序表

实现动态实现我们要在VS上编辑三个文件(SeqList.h、SeqList.c、test.c)。

我们在头文件上声明动态顺序表的基本形式:

cpp 复制代码
//SeqList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//顺序表的结构
typedef int SLDataType;
typedef struct SqeList
{
	SLDataType* arr;
	int size;//有效数据个数
	int capacity;//空间大小
}SL;

那么怎么存储用户的数据呢??

在这里有6种存储用户数据的方法:尾插、头插、尾删、头删、指定位置之前插入数据、指定位置删除数据。

在实现这些方法之前我们要对这个进行结构体初始化。

①动态顺序表的初始化

代码实例:

cpp 复制代码
//SeqList.h
//初始化
void SLInit(SL* ps);
cpp 复制代码
//SqeList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
//初始化
void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

②尾插

无论是什么方法只要关于插入数据的都要坚查是否存满了数据,如果存满了那就在原来数组大小乘以2倍。

代码实例:

cpp 复制代码
//SeqList.h
void SLcheckCapacity(SL* ps);

怎么判断用户的数据存满了呢??

如果有效数据个数等于空间大小,那么用户的数据存满了

满了之后我们要扩容

但是由于realloc有可能申请空间失败返回NULL,所以要用临时变量来接受一下,再来判断是否申请空间失败。

cpp 复制代码
//SeqList.c
void SLcheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)//空间满了
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

尾插的实现

代码实例:

cpp 复制代码
//SeqList.h
void SLPushBack(SL* ps, SLDataType x);

图片解疑: 假设我们存储了6个用户数据,空间大小为8,那么尾插就是在size这个位置插入数据,然后size++就行。

cpp 复制代码
//SeqList.c
//尾插
void SLPushBack(SL* ps, SLDataType x)
{
	SLcheckCapacity(ps);
	ps->arr[ps->size++] = x;
}

③头插

代码实例:

cpp 复制代码
//SeqList.h
//头插
void SLPushFront(SL* ps, SLDataType x);

图片解疑:

头插就是在下标为0的位置插入数据,这时我们在令i=size,把 i 和 i-1的位置的数据用个循环来前面的数据整体移动,这时候下标为0的位置没有数据,再把数据插入进去就行,这时size要加一。

cpp 复制代码
//SqeList.c
//头插
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;
}

④尾删

代码实例:

cpp 复制代码
//SeqList.h
//尾删
void SLPopBack(SL* ps);

图片解疑:

尾删不是让下标为5的位置的数据置为0(假如用户存储的数据就是0),我们只要size--指向下标为5的数据就行了。用尾插例子,尾插这时就是在下标为5的位置插入数据就行(插入的数据会覆盖原来的数据)。

cpp 复制代码
//SeqList.c
//尾删
void SLPopBack(SL* ps)
{
	assert(ps->size);
	--ps->size;
}

⑤头删

代码实例:

cpp 复制代码
//SeqList.h
//头删
void SLPopFront(SL* ps);

图片解疑:

头删我们只要用个循环把下标为0的后面的数据整体移动覆盖下标为0的数据就行,然后size--。

cpp 复制代码
//SeqList.c
//头删
void SLPopFront(SL* ps)
{
	assert(ps && ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	--ps->size;
}

⑥指定之前位置插入数据

代码实例:

cpp 复制代码
//SeqList.h
//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x);

图片解疑:

指定位置之前插入数据是:举个例子我们要在下标为2的位置插入数据,那么我们用个循环把下标为2的数据和后面的数据整体移动,把下标为2的位置的数据空出来然后再在要插入的数据放到下标为2的空间上,然后size要加一。

cpp 复制代码
//SqeList.c
//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(pos >= 0 && pos <= ps->size);
	SLcheckCapacity(ps);
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	++ps->size;
}

⑦指定位置删除数据

代码实例:

cpp 复制代码
//SeqList.h
//指定位置删除数据
void SLErase(SL* ps, int pos);

图片解疑:

假设我们要把下标为3的数据删除掉,那么我们可以让i = 3,然后用个循环把i = 3的数据覆盖掉,然后size要减一。

cpp 复制代码
//SeqList.c
//指定位置删除数据
void SLErase(SL* ps, int pos)
{
	assert(ps && ps->size);
	assert(pos >= 0 && pos <= ps->size);

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

三、福利:

1、用户查找数据的方法

代码实例:

cpp 复制代码
//SeqList.h
//查找
//找到了,就返回下标,未找到,返回-1;
int SLFind(SL* ps, SLDataType x);

遍历数组内容就行。

cpp 复制代码
//SeqList.c
int SLFind(SL* ps, SLDataType x)
{
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	//未找到
	return -1;

}

2、动态顺序表的销毁

代码实例:

cpp 复制代码
//SeqList.h
void SLDesTroy(SL* ps);
cpp 复制代码
//SeqList.c
//销毁
void SLDesTroy(SL* ps)
{
	if (ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

完!!!

相关推荐
sxtyjty2 分钟前
tarjan缩点+强联通分量
算法
freyazzr2 分钟前
Leetcode刷题 | Day50_图论02_岛屿问题01_dfs两种方法+bfs一种方法
数据结构·c++·算法·leetcode·深度优先·图论·广度优先
悦悦子a啊4 分钟前
C++之string
开发语言·数据结构·c++
我想进大厂5 分钟前
图论---LCA(倍增法)
数据结构·c++·算法·图论
明月看潮生17 分钟前
青少年编程与数学 02-018 C++数据结构与算法 16课题、贪心算法
c++·算法·青少年编程·贪心算法·编程与数学
赛卡19 分钟前
IPOF方法学应用案例:动态电压频率调整(DVFS)在AIoT芯片中的应用
开发语言·人工智能·python·硬件工程·软件工程·系统工程·ipof
机器学习之心34 分钟前
飞蛾扑火算法优化+Transformer四模型回归打包(内含MFO-Transformer-LSTM及单独模型)
算法·回归·lstm·transformer·飞蛾扑火算法优化
网络大镖客36 分钟前
JavaScript高级进阶(五)
开发语言·前端·javascript
API小爬虫1 小时前
利用 Python 爬虫按关键字搜索 1688 商品详情:实战指南
开发语言·爬虫·python
不当菜虚困1 小时前
JAVA设计模式——(九)工厂模式
java·开发语言·设计模式