线性表的顺序实现【C语言版的真代码】

news2024/11/22 21:10:40

顺序表

    • 线性表
    • 顺序表
      • 顺序表的概念及其结构
      • 顺序表基本操作
      • 顺序表的初始化
      • 顺序表的插入
      • 顺序表的删除
      • 顺序表的查找

线性表

线性表:一个线性表是含n个数据元素的有限序列。

它的逻辑结构要求是线性的,但其存储结构并没有做要求,即逻辑结构类似于如下的表则被称为线性表:
在这里插入图片描述
线性表的每个结点都有且仅有一个前驱(前一个)和一个后继(后一个),但它的第一个结点没有前驱,最后一个结点没有后继。

既然它对存储结构未做要求,那么它的存储结构可以采用顺序存储、也可以采用链式存储。因此一个线性表可以顺序实现、也可以链式实现。
在这里插入图片描述

采用顺序存储的线性表,被称为顺序表,更为详细一点的逻辑关系:
在这里插入图片描述

采用链式存储的线性表,则被称为链表,更为详细一点的逻辑关系:
在这里插入图片描述
线性表的第一个数据元素的存储位置,通常称为线性表的起始地址或者基地址。

顺序表

顺序表的概念及其结构

采用顺序存储的线性表即为顺序表,指的是用一组地址连续的存储单元依次存储线性表的数据元素。通俗地来说,就是这些数据元素存放的“位置是相邻的”。

通常情况下使用数组来描述顺序表(数组的逻辑结构是线性的,物理存储采用顺序存储符合顺序表的特点)

//例如
//定长的数组
int arr[10];
//动态开辟的数组
int* arr;

顺序表可以分为静态顺序表和动态顺序表

  • 静态顺序表:采用定长的数组存储数据元素
  • 动态顺序表:采用动态开辟的数组存储数据元素

【静态顺序表的定义】
现阶段数据元素的类型并不清楚,在C语言中可以使用类型重定义的方式,便于后续修改。

typedef int ELemType;
ElemType arr[100];

同理,究竟需要多大的空间我们也并不确定,因此使用宏定义的方式,便于后续修改

#define MAXSIZE 100
typedef int ELemType;
ElemType arr[MAXSIZE];

仅仅这样无法满足我们需求,线性表不仅要支持存储数据,还要能够对数据进行增删查改。如果顺序表内一个元素都不存在了,还要去删除,又或者说顺序表满了,还要去插入数据元素,这样是不可行的。因此我们还需要一个属性去标记它每个时刻所存放的真实数据元素的个数,当要进行删除的时候,就判断一下个数是不是为0,如果不为0的话再进行删除操作,其他操作根据情况来定:

#define MAXSIZE 100
typedef int ELemType;
struct SeqList
{
	ELemType arr[MAXSIZE];
	int size; //记录每个时刻保存的数据元素个数
};

此外,如果直接这样,一个顺序表就需要这样定义struct SeqList name。通常会把这个结构体类型进行类型重定义,达到简写的目的:

#define MAXSIZE 100
typedef int ELemType;
typedef struct SeqList
{
	ELemType arr[MAXSIZE];
	int size; //记录每个时刻保存的数据元素个数
}SeqList;

【动态顺序表的定义】

typedef int ELemType;
typedef struct SeqList
{
	ElemType* arr;
	int capacity; //记录此时容量大小,以数据元素个数为单位
	int size; //记录每个时刻保存的数据元素个数
}SeqList;

数组指针arr指向顺序表的基地址。

静态的顺序表因为其存储空间是静态的,如果开一个很大的空间,可能就会造成浪费,如果一开始开比较小的空间,则可能不够用。因此对于更加高阶一些并且基于线性表的数据结构来说,通常采用的都是动态顺序表。

顺序表基本操作

