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

完!!!

相关推荐
矛取矛求4 分钟前
QT的前景与互联网岗位发展
开发语言·qt
Leventure_轩先生4 分钟前
[WASAPI]从Qt MultipleMedia来看WASAPI
开发语言·qt
向宇it18 分钟前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎
是娜个二叉树!35 分钟前
图像处理基础 | 格式转换.rgb转.jpg 灰度图 python
开发语言·python
KpLn_HJL36 分钟前
leetcode - 2139. Minimum Moves to Reach Target Score
java·数据结构·leetcode
Schwertlilien38 分钟前
图像处理-Ch5-图像复原与重建
c语言·开发语言·机器学习
liuyunshengsir41 分钟前
Squid代理服务器的安装使用
开发语言·php
只做开心事1 小时前
C++之红黑树模拟实现
开发语言·c++
很楠不爱1 小时前
项目实战——高并发内存池
开发语言·项目实战
程序员buddha2 小时前
C语言从入门到放弃教程
c语言·开发语言