Java数据结构之顺序表详解

 更新时间:2023年07月20日 10:07:53   作者:学习同学  
这篇文章主要介绍了Java数据结构之顺序表详解,线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储,需要的朋友可以参考下

一. 线性表

1.1 定义

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

看这个定义 我们再联想前面的知识

是不是发现数组的使用和这个定义十分相似

没错 其实顺序表本质上就是数组

但是它再数组上增加了一点内容

1.2 特点

它分为静态的和动态的

这个特点是不是又发现和我们上面做的项目通讯录十分相似

它是连续存储的 不能跳过元素

二. 顺序表

2.1 定义

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

2.2 代码

struct SeqList
{
	int a[100]; //数组
	int size; //数组中存储了多少个数字 
};

我们说类似这个结构的 就是一个顺序表

但是呢 为了我们以后改变数字方便 我们可以把这里的100 定义成一个宏 这样我们以后如果想修改顺序

表的大小 只要改变宏就可以了

代码表示如下

// 静态顺序表
#define N 100
struct SeqList
{
	int a[N]; //数组
	int size; //数组中存储了多少个数字 
};

上面就是一个标准的静态数据表 假如说 我们想使用顺序表来管理一个字符串

#define N 100
struct SeqList
{
	char a[N]; //数组
	int size; //数组中存储了多少个数字 
};

我们可以改变int类型 变为char类型的数据 但是这样每次改也太麻烦了 所以我们依旧可以再上面定义

一个宏变量

#define N 100
typedef char SLDateType
struct SeqList
{
	int SLDateType[N]; //数组
	int size; //数组中存储了多少个数字 
};

我们说 就可以使用这样的格式 方便以后一次性改变所有的变量类型

但是呢 这样子我们看整个结构体还是有点麻烦 我们再将这个结构体简化一下

typedef struct SeqList
{
	int SLDateType[N]; //数组
	int size; //数组中存储了多少个数字 
}SL;

这样子就能得到一个相对完美的静态顺序表啦

2.3 功能需求

在创建好这个静态表之后 我们要开始大概创建它的一些功能啦

比如说以下的一些功能

vovoid SeqListInit(SL* ps);
void SeqListPushBack(SL* ps, SLDateType x);
void SeqListPopBack(SL* ps);
void SeqListPushFront(SL* ps, SLDateType x);
void SeqListPopFront(SL* ps);

初始化 尾插 头插等等

2.4 静态顺序表的特点以及缺点

特点: 如果满了就不让插入

缺点: 不知道给多少合适

2.5 动态的顺序表

typedef struct SeqList
{
	SLDateType* a; //数组
	int size; //数组中存储了多少个数字 
	int capacity;
}SL;

是不是跟我们的通讯录特别相似

其实原理本质上都是一样的 这里只是命名更加规范了

2.6 动态顺序表接口的实现

初始化

void SeqListInit(SL* ps)
{
	ps->a = NULL;
	ps->size = ps->capacity = 0;
}

尾插

在这里插入图片描述

我们先写空间足够的情况

void SeqListPushBack(SL* ps, SLDateType x)
{
	ps->a[ps->size] = x;
	ps->size++;
}

代码表示如上

那么我们接下来我们写上面的两种情况

这里我们要注意的是 一开始我们将指针置空 占用的空间为0

所以说我们一开始至少要开始4个数据的空间 这里可以使用一个三目操作符解决

int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;

养成良好的习惯 代码加注释

void SeqListPushBack(SL* ps, SLDateType x)
{
	// 如果没有空间或者空间不足 我们就扩容 
	// 扩容失败就报错
	if ((ps->size)==(ps->capacity))
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDateType* tmp =(SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
		if (tmp==NULL)
		{
			perror("pushback realloc");
		}
	}
	ps->a[ps->size] = x;
	ps->size++;
}

这里我们使用一个打印函数看看整个数据的内容

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

打印出结果如下

在这里插入图片描述

在使用完成之后我们还需要一个借口函数来释放我们的动态开辟的内存 从而避免内存泄漏的问题

void SeqListDestory(SL* ps)
{
	free(ps->a);
	ps->a == NULL;
	ps->capacity = ps->size = 0;
}

接下来我们看尾删函数

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

尾删的话其实我们只要将size-- 就可以

但是这里我们要注意一点 当size为0的时候 这里就不可以再删除了 所以我们还需要完善以下上面的代码

void SeqListPopBack(SL* ps)
{
	if (ps->size==0)
	{
		perror("SeqListPopBack");
	}
	ps->size--;
}

接下来我们看前插

void SeqListPushFront(SL* ps, SLDateType x)
{
	// 考虑扩容问题
	if ((ps->size) == (ps->capacity))
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		ps->capacity = newcapacity;
		SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
		if (tmp == NULL)
		{
			perror("pushback realloc");
		}
		ps->a = tmp;
	}
	// 头插
	int end = ps->size - 1;
	while (end>=0)
	{
		ps->a[end + 1] = ps->a[end];
	}
	ps->a[0] = x;
	ps->size++;
}

接下来我们来看头删

在这里插入图片描述

这就要求我们定义一个bejin 然后从前往后依次挪数据

代码表示如下

void SeqListPopFront(SL* ps)
{
	int bejin = 0;
	while (bejin<ps->size-1)
	{
		ps->a[bejin] = ps->a[bejin + 1];
		bejin++;
	}
	ps->size--;
}

