【C/C++】静态顺序表详解(附完整源码)

news/2024/11/15 5:44:30/

本章内容

1.什么是线性表

2.什么是顺序表 

3.静态顺序表结构的定义

4.静态顺序表的函数接口实现

5.静态顺序表的问题及思考


1.什么是线性表

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

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

2.什么是顺序表 

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

顺序表一般可以分为:

1.静态顺序表:使用定长数组存储元素。

2.动态顺序表:使用动态开辟的数组存储元素。

3.静态顺序表结构的定义

#define N 100
typedef int SLDataType;//静态顺序表
typedef struct SeqList
{SLDataType a[N];//定长数组int size;//记录存储多少个有效数据
}SeqList;

4.静态顺序表的函数接口实现

//初始化顺序表
void SLInit(SeqList* ps);
//静态顺序表的尾插
void SLPushBack(SeqList* ps,SLDataType data);
//静态顺序表的尾删
void SLPopBack(SeqList* ps);
//静态顺序表的头插
void SLPushFront(SeqList* ps,SLDataType data);
//静态顺序表的头删
void SLPopFront(SeqList* ps);
//pos位置插入数据
void SLInsert(SeqList* ps, int pos, SLDataType data);
//pos位置插入数据
void SLErase(SeqList* ps,int pos);
//查找数据
int SLFind(SeqList* ps, SLDataType data, int begin);
//判断数组是否已满
bool IsFull(SeqList* ps);
//打印存储的数据
void SLPrint(SeqList* ps);

以下是函数接口的实现:

void SLInit(SeqList* ps)
{assert(ps);ps->size = 0;
}
bool IsFull(SeqList* ps)
{assert(ps);if (ps->size == N){return true;}else{return false;}
}
void SLPushBack(SeqList* ps,SLDataType data)
{assert(ps);assert(!IsFull(ps));//插入数据ps->a[ps->size] = data;ps->size++;
}
void SLPopBack(SeqList* ps)
{assert(ps);ps->size--;
}
void SLPushFront(SeqList* ps, SLDataType data)
{assert(ps);assert(!IsFull(ps));//挪动数据for (int i = ps->size - 1; i >= 0; i--){ps->a[i + 1] = ps->a[i];}//插入数据ps->a[0] = data;ps->size++;
}
void SLPopFront(SeqList* ps)
{assert(ps);assert(ps->size > 0);//挪动数据for (int i = 0; i < ps->size-1; i++){ps->a[i] = ps->a[i + 1];}ps->size--;
}
void SLInsert(SeqList* ps, int pos, SLDataType data)
{assert(ps);assert(!IsFull(ps));//挪动数据for (int i = ps->size-1; i >= pos; i--){ps->a[i + 1] = ps->a[i];}//插入数据ps->a[pos] = data;ps->size++;
}
void SLErase(SeqList* ps, int pos)
{assert(ps);assert(ps->size > 0);//挪动数据for (int i = pos; i < ps->size - 1; i++){ps->a[i] = ps->a[i + 1];}ps->size--;
}
int SLFind(SeqList* ps, SLDataType data, int begin)
{assert(ps);assert(begin < ps->size);for (int i = begin; i < ps->size; i++){if (ps->a[i] == data){return i;}}return -1;
}
void SLPrint(SeqList* ps)
{assert(ps);for (int i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");
}

5.静态顺序表的问题及思考

1.静态顺序表的局限性

静态顺序表只适用于确定知道需要存多少数据的场景。如果数据量未知,N的值太大,造成空间浪费;N的值太小,数据存储不下。

2.接口函数的参数为什么要用结构体指针?

因为尾插、尾删与初始化需要改变结构的内容,若不用结构体指针,形参的改变无法影响实参,则导致无法完成任务;剩下的两个是为了统一与美观。

3.顺序表增删查改的时间复杂度

①顺序表的优势

顺序表的优势是尾插与尾删,为什么呢?

顺序表底层逻辑结构与数组相同,都是在内存上取一连串连续的空间来存储数据。既然这些空间是连续的,那么就意味着我们只需要记住这一连串空间的起始位置,若需要访问与起始位置只相差距离为5的位置时,我们只要在起始位置的地址上加5就可以一步到位。

尾插与尾删最重要的一步就是如何找到尾巴。然而数组几乎可以一步做到这一点,我们知道数组的起始位置,而且用size记录着数组有效长度,那么找尾可以说是及其简单,一步到位。

所以顺序表的尾插与尾删时间复杂度为O(1)。

②顺序表的劣势

与尾插尾删相比,顺序表最大的劣势就是头插与头删。

数组的空间开辟好之后,数组的起始位置已经固定了。我们不能想着将起始位置往前挪一格,然后留出来一个空位置进行插入;同样的也不能将起始位置往后挪一个就完成头删。

正确的头插与头删:

头插:从索引为0的位置开始,将所有数据向后平移一格,然后插入数据。

头删:从索引为1的位置开始,将所有数据向前平移一格,此时索引为0的位置的数据被索引为1的位置的数据覆盖掉了。

头插与头删关键的步骤是平移数据,因此头插与头删的时间复杂度为O(N)。

有关于数组更多详细的讲解,请参考这篇文章:

数据结构为何重要(数组)icon-default.png?t=MBR7http://t.csdn.cn/NB1Uw


6.完整源码

SeqList.h文件

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#define N 5
typedef int SLDataType;//静态顺序表
typedef struct SeqList
{SLDataType a[N];//定长数组int size;//记录存储多少个有效数据
}SeqList;//初始化顺序表
void SLInit(SeqList* ps);
//静态顺序表的尾插
void SLPushBack(SeqList* ps,SLDataType data);
//静态顺序表的尾删
void SLPopBack(SeqList* ps);
//静态顺序表的头插
void SLPushFront(SeqList* ps,SLDataType data);
//静态顺序表的头删
void SLPopFront(SeqList* ps);
//pos位置插入数据
void SLInsert(SeqList* ps, int pos, SLDataType data);
//pos位置插入数据
void SLErase(SeqList* ps,int pos);
//查找数据
int SLFind(SeqList* ps, SLDataType data, int begin);
//判断数组是否已满
bool IsFull(SeqList* ps);
//打印存储的数据
void SLPrint(SeqList* ps);

SeqList.c文件

#define _CRT_SECURE_NO_DEPRECATE 1
#include"SeqList.h"void SLInit(SeqList* ps)
{assert(ps);ps->size = 0;
}void SLPushBack(SeqList* ps,SLDataType data)
{assert(ps);assert(!IsFull(ps));//插入数据ps->a[ps->size] = data;ps->size++;
}void SLPopBack(SeqList* ps)
{assert(ps);ps->size--;
}void SLPushFront(SeqList* ps, SLDataType data)
{assert(ps);assert(!IsFull(ps));//挪动数据for (int i = ps->size - 1; i >= 0; i--){ps->a[i + 1] = ps->a[i];}//插入数据ps->a[0] = data;ps->size++;
}void SLPopFront(SeqList* ps)
{assert(ps);assert(ps->size > 0);//挪动数据for (int i = 0; i < ps->size-1; i++){ps->a[i] = ps->a[i + 1];}ps->size--;
}void SLInsert(SeqList* ps, int pos, SLDataType data)
{assert(ps);assert(!IsFull(ps));//挪动数据for (int i = ps->size-1; i >= pos; i--){ps->a[i + 1] = ps->a[i];}//插入数据ps->a[pos] = data;ps->size++;
}void SLErase(SeqList* ps, int pos)
{assert(ps);assert(ps->size > 0);//挪动数据for (int i = pos; i < ps->size - 1; i++){ps->a[i] = ps->a[i + 1];}ps->size--;
}int SLFind(SeqList* ps, SLDataType data, int begin)
{assert(ps);assert(begin < ps->size);for (int i = begin; i < ps->size; i++){if (ps->a[i] == data){return i;}}return -1;
}void SLPrint(SeqList* ps)
{assert(ps);for (int i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");
}bool IsFull(SeqList* ps)
{assert(ps);if (ps->size == N){return true;}else{return false;}
}


http://www.ppmy.cn/news/11552.html

相关文章

Mybatis-plus(上)

1.什么是mybatis-plus升级版的mybatis&#xff0c;目的是让mybatis更易于使用&#xff0c; 用官方的话说“为简化而生”官网&#xff1a;https://baomidou.com/初体验按照官网中的快速开始即可1.准备数据库脚本数据库 Schema 脚本如下&#xff1a; DROP TABLE IF EXISTS user; …

pytest-pytest插件之测试覆盖率pytest-cov

简介 测试覆盖率是指项目代码被测试用例覆盖的百分比&#xff0c;使用pytest-cov插件可以统计测试覆盖率 添加链接描述 安装插件pytest-cov pip install pytest-cov用法 基本用法 –cov的参数是要统计代码覆盖率的源码&#xff0c;我将源码放在mysrc中&#xff0c;test_s…

Kotlin的lateinit和by lazy的区别

一、lateinit1.lateinit的使用由于kotlin有严格的语法要求变量需要声明是否可以为null&#xff0c;但由于在实际的业务场景中&#xff0c;这个变量必须在某些时候才能做初始化操作&#xff0c;并且这个变量肯定不为null&#xff0c;如果为null&#xff0c;就是逻辑有问题了。这…

xilinx srio ip学习笔记之再识srio

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 xilinx srio ip学习笔记之再识srio前言SRIO的理解IP核的理解前言 这段时间&#xff0c;随着对SRIO的学习&#xff0c;又有了更深的一点认识&#xff0c;不像一开始这么慌张了…

nodejs——MongoDB模块

MongoDB 是一个面向文档&#xff0c;schema 无关&#xff08;schema-less&#xff09;的数据库&#xff0c;它非常适合于 Node.js 应用以及云端部署。 与 MySQL 及 PostgreSQL 是根据固定的结构设计&#xff08;schema&#xff09;将数据存储在表中不同&#xff0c;MongoDB 可以…

设计模式面试题

工厂模式是我们最常用的实例化对象模式了&#xff0c;是用工厂方法代替new操作的一种模式,工厂模式在Java程序中可以说是随处可见。本文来给大家详细介绍下工厂模式 面向对象设计的基本原则&#xff1a; OCP&#xff08;开闭原则&#xff0c;Open-Closed Principle&#xff0…

【Linux】 gcc 、动态库和静态库,程序是如何链接的

文章目录前言一、gcc 是什么&#xff1f;二、使用步骤1.预编译2.编译3.汇编4.链接三、动静态库1.概念2.区别前言 在Linux环境下&#xff0c;除了学好编辑器 vim 的使用&#xff0c;还需要学会C语言的编译器 gcc 的功能&#xff0c;否则代码无法翻译成可执行程序。本文将介绍 gc…

RK3588平台开发系列讲解(日志篇)RK3588 syslog的使用

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、查看是否启用syslog.conf二、配置启用syslog.conf1、配置busybox2、添加配置文件3、编译buildroot烧录三、验证1、编写测试代码2、查看日志文件3、运行测试程序沉淀、分享、成长,让自己和他人都能有所收获!😄 …