//线性表的初始化
void SeqListInit(SeqList* seq);
//线性表的销毁
void SeqListDestory(SeqList* seq);
//线性表的尾插
void SeqListPushBack(SeqList* seq, ElemType value);
//线性表的尾删
void SeqListPopBack(SeqList* seq);
//线性表的头插
void SeqListPushFront(SeqList* seq, ElemType value);
//线性表的头删
void SeqListPopFront(SeqList* seq);
//线性表的查找
int SeqListFind(SeqList* seq, ElemType value);
//在pos位置(下标)插入value
void SeqListInsert(SeqList* seq, int pos, ElemType value);
//删除pos位置(下标)的值
void SeqListErase(SeqList* seq, int pos);
//打印顺序表
void SeqListPrint(SeqList seq);

下面将只介绍几个十分重要的顺序表基本操作

顺序表的初始化

void SeqListInit(SeqList* seq)
{
	seq->arr = NULL;
	seq->size = seq->capacity = 0;
}

顺序表的插入

顺序表的插入有三种情况:

  • 尾插:在顺序表的尾部插入一个数据元素
  • 头插:在顺序表的头部插入一个数据元素
  • 在任意位置(下标)处插入一个数据元素

【尾插的实现】

void SeqListPushBack(SeqList* seq, ElemType value)
{

}

按照逻辑,直接将要插入的数据元素放入数组的尾部。
在这里插入图片描述

此时数组尾部的下标就是size的大小,插入之后一定要维护size的值。

void SeqListPushBack(SeqList* seq, SLDataType value)
{
	seq->arr[seq->size] = value;
	seq->size++;
}

但还可能会遇到顺序表已满的情况,此时就不能够直接进行插入。若顺序表已满,插入前则应该先扩容,再执行上述的逻辑。
在这里插入图片描述
那么在进行插入之前,应当先判断顺序表内此刻是否有空间,能够容纳要插入的数据元素。当size和capacity相同的时候,就表示顺序表内没有多余的空间。但还要分成两种情况:
(1)size=capacity=0;顺序表一点容量都没有
(2)size=capacity≠0;顺序表没有多余容量存放其他数据元素

void SeqListPushBack(SeqList* seq, SLDataType value)
{
	if(seq->size == seq->capacity)
	{
		//如果为空,则新容量为4;否则开辟原来的2倍
		//策略可以自行定制,但要注意适当
		int newcapacity = (seq->capacity == 0 ? 4 : seq->capacity * 2);
		ElemType* tmp = (ElemType*)realloc(seq->arr, sizeof(ElemType) * newcapacity);
		if(NULL == tmp)
		{
			printf("扩容失败\n");
			exit(-1);
		}
		seq->arr = tmp;
		seq->capacity = newcapacity;
	}
	seq->arr[seq->size] = value;
	seq->size++;
}

【头插的实现】
和尾插类似,在进行插入前需要检查是否还有足够的容量,容纳准备插入的数据元素。为了提高代码的复用率,我们可以将检查容量的工作提取出来,封装成一个方法。

void SeqListCheckCapac(SeqList* seq)
{
	//如果size== capacity说明:数组为空 或者满了;需要扩容
	if (seq->size == seq->capacity)
	{
		int newcapacity = seq->capacity == 0 ? 4 : (seq->capacity * 2);
		ElemType* tmp = (ElemType*)realloc(seq->arr, sizeof(ElemType) * newcapacity);
		if (tmp == NULL)
		{
			printf("扩容失败\n");
			exit(-1);
		}
		seq->arr = tmp;
		seq->capacity = newcapacity;
	}
}

优化一下尾插的方法:

void SeqListPushBack(SeqList* seq, ElemType value)
{
	//检查容量
	SeqListCheckCapac(seq);

	seq->arr[seq->size] = value;
	seq->size++;
}

现在正式开始顺序表头插的实现

void SeqListPushFront(SeqList* seq, ElemType value)
{
	//检查容量
	SeqListCheckCapac(seq);
}

在这里插入图片描述
在顺序表的头部进行插入,若插入位置有数据元素,则应将数据元素往后面挪。但只将插入位置的一个数据元素挪到后面,会把后面的数据元素覆盖掉。因此要从顺序表的尾部开始,依次将数据元素往后挪一个位置。简而言之,就是要给插入的数据元素“腾位置”。
在这里插入图片描述
然后插入即可。