在这里插入图片描述

这里我们基本实现了顺序表的所有接口函数啦

三. 代码

头文件

#pragma once
#define N 100
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a; //数组
	int size; //数组中存储了多少个数字 
	int capacity;
}SL;
void SeqListInit(SL* ps);
void SeqListDestory(SL* ps);
void SeqListPushBack(SL* ps, SLDateType x);
void SeqListPopBack(SL* ps);
void SeqListPushFront(SL* ps, SLDateType x);
void SeqListPopFront(SL* ps);
void SeqListPrint(SL* ps);
// . 
//...

主文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "seqlist.h"
void SeqListInit(SL* ps)
{
	ps->a = NULL;
	ps->size = ps->capacity = 0;
}
void SeqListPrint(SL* ps)
{
	int i = 0;
	for ( i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}
void SeqListPushBack(SL* ps, SLDateType x)
{
	// 如果没有空间或者空间不足 我们就扩容 
	// 扩容失败就报错
	if ((ps->size)==(ps->capacity))
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		ps->capacity = newcapacity;
		SLDateType* tmp =(SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
		if (tmp==NULL)
		{
			perror("pushback realloc");
		}
		ps->a = tmp;
	}
	ps->a[ps->size] = x;
	ps->size++;
}
void SeqListDestory(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}
void SeqListPopBack(SL* ps)
{
	if (ps->size==0)
	{
		perror("SeqListPopBack");
	}
	ps->size--;
}
void SeqListPushFront(SL* ps, SLDateType x)
{
	// 考虑扩容问题
	if ((ps->size) == (ps->capacity))
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		ps->capacity = newcapacity;
		SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
		if (tmp == NULL)
		{
			perror("pushback realloc");
		}
		ps->a = tmp;
	}
	// 头插
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}
void SeqListPopFront(SL* ps)
{
	int bejin = 0;
	while (bejin<ps->size-1)
	{
		ps->a[bejin] = ps->a[bejin + 1];
		bejin++;
	}
	ps->size--;
}

测试文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "seqlist.h"
int main()
{
	SL a1;
	SeqListInit(&a1);
	SeqListPushBack(&a1, 1);
	SeqListPushBack(&a1, 2);
	SeqListPushBack(&a1, 3);
	SeqListPushBack(&a1, 4);
	SeqListPushBack(&a1, 5);
	SeqListPrint(&a1);
	SeqListPopBack(&a1);
	SeqListPrint(&a1);
	SeqListPopFront(&a1);
	SeqListPrint(&a1);
	SeqListDestory(&a1);
	return 0;
}

到此这篇关于Java数据结构之顺序表详解的文章就介绍到这了,更多相关Java顺序表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot接收参数所有方式总结

    SpringBoot接收参数所有方式总结

    这篇文章主要介绍了SpringBoot接收参数所有方式总结,文中通过代码示例和图文结合的方式给大家介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-07-07
  • 详解JAVA中的Collection接口和其主要实现的类

    详解JAVA中的Collection接口和其主要实现的类

    这篇文章主要介绍了JAVA中的Collection接口和其主要实现的类,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • Java软件编程培训机构靠谱吗

    Java软件编程培训机构靠谱吗

    随着网络信息化的快速发展,Java培训受到越来越多人的青睐,目前Java工程师的薪资水平在不断攀升,但是有好多企业还是招不到合适的人才,为什么呢
    2017-04-04
  • Java并发编程之synchronized底层实现原理分析

    Java并发编程之synchronized底层实现原理分析

    这篇文章主要介绍了Java并发编程之synchronized底层实现原理,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-02-02
  • centos上安装配置java WEB环境

    centos上安装配置java WEB环境

    前提是centos6.3系统已经安装好,在这里以64位系统为例,下面是jdk,tomcat,mysql下载安装步骤,有需要的小伙伴可以参考下
    2016-10-10
  • Java如何通过ssh远程连接主机并执行命令

    Java如何通过ssh远程连接主机并执行命令

    这篇文章主要介绍了Java如何通过ssh远程连接主机并执行命令问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • 详解SpringBoot+Mybatis实现动态数据源切换

    详解SpringBoot+Mybatis实现动态数据源切换

    这篇文章主要介绍了详解SpringBoot+Mybatis实现动态数据源切换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • Java中List集合去重的几种方式详细解析

    Java中List集合去重的几种方式详细解析

    这篇文章主要介绍了Java中List集合去重的几种方式详细解析,在日常的业务开发中,偶尔会遇到需要将 List 集合中的重复数据去除掉的场景,那么今天我们来看看几种LIst集合去重的方式,需要的朋友可以参考下
    2023-11-11
  • Java中保证线程顺序执行的操作代码

    Java中保证线程顺序执行的操作代码

    本文给大家分享一篇教程关于java线程顺序执行问题,如何保证线程的顺序执行呢?今天通过实例代码给大家详细讲解下,感兴趣的朋友跟随小编一起看看吧
    2021-05-05
  • Java中的Kafka拦截器详解

    Java中的Kafka拦截器详解

    这篇文章主要介绍了Java中的Kafka拦截器详解,Producer 拦截器(interceptor)是在 Kafka 0.10 版本被引入的,主要用于实现 clients 端的定制化控制逻辑,需要的朋友可以参考下
    2023-11-11

最新评论