顺序表详解(SeqList)

news2024/11/22 6:41:58

本文使用C语言进行顺序表的代码实现。

博主将使用代码和相关知识相结合的方式进行讲解,简单易懂,懵懂的大学生一听就会~

顺序表是一种线性表的存储结构,它将数据元素存储在一段连续的存储空间中,每个元素占据一个存储单元,并按照逻辑顺序依次存放。顺序表可以采用数组来实现,通过数组的下标来表示元素在顺序表中的位置,从而实现对元素的快速访问和操作。


一、顺序表的定义

线性表是一种基本的数据结构,它是由一组相同类型的数据元素组成的有序序列。线性表的特点是元素之间的关系是线性的,即每个元素都有一个唯一的索引(也称为位置),并且可以通过索引访问元素。

线性表有两种常见的实现方式:顺序表和链表。顺序表是使用一组连续的内存空间来存储元素,而链表则是使用一组离散的内存空间来存储元素,并通过指针将它们连接起来。

本文讲解顺序表的代码实现。

二、顺序表的实现

我们使用多文件的方法来进行顺序表的实现。

  • SeqList.h用存放需要使用的头文件及声明函数
  • SeqList.c用来实现对于顺序表的操作函数
  • test用来进行顺序表的功能测试和使用

1.顺序表的初始化

//结构体创建
typedef int SQDataType;

typedef struct SeqList
{
	SQDataType* a;
	int size;     // 有效数据的个数
	int capacity; // 容量
}SL;


//顺序表初始化
void SeqListInit(SL* ps)
{
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

首先创建一个结构体用来存放一个指针a,数据个数和顺序表的容量。

2.设置修改检查函数

//作为每次增添时的检查函数,如果顺序表的存储满了就进行扩容
void SeqListCheckCapacity(SL* ps)
{
	// 满了就要扩容
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SQDataType* tmp = (SQDataType*)realloc(ps->a, newcapacity * sizeof(SQDataType));
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		else
		{
			ps->a = tmp;
			ps->capacity = newcapacity;
		}
	}
}

 该函数用于检查顺序表(a)是否大小足够进行添加数据,如果大小为0那么将空间设置为4,如果不够用即用realloc扩容到原大小的二倍。,之后再对相关数值进行修改。

3.从头部插入数据

void SeqListPushFront(SL* ps, SQDataType x)
{
	SeqListCheckCapacity(ps);

	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}

	ps->a[0] = x;
	ps->size++;

}

头插的方法相当于是将整个顺序表向后挪动一位,最后将第一个位置空下然后插入数据。但是挪动的顺序是从后往前挪动,如果是从前往后的话就会将数据覆盖,从而无法正常插入。

4.从尾部插入数据

void SeqListPushBack(SL* ps, SQDataType x)
{
	SeqListCheckCapacity(ps);

	ps->a[ps->size] = x;
	ps->size++;

}

尾插就是直接向顺序表最后添加数据。

5.指定位置插入数据

void SeqListInsert(SL* ps, int pos, SQDataType x)
{
	assert(pos <= ps->size);
	SeqListCheckCapacity(ps);

	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	//将pos位置及之后全部向后移动一位,然后再pos位置上插入x
	ps->a[pos] = x;
	ps->size++;
}

关于assert断言相关知识如果想深入学习可以点击这段话跳转至博主的另一篇博客~

首先使用assert断言进行一个条件判断,确保插入的位置合法。之后的移动数据位置的操作和头插的方法类似,将pos位置和之后的数据全部向后移动一个位置,然后再在pos这个下标的位置上添加数据。

6.从头部删除数据

void SeqListPopFront(SL* ps)
{
	assert(ps->size > 0);

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

代码实现的操作就是将第一个位置上的位置进行覆盖,用第一个之后的数据逐一将前面一个的数据进行覆盖,从而达到删除第一个数据的效果。最后将size进行修改。

7.从尾部删除数据

void SeqListPopBack(SL* ps)
{
	assert(ps->size > 0);

	ps->size--;
}

直接将顺序表的size进行-1就可以实现删除最后一个数据的操作。

8.指定位置删除数据

void SeqListErase(SL* ps, int pos)
{
	assert(pos < ps->size);
	int start = pos + 1;
	while (start < ps->size)
	{
		ps->a[start - 1] = ps->a[start];
		++start;
	}
	ps->size--;
}

操作与头删类似,先设置start的数值为要删除的那个下标,然后将start之后的数据依次向前挪动覆盖数据实现在该指定位置的数据删除。

9.指定位置修改数据

void SeqListModity(SL* ps, int pos, SQDataType x)
{
	assert(pos < ps->size);
	ps->a[pos] = x;
}

修改数据的操作十分简单,找到该位置的下标然后进行修改即可完成操作。

10.查找数据

int SeqListFind(SL* ps, SQDataType x)
{
	for (int i = 0; i < ps->size; ++i)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}

	return -1;
}