void SeqListPushFront(SeqList* seq, ElemType value)
{
	//检查容量
	SeqListCheckCapac(seq);

	int end = seq->size - 1;
	while(end > 0)
	{
		seq->arr[end + 1] = seq->arr[end]
		end--;
	}
	seq->arr[0] = value;
	seq->size++;
}

[在任意位置插入]
同样,插入前需要检查容量,并且还需要判断选择插入的位置是否合法,在准许插入的范围之内。

//在pos位置插入value
void SeqListInsert(SeqList* seq, int pos, ElemType value)
{
	//检查容量
	SeqListCheckCapac(seq);
	if(pos < 0 || pos > seq->size)
	{
		printf("试图插入一个非法的位置\n");
		return;
	}
}

在这里插入图片描述
如果不是尾部的插入(当前要插入的位置有数据元素),类似于头插,需要给它“腾位置”,从尾部开始依次往后挪一位。
在这里插入图片描述

//在pos位置插入value
void SeqListInsert(SeqList* seq, int pos, ElemType value)
{
	//检查容量
	SeqListCheckCapac(seq);
	if(pos < 0 || pos > seq->size)
	{
		printf("试图插入一个非法的位置\n");
		return;
	}
	int end = seq->size - 1;
	while(end > pos)
	{
		seq->arr[end + 1] = seq->arr[end]
		end--;
	}
	seq->arr[pos] = value;
	seq->size++;
}

顺序表的删除

顺序表的删除共有三种删除方式:

  • 尾删:删除顺序表尾部的一个数据元素;
  • 头删:删除顺序表头部的一个数据元素;
  • 删除顺序表任意位置的一个数据元素

【尾删的实现】
尾删的基本做法:将尾部的位置置为初始值,同时size的大小减去1;
但对于我们的角度来说,只要访问不到这个位置,那么就认为这个位置不存在真实的数据元素。根据整个代码的逻辑来看,只需要将描述顺序表内真实数据元素个数的size,减去1即可。

void SeqListPopBack(SeqList* seq)
{
	seq->size--;
}

设想顺序表内没有数据元素了,却仍然要去执行删除的操作,那么必定不能够删除。因此在执行删除操作之前,还需判断顺序表内是否存在数据元素。此处可采用稍暴力的方式“断言”

void SeqListPopBack(SeqList* seq)
{
	assert(seq->size > 0);
	seq->size--;
}

【头删的实现】
同尾删一样,删除前需要检查顺序表内是否存在数据元素。

void SeqListPopFront(SeqList* seq)
{
	assert(seq->size > 0);
}

在这里插入图片描述
(1)若删除位置后面不存在数据元素,可直接将size的值减去1即可;
(2)若删除位置后面存在数据元素,将后面的值依次挪到前面,将要删除位置的数据元素进行覆盖,再将size的值减去1即可。
在这里插入图片描述

void SeqListPopFront(SeqList* seq)
{
	assert(seq->size > 0);
	int end = 0;
	while (end < seq->size)
	{
		seq->arr[end] = seq->arr[end + 1];
		end++;
	}
	seq->size--;
}

【任意位置的删除】
类似于头删,若后面存在数据元素,则将删除位置后面的数据元素依次挪动即可,若不存在数据元素就无需挪动,再将顺序表size的值减去1即可。

void SeqListErase(SeqList* seq, int pos)
{
	assert(seq->size > 0 && pos >=0 && pos < seq->size);

	int end = pos;
	while (end < seq->size)
	{
		seq->arr[end] = seq->arr[end + 1];
		end++;
	}
	seq->size--;
}

顺序表的查找

由于顺序表采用数组实现,那么它就支持随机访问。因此要查找一个数据元素时,只需要依次去比较,如果找到了符合的,返回对应的下标即可。否则返回-1,表示该顺序表内不存在这样的数据元素。

int SeqListFind(SeqList* seq, ElemType value)
{
	for (int i = 0; i < seq->size; i++)
	{
		if (value == seq->arr[i])
		{
			return i;
		}
	}
	return -1;
}

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

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

相关文章

非DBA人员从零到一,MySQL InnoDB数据库调优之路(四)-数据备份与迁移

上一篇【非DBA人员从零到一&#xff0c;MySQL InnoDB数据库调优之路(三)-分区表与分库分表】 我认为分表在数据库的调优中是一种加法&#xff0c;通过拆分单表数据到多个表中&#xff0c;减少单表的压力&#xff0c;从而达到调优的效果&#xff0c;那么这一篇博文会通过对数据…

Spring Security权限管理原理

1.简介 授权是更具系统提前设置好的规则&#xff0c;给用户分配可以访问某一资源的权限&#xff0c;用户根据自己所具有的权限&#xff0c;去执行相应的操作&#xff0c;spring security提供的权限管理功能主要有两种&#xff1a; 基于过滤器的权限管理功能&#xff08;Filte…

Syntax Error: Error: Missing binary. See message above.

安装完nvm&#xff0c;选择后node版本&#xff0c;在idea中引入vue项目&#xff0c;npm install后&#xff0c;运行npm run serve后 控制台出现下面错误&#xff1a; Try running this to fix the issue: D:\Program Files\nodejs\node.exe E:\vue-project\node_modules\fibe…

篮球竞赛预约平台设计与实现的源码+文档

摘 要 随着信息化时代的到来&#xff0c;管理系统都趋向于智能化、系统化&#xff0c;篮球竞赛预约平台也不例外&#xff0c;但目前国内仍都使用人工管理&#xff0c;市场规模越来越大&#xff0c;同时信息量也越来越庞大&#xff0c;人工管理显然已无法应对时代的变化&#x…

platform总线

1、什么是platform总线&#xff1f; platform是Linux内核抽象出来的软件代码&#xff0c;用于设备与驱动的连接&#xff0c;设备与驱动通过总线进行匹配&#xff1b;匹配成功后会执行驱动中的probe函数&#xff0c;在probe函数中可以获取到设备的信息&#xff1b; 设备与驱动…

gitlab的使用方法,详解gitlab操作

1.导读 本教程主要讲解了GitLab在项目的环境搭建和基本的使用&#xff0c;可以帮助大家在企业中能够自主搭建GitLab服务&#xff0c;并且可以GitLab中的组、权限、项目自主操作。 - GitLab简介 - GitLab环境搭建 - GitLab基本使用(组、权限、用户、项目) 2.GitLab简介 Gi…

debug - JLX12864C(ST7920-12864)液晶屏不能使用串行通讯的原因

文章目录debug - JLX12864C(ST7920-12864)液晶屏不能使用串行通讯的原因概述调试备注ENDdebug - JLX12864C(ST7920-12864)液晶屏不能使用串行通讯的原因 概述 正在给板子写出厂测试程序, 买的12864型号是JLX12864C. STC官方给的例程是并行通讯, 好使. 但是想在测试程序中改为…

Linux线程基础

目录 一&#xff0c;线程函数 1、创建一个线程 2、获取自身线程ID 3、线程终止 4、取消正在执行线程 5、线程等待 6、线程分离 二&#xff0c;线程的使用 1&#xff0c;线程等待和线程分离 (1)、线程等待 (2)、线程分离 (3)、线程等待线程分离同时进行 三&#xff…

中英翻译《森林火灾的预防措施》

The Preventive Measures for Forest Fire 森林火灾的预防措施 The preventive measures for forest fires include some preemptive methods that can help reduce the risks of fires and contril their severity and spread, and thus, maintain ecological balance …

vue与es6的知识点

var let const let const 不能重复声明&#xff0c;局部作用域&#xff0c; 案例 let name "未来"; let str 我是${name}; console.log(str); 箭头函数 let add (x)>{ return x; } console.log(add(9)) v-bind 绑定标签的属性 src class a titie等等…

Qt for Android实现开机自启动