遍历顺序表,逐个进行对比,与要查找的数据相同时返回该数据位置的下标,未找到返回-1.

三、整体程序代码展现

因为指定位置插入数据的函数和指定位置删除数据的函数可以完成头插尾插,头删尾删的操作,所以在程序中直接使用这两个插入方法进行头尾的操作减少了代码量。

在test.c中通过简单的菜单和分支操作可以对顺序表进行简单的操作。

SeqList.h

#pragma once

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
#include <assert.h>


// 增强程序可维护性
typedef int SQDataType;
// 动态的
typedef struct SeqList
{
	SQDataType* a;
	int size;     // 有效数据的个数
	int capacity; // 容量
}SL;

//typedef struct SeqList SL;

// 增删查改等接口函数
void SeqListInit(SL* ps);
void SeqListPrint(SL* ps);
void SeqListDestory(SL* ps);

// 头插 尾插 头删 尾删
void SeqListPushBack(SL* ps, SQDataType x);
void SeqListPushFront(SL* ps, SQDataType x);
void SeqListPopBack(SL* ps);
void SeqListPopFront(SL* ps);
void SeqListInsert(SL* ps, int pos, SQDataType x);
void SeqListErase(SL* ps, int pos);

int SeqListFind(SL* ps, SQDataType x);
void SeqListModity(SL* ps, int pos, SQDataType x);

SeqList.c

#include "SeqList.h"

// 增删查改等接口函数

//初始化数组
void SeqListInit(SL* ps)
{
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

//清除内存
void SeqListDestory(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}

//作为每次增添时的检查函数,如果顺序表的存储满了就进行扩容
void SeqListCheckCapacity(SL* ps)
{
	// 满了就要扩容
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SQDataType* tmp = (SQDataType*)realloc(ps->a, newcapacity * sizeof(SQDataType));
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		else
		{
			ps->a = tmp;
			ps->capacity = newcapacity;
		}
	}
}

// 头插 尾插 头删 尾删
void SeqListPushBack(SL* ps, SQDataType x)
{
	/*SeqListCheckCapacity(ps);

	ps->a[ps->size] = x;
	ps->size++;*/

	SeqListInsert(ps, ps->size, x);
}

void SeqListPushFront(SL* ps, SQDataType x)
{
	//SeqListCheckCapacity(ps);

	 1、初始条件
	 2、结束条件
	 3、迭代过程
	//int end = ps->size - 1;
	//while (end >= 0)
	//{
	//	ps->a[end + 1] = ps->a[end];
	//	--end;
	//}

	//ps->a[0] = x;
	//ps->size++;

	SeqListInsert(ps, 0, x);

}

void SeqListPopBack(SL* ps)
{
	//assert(ps->size > 0);

	ps->a[ps->size - 1] = 0;
	//ps->size--;
	SeqListErase(ps, ps->size - 1);
}

void SeqListPopFront(SL* ps)
{
	assert(ps->size > 0);

	/*
	int start = 1;
	while (start < ps->size)
	{
		ps->a[start - 1] = ps->a[start];
		++start;
	}
	ps->size--;*/
	SeqListErase(ps, 0);
}

void SeqListInsert(SL* ps, int pos, SQDataType x)
{
	assert(pos <= ps->size);
	SeqListCheckCapacity(ps);

	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	//将pos位置及之后全部向后移动一位,然后再pos位置上插入x
	ps->a[pos] = x;
	ps->size++;
}

void SeqListErase(SL* ps, int pos)
{
	assert(pos < ps->size);
	int start = pos + 1;
	while (start < ps->size)
	{
		ps->a[start - 1] = ps->a[start];
		++start;
	}
	ps->size--;
}

int SeqListFind(SL* ps, SQDataType x)
{
	for (int i = 0; i < ps->size; ++i)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}

	return -1;
}

//修改pos位置上的值为x
void SeqListModity(SL* ps, int pos, SQDataType x)
{
	assert(pos < ps->size);
	ps->a[pos] = x;
}

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

test.c

#include "SeqList.h"

void TestSeqList1()
{
	SL sl;
	SeqListInit(&sl);
	SeqListPushBack(&sl, 1);
	SeqListPushBack(&sl, 2);
	SeqListPushBack(&sl, 3);
	SeqListPushBack(&sl, 4);
	SeqListPushBack(&sl, 5);
	SeqListPushBack(&sl, 6);
	SeqListPushBack(&sl, 7);
	SeqListPushBack(&sl, 8);
	SeqListPushBack(&sl, 9);
	SeqListPushBack(&sl, 10);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPushBack(&sl, 11);
	SeqListPrint(&sl);

	SeqListDestory(&sl);
}

void TestSeqList2()
{
	SL sl;
	SeqListInit(&sl);
	SeqListPushFront(&sl, 1);
	SeqListPushFront(&sl, 2);
	SeqListPushFront(&sl, 3);
	SeqListPushFront(&sl, 4);
	SeqListPushFront(&sl, 5);
	SeqListPushFront(&sl, 6);
	SeqListPrint(&sl);

	SeqListPopBack(&sl);
	SeqListPopBack(&sl);
	SeqListPopBack(&sl);
	SeqListPrint(&sl);

	SeqListPopFront(&sl);
	SeqListPrint(&sl);

	SeqListDestory(&sl);
}

void TestSeqList3()
{
	SL sl;
	SeqListInit(&sl);
	SeqListPushFront(&sl, 1);
	SeqListPushFront(&sl, 2);
	SeqListPushFront(&sl, 3);
	SeqListPushFront(&sl, 4);
	SeqListPushFront(&sl, 5);
	SeqListPushFront(&sl, 6);
	SeqListPrint(&sl);
	SeqListInsert(&sl, 1, 20);
	SeqListPrint(&sl);

	SeqListErase(&sl, 1);
	SeqListPrint(&sl);

	SeqListDestory(&sl);
}

void menu()
{
	printf("**********************************************\n");
	printf("1.尾插数据, 2.头插数据\n");
	printf("3.尾删数据, 4.头删数据\n");
	printf("5.打印数据,-1.退出\n");
	printf("**********************************************\n");
	printf("请输入你操作选项:");
}

int main()
{
	SL s;
	SeqListInit(&s);
	int option = 0;
	int x = 0;
	while (option != -1)
	{
		menu();
		scanf("%d", &option);
		switch (option)
		{
		case 1:
			printf("请输入你要插入的数据,以-1结束\n");
			do {
				scanf("%d", &x);
				if (x != -1)
				{
					SeqListPushBack(&s, x);
				}
			} while (x != -1);
			break;
		case 2:
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:
			SeqListPrint(&s);
			break;
		default:
			break;
		}
	}

	SeqListDestory(&s);

	return 0;
}

那么本篇博客到此就结束了,如果可以帮助到你是博主的荣幸!

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

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

相关文章

Spring Security 认证授权安全框架

Spring Security概述 1.什么是Spring Security? Spring Security是一个Java框架&#xff0c;用于保护应用程序的安全性。它提供了一套全面的安全解决方案&#xff0c;包括身份验证、授权、防止攻击等功能。Spring Security基于过滤器链的概念&#xff0c;可以轻松地集成到任…

白盒测试接口测试自动化测试

一、白盒测试&#xff1a;一种测试策略&#xff0c;允许我们检查程序的内部结构&#xff0c;对程序的逻辑结构进行检查&#xff0c;从中获取测试数据。白盒测试的对象基本是源程序&#xff0c;所以它又称为结构测试或逻辑驱动测试&#xff0c;白盒测试方法一般分为静态测试和动…

Cesium 问题:加载 gltf 格式的模型之后太小,如何让相机视角拉近

文章目录 问题分析问题 刚加载的模型太小,如何拉近视角放大 分析 在这里有两种方式进行拉近视角, 一种是点击复位进行视角拉近一种是刚加载就直接拉近视角// 模型三加载 this.damModel = new Cesium.Entity({name: "gltf模型",position:</

leetcode hot100零钱兑换Ⅱ

本题可以看出也是背包问题&#xff0c;但区别于之前的01背包问题&#xff0c;这个是完全背包问题的变形形式。 下面介绍01背包和完全背包的区别与联系&#xff1a; 01背包是背包中的物品只能用一次&#xff0c;不可以重复使用&#xff0c;而完全背包则是可以重复使用。01/完全…

一命通关动态规划dp

前言 这篇文章详细概括了动态规划的所有题型&#xff0c;以及各个题型的解决公式方法。如果看完这篇动态规划还是不会做题&#xff0c;我来给你补&#xff0c;我爱说点实话。 动态规划 何为动态规划&#xff1f; 动态规划&#xff0c;有一点暴力求解的感觉。用最通俗的语言来…

利用nbsp设置空格

想要实现上面效果&#xff0c;一开始直接<el-col :span"8" >{{ item.name }} </el-col> 或者<el-col :span"8" >{{ item.name }}</el-col>或者<el-col :span"8" >{{ item.name }}</el-col> 都无…

【办公类-16-07-02】“2023下学期 周计划-户外游戏 每班1周五天相同场地,6周一次循环”(python 排班表系列)

背景需求&#xff1a; 又到了开学季&#xff0c;新的自主游戏&#xff08;户外游戏&#xff09;安排表出炉了。 这张是贴在美术活动室的安排表&#xff0c;我需要转换成班级为单位的安排表&#xff0c;便于批量制作周计划。 设计思路&#xff1a; 1、一个班级每周轮到的一个场…