前言 最近项目需要&#xff0c;在Android上编写的程序&#xff0c;需要实现开机自启动。笔者查询了下资料&#xff0c;基本原理如下&#xff1a; 当Android启动时&#xff0c;会发出一个系统广播&#xff0c;内容为ACTION_BOOT_COMPLETED&#xff0c;它的字符串常量表示为 an…

详解时间复杂度计算公式(附例题细致讲解过程)

这几天开始刷力扣上面的算法题&#xff0c;有些题目上面限制时间复杂度和空间复杂度&#xff0c;题目虽然写出来了&#xff0c;但是很没底。印象里数据结构老师讲过一点&#xff0c;沉睡的记忆苏醒了。只记得一个时间复杂度是O(n)&#xff0c;空间复杂度是S(n)。for循环常常是O…

中学语文教学参考杂志社中学语文教学参考编辑部2022年第27期目录

理论学术_课题荟萃《中学语文教学参考》投稿&#xff1a;cn7kantougao163.com 统编教材鲁迅作品的民俗文化分析及教学应用 张家波;张晓静; 3-5 高中语文线上学习的实践与反思 张灵贵; 6-797 不同课型导学案设计建议 张桂霞; 8-997 现代化进程中的阵痛:《哦,香雪…

遇到Bug漏测,不能总想着甩锅吧

背景 漏测Bug是指产品逻辑缺陷在测试过程中没有被发现&#xff08;尤其是测试环境可以重现的缺陷&#xff09;&#xff0c;上线版本发布后或者在用户使用体验后发现并反馈回来的缺陷。 漏测Bug可能造成线上故障或者资损&#xff0c;在对产品测试过程中&#xff0c;自己也难免…

Pandas常见筛选数据的五种方法其一逻辑筛选。看见必懂,懂者必会,会者必加分

前言&#xff1a;Pandas的数据操作中&#xff0c;最基本的就是操作的筛选了&#xff0c;但是对新学员来说的这又是一个难点&#xff0c;因为方法比较多&#xff0c;不容易记。在此总结一下pandas中的一些常用的数据筛选操作。 逻辑筛选数据&#xff1a;切片&#xff08;[ ]&am…

ubuntu 安装、配置FTP

ubuntu 安装、配置FTP 提示&#xff1a;ubuntu 16.0.4&#xff0c;不同版本操作可能稍有不同 前言 本文主要对服务器安装及配置FTP做一个记录&#xff0c;涉及安装、配置、创建FTP账号、以及第一次连接异常等。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可…

单载波频域均衡matlab仿真,包括卷积编码维特比译码,矩阵交织,QPSK调制解调,导频插入,MMSE-FDE频域均衡

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 频域均衡是从校正系统的频率特性出发&#xff0c;利用一个可调滤波器的频率的频率特性去补偿信道或系统的频率特性&#xff0c;使包括可调滤波器在内的基带系统的总特性接近无失真传输条件。频域…

【Spring项目中的Controller理解】

目录 1. 添加依赖 2. 关于异常 1. 添加依赖 首先&#xff0c;需要保障此项目中存在spring-boot-starter-web依赖项&#xff0c;否则&#xff0c;当前项目并不具备Web应用程序开发所需的依赖&#xff01; 提示&#xff1a;spring-boot-starter-web是建立在spring-boot-starte…

基于Python的Django开发接口框架搭建

1、安装Django&#xff0c;如图1 命令行执行&#xff1a;pip install django 2、创建Django项目&#xff0c;如图2 django-admin startproject imooc 3、创建Django的应用项目&#xff0c;如图3 必须进入项目文件下执行命令&#xff1a; python3 manage.py startapp app …

✿✿✿JavaScript ---- 函数/js内置对象

目 录 一、函数 自调用函数如下演示&#xff1a; 二、JS中的内置对象 2.Number对象 3.Date 对象 补&#xff1a;第三方的日期工具类 moment.js 4.Math对象 5.数组对象 补&#xff1a;ES6中数组对象新增的方法 6.Global全局方法对象 7.RegExp(**)正则表达式对象 一、…