网工内推 | 上市公司、外企网工,厂商认证优先,最高18K*13薪

01 北京电旗通讯技术股份有限公司 招聘岗位&#xff1a;网络运维工程师 职责描述&#xff1a; 1.负责内部核心网络的运行监控、故障处理。 2.对网络性能进行监控和调优。 3.负责网络设备的规划选型。 4.设计网络架构拓扑图,制定网络规范。 5.分析处理复杂网络故障。 6.负…

sizeof()的易错点

你也可以传入一个变量的名字&#xff08;而不只是类型&#xff09;给 sizeof()&#xff0c;但在一些情况下&#xff0c;可能得不到你要的结果&#xff0c;所以要小心使用。例如&#xff0c;看看下面的代码片段&#xff1a; 在第一行&#xff0c;我们为 10 个整数的数组声明了空…

【前端】前端三要素之JavsScript基础

写在前面&#xff1a;本文仅包含JavaScript内容&#xff0c;DOM知识传送门在这里&#xff0c;BOM传送门在这里。 本文内容是假期中刷的黑马Pink老师视频&#xff08;十分感谢Pink老师&#xff09;&#xff0c;原文保存在个人的GitLab中&#xff0c;如果需要写的网页内容信息等可…

笔记:torch.roll

最近在准备写 swin transformer 的文章&#xff0c;记录下 torch.roll 的用法&#xff1a; >>> x torch.tensor([1, 2, 3, 4, 5, 6, 7, 8]).view(4, 2) >>> x tensor([[1, 2],[3, 4],[5, 6],[7, 8]]) 第0维度向下移1位&#xff0c;多出的[7,8]补充到顶部 &g…

【Flink网络通讯(一)】Flink RPC框架的整体设计

文章目录 1. Akka基本概念与Actor模型2. Akka相关demo2.1. 创建Akka系统2.2. 根据path获取Actor并与之通讯 3. Flink RPC框架与Akka的关系4.运行时RPC整体架构设计5. RpcEndpoint的设计与实现 我们从整体的角度看一下Flink RPC通信框架的设计与实现&#xff0c;了解其底层Akka通…

JS进阶——解构赋值

数组解构 基本&#xff1a; let [a, b, c] [1, 2, 3]; // a 1 // b 2 // c 3 可嵌套 let [a, [[b], c]] [1, [[2], 3]]; // a 1 // b 2 // c 3 可忽略 let [a, , b] [1, 2, 3]; // a 1 // b 3 不完全解构 let [a 1, b] []; // a 1, b undefined 剩余运…

基于RHEL8部署Zabbix6.0,监控不再困难!

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

5G——物理层仿真

1.前置条件 2.仿真流程 1.填写搜索过程 解&#xff1a; 2.填写每一步细节 2.2.1 准备 解&#xff1a; &#xff08;1&#xff09;BCH &#xff08;2&#xff09;BCCH 解析&#xff1a;因为PBCH是物理广播信道&#xff0c;BCCH是用于广播系统控制信息的下行信道&#…

vulfocus靶场搭建

vulfocus靶场搭建 什么是vulfocus搭建教程靶场配置场景靶场编排靶场优化 什么是vulfocus Vulfocus 是一个漏洞集成平台&#xff0c;将漏洞环境 docker 镜像&#xff0c;放入即可使用&#xff0c;开箱即用&#xff0c;我们可以通过搭建该靶场&#xff0c;简单方便地复现一些框架…

数据库专题——分库分表

一. 分库分表介绍二. 分库分表实践 一. 分库分表介绍 1.1 分库分表解决了什么问题 先说分库&#xff1a; 《高性能MySQL》中提到了两种数据库扩展方式&#xff1a;垂直扩展和水平扩展。前者意味着买更多性能强悍的硬件&#xff0c;但是总会达到扩展的天花板&#xff0c;且成本…

​LeetCode解法汇总105. 从前序与中序遍历序列构造二叉树

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 描述&#xff1a; 给定两个整…

js 多对象去重(多属性去重)

需求中发现后端可能没有处理重复数据&#xff0c;这个时候前段可以直接解决。 在 JavaScript 中&#xff0c;可以使用 Set 数据结构来进行多对象的去重。Set 是 ES6 新引入的集合类型&#xff0c;其特点是元素不会重复且无序。 下面是一个示例代码&#xff0c;展示如何通过 S…

python基础教程—总结篇

这篇是Python基础教程系列的总结篇&#xff0c;这里这个专栏的地址&#xff1a;《Python教程》 首先必须声明一点&#xff0c;这是基础教程&#xff0c;所以面向的是新人&#xff0c;没有学过Python的同学&#xff0c;所以这套教程并没有涉及到比较难的并发编程模块&#xff0…