线性表之顺序表详解(1)

news2025/1/11 4:08:44

线性表

参考来源:

线性表是最基本、最简单、也是最常用的一种数据结构。一个线性表是n个具有相同特性的数据元素的有限序列。
前驱元素:
若A元素在B元素的前面,则称A为B的前驱元素
后继元素:
若B元素在A元素的后面,则称B为A的后继元素
线性表的特征:数据元素之间具有一种“一对一”的逻辑关系。

  1. 第一个数据元素没有前驱,这个数据元素被称为头结点;
  2. 最后一个数据元素没有后继,这个数据元素被称为尾结点;
  3. 除了第一个和最后一个数据元素外,其他数据元素有且仅有一个前驱和一个后继。
  4. 如果把线性表用数学语言来定义,则可以表示为(a1,…ai-1,ai,ai+1,…an),ai-1领先于ai,ai领先于ai+1,称ai-1是ai的前驱元素,ai+1是ai的后继元素

线性表的分类:
线性表中数据存储的方式可以是顺序存储,也可以是链式存储,按照数据的存储方式不同,可以把线性表分为顺序
表和链表。

顺序表

定义:

顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元,依次存
储线性表中的各个元素、使得线性表中再逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元
素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系。
在这里插入图片描述

API设计:

在这里插入图片描述

代码实现:

//顺序表代码
public class SequenceList<T> {
	//存储元素的数组
	private T[] eles;
	//记录当前顺序表中的元素个数
	private int N;
	//构造方法
	public SequenceList(int capacity){
		eles = (T[])new Object[capacity];
		N=0;
	}
	//将一个线性表置为空表
	public void clear(){
		N=0;
	}
	//判断当前线性表是否为空表
	public boolean isEmpty(){
	}
	//获取线性表的长度
	public int length(){
		return N;
	}
	//获取指定位置的元素
	public T get(int i){
		if (i<0 || i>=N){
			throw new RuntimeException("当前元素不存在!");
		}
		return eles[i];
	}
	//向线型表中添加元素t
	public void insert(T t){
		if (N==eles.length){
			throw new RuntimeException("当前表已满");
		}
		eles[N++] = t;
	}
	//在i元素处插入元素t
	public void insert(int i,T t){
		if (i==eles.length){
			throw new RuntimeException("当前表已满");
	}
		if (i<0 || i>N){
			throw new RuntimeException("插入的位置不合法");
		}
	//把i位置空出来,i位置及其后面的元素依次向后移动一位
	for (int index=N;index>i;index--){
		eles[index]=eles[index-1];
	}
	//把t放到i位置处
	eles[i]=t;
	//元素数量+1
	N++;
	}
	//删除指定位置i处的元素,并返回该元素
	public T remove(int i){
		if (i<0 || i>N-1){
			throw new RuntimeException("当前要删除的元素不存在");
	}
	//记录i位置处的元素
	T result = eles[i];
	//把i位置后面的元素都向前移动一位
	for (int index=i;index<N-1;index++){
		eles[index]=eles[index+1];
	}
	//当前元素数量-1
		N--;
		return result;
	}
	//查找t元素第一次出现的位置
	public int indexOf(T t){
		if(t==null){
			throw new RuntimeException("查找的元素不合法");
		}
		for (int i = 0; i < N; i++) {
			if (eles[i].equals(t)){
				return i;
			}
		}
		return -1;
		}
	}
	//测试代码
	public class SequenceListTest {
		public static void main(String[] args) {
		//创建顺序表对象
			SequenceList<String> sl = new SequenceList<>(10);
		//测试插入
			sl.insert("姚明");
			sl.insert("科比");
			sl.insert("麦迪");
			sl.insert(1,"詹姆斯");
		//测试获取
			String getResult = sl.get(1);
			System.out.println("获取索引1处的结果为:"+getResult);
		//测试删除
			String removeResult = sl.remove(0);
			System.out.println("删除的元素是:"+removeResult);
		//测试清空
			sl.clear();
			System.out.println("清空后的线性表中的元素个数为:"+sl.length());
	}
}

顺序表的遍历

一般作为容器存储数据,都需要向外部提供遍历的方式,因此我们需要给顺序表提供遍历方式。
在java中,遍历集合的方式一般都是用的是foreach循环,如果想让我们的SequenceList也能支持foreach循环,则
需要做如下操作:
1.让SequenceList实现Iterable接口,重写iterator方法;
2.在SequenceList内部提供一个内部类SIterator,实现Iterator接口,重写hasNext方法和next方法;
代码:

//顺序表代码
import java.util.Iterator;
public class SequenceList<T> implements Iterable<T>{
	//存储元素的数组
	private T[] eles;
	//记录当前顺序表中的元素个数
	private int N;
	//构造方法
	public SequenceList(int capacity){
		eles = (T[])new Object[capacity];
		N=0;
	}
	//将一个线性表置为空表
	public void clear(){
		N=0;
	}
	//判断当前线性表是否为空表
	public boolean isEmpty(){
		return N==0;
	}
	//获取线性表的长度
	public int length(){
		return N;
	}
	//获取指定位置的元素
	public T get(int i){
		if (i<0 || i>=N){
		throw new RuntimeException("当前元素不存在!");
	}
		return eles[i];
	}
	//向线型表中添加元素t
	public void insert(T t){
		if (N==eles.length){
			throw new RuntimeException("当前表已满");
	}
		eles[N++] = t;
	}
	//在i元素处插入元素t
	public void insert(int i,T t){
		if (i==eles.length){
			throw new RuntimeException("当前表已满");
		}
		if (i<0 || i>N){
			throw new RuntimeException("插入的位置不合法");
		}
		//把i位置空出来,i位置及其后面的元素依次向后移动一位
		for (int index=N;index>i;index--){
			eles[index]=eles[index-1];
		}
		//把t放到i位置处
			eles[i]=t;
		//元素数量+1
			N++;
	}
	//删除指定位置i处的元素,并返回该元素
	public T remove(int i){
		if (i<0 || i>N-1){
			throw new RuntimeException("当前要删除的元素不存在");
		}
		//记录i位置处的元素
		T result = eles[i];
		//把i位置后面的元素都向前移动一位
		for (int index=i;index<N-1;index++){
			eles[index]=eles[index+1];
		}
		//当前元素数量-1
		N--;
		return result;
	}
	//查找t元素第一次出现的位置
	public int indexOf(T t){
		if(t==null){
			throw new RuntimeException("查找的元素不合法");
	}
		for (int i = 0; i < N; i++) {
			if (eles[i].equals(t)){
				return i;
			}
		}
			return -1;
		}
	//打印当前线性表的元素
	public void showEles(){
		for (int i = 0; i < N; i++) {
			System.out.print(eles[i]+" ");
		}
		System.out.println();
	}
	@Override
	public Iterator iterator() {
		return new SIterator();
	}
		private class SIterator implements Iterator{
		private int cur;
		public SIterator(){
			this.cur=0;
	}
	@Override
	public boolean hasNext() {
		return cur<N;
	}
	@Override
	public T next() {
		return eles[cur++];
	}
	}
}
//测试代码
public class Test {
	public static void main(String[] args) throws Exception {
		SequenceList<String> squence = new SequenceList<>(5);
		//测试遍历
		squence.insert(0, "姚明");
		squence.insert(1, "科比");
		squence.insert(2, "麦迪");
		squence.insert(3, "艾佛森");
		squence.insert(4, "卡特");
		for (String s : squence) {
			System.out.println(s);
		}
	}
}

顺序表的容量可变

当我们使用SequenceList时,先new SequenceList(5)创建一个对象,创建对象时就需要指定容
器的大小,初始化指定大小的数组来存储元素,当我们插入元素时,如果已经插入了5个元素,还要继续插入数
据,则会报错,就不能插入了。这种设计不符合容器的设计理念,因此我们在设计顺序表时,应该考虑它的容量的
伸缩性。
考虑容器的容量伸缩性,其实就是改变存储数据元素的数组的大小,那我们需要考虑什么时候需要改变数组的大
小?
1.添加元素时:
添加元素时,应该检查当前数组的大小是否能容纳新的元素,如果不能容纳,则需要创建新的容量更大的数组,我
们这里创建一个是原数组两倍容量的新数组存储元素。
在这里插入图片描述
2.移除元素时:
移除元素时,应该检查当前数组的大小是否太大,比如正在用100个容量的数组存储10个元素,这样就会造成内存
空间的浪费,应该创建一个容量更小的数组存储元素。如果我们发现数据元素的数量不足数组容量的1/4,则创建
一个是原数组容量的1/2的新数组存储元素。
在这里插入图片描述
顺序表的容量可变代码:

//顺序表代码
public class SequenceList<T> implements Iterable<T>{
	//存储元素的数组
	private T[] eles;
	//记录当前顺序表中的元素个数
	private int N;
	//构造方法
	public SequenceList(int capacity){
		eles = (T[])new Object[capacity];
		N=0;
	}
	//将一个线性表置为空表
	public void clear(){
		N=0;
	}
	//判断当前线性表是否为空表
	public boolean isEmpty(){
		return N==0;
	}
	//获取线性表的长度
	public int length(){
		return N;
	}
	//获取指定位置的元素
	public T get(int i){
		if (i<0 || i>=N){
		throw new RuntimeException("当前元素不存在!");
	}
		return eles[i];
	}
	//向线型表中添加元素t
	public void insert(T t){
		if (N==eles.length){
		resize(eles.length*2);
	}
		eles[N++] = t;
	}
	//在i元素处插入元素t
	public void insert(int i,T t){
		if (i<0 || i>N){
			throw new RuntimeException("插入的位置不合法");
	}
	//元素已经放满了数组,需要扩容
		if (N==eles.length){
		resize(eles.length*2);
	}
	//把i位置空出来,i位置及其后面的元素依次向后移动一位
		for (int index=N-1;index>i;index--){
			eles[index]=eles[index-1];
		}
		//把t放到i位置处
		eles[i]=t;
		//元素数量+1
		N++;
	}
	//删除指定位置i处的元素,并返回该元素
	public T remove(int i){
		if (i<0 || i>N-1){
			throw new RuntimeException("当前要删除的元素不存在");
		}
		//记录i位置处的元素
		T result = eles[i];
		//把i位置后面的元素都向前移动一位
		for (int index=i;index<N-1;index++){
			eles[index]=eles[index+1];
		}
		//当前元素数量-1
			N--;
		//当元素已经不足数组大小的1/4,则重置数组的大小
		if (N>0 && N<eles.length/4){
			resize(eles.length/2);
		}
		return result;
	}
	//查找t元素第一次出现的位置
	public int indexOf(T t){
		if(t==null){
			throw new RuntimeException("查找的元素不合法");
		}
		for (int i = 0; i < N; i++) {
			if (eles[i].equals(t)){
			return i;
		}
		}
		return -1;
	}
	//打印当前线性表的元素
	public void showEles(){
		for (int i = 0; i < N; i++) {
			System.out.print(eles[i]+" ");
		}
			System.out.println();
		}
		@Override
		public Iterator iterator() {
			return new SIterator();
		}
		private class SIterator implements Iterator{
			private int cur;
			public SIterator(){
			this.cur=0;
			}
		@Override
		public boolean hasNext() {
			return cur<N;
		}
		@Override
		public T next() {
			return eles[cur++];
		}
	}
	//改变容量
	private void resize(int newSize){
		//记录旧数组
		T[] temp = eles;
		//创建新数组
		eles = (T[]) new Object[newSize];
		//把旧数组中的元素拷贝到新数组
		for (int i = 0; i < N; i++) {
			eles[i] = temp[i];
		}
		}
		public int capacity(){
			return eles.length;
	}
}
//测试代码
public class Test {
	public static void main(String[] args) throws Exception {
		SequenceList<String> squence = new SequenceList<>(5);
		//测试遍历
		squence.insert(0, "姚明");
		squence.insert(1, "科比");
		squence.insert(2, "麦迪");
		squence.insert(3, "艾佛森");
		squence.insert(4, "卡特");
		System.out.println(squence.capacity());
		squence.insert(5,"aa");
		System.out.println(squence.capacity());
		squence.insert(5,"aa");
		squence.insert(5,"aa");
		squence.insert(5,"aa");
		squence.insert(5,"aa");
		squence.insert(5,"aa");
		System.out.println(squence.capacity());
		squence.remove(1);
		squence.remove(1);
		squence.remove(1);
		squence.remove(1);
		squence.remove(1);
		squence.remove(1);
		squence.remove(1);
		System.out.println(squence.capacity());
	}
}

get(i):不难看出,不论数据元素量N有多大,只需要一次eles[i]就可以获取到对应的元素,所以时间复杂度为O(1);
insert(int i,T t):每一次插入,都需要把i位置后面的元素移动一次,随着元素数量N的增大,移动的元素也越多,时
间复杂为O(n);
remove(int i):每一次删除,都需要把i位置后面的元素移动一次,随着数据量N的增大,移动的元素也越多,时间复
杂度为O(n);
由于顺序表的底层由数组实现,数组的长度是固定的,所以在操作的过程中涉及到了容器扩容操作。这样会导致顺
序表在使用过程中的时间复杂度不是线性的,在某些需要扩容的结点处,耗时会突增,尤其是元素越多,这个问题
越明显

java中ArrayList实现
java中ArrayList集合的底层也是一种顺序表,使用数组实现,同样提供了增删改查以及扩容等功能。
1.是否用数组实现;
2.有没有扩容操作;
3.有没有提供遍历方式;

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

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

相关文章

用HTML+CSS做一个漂亮简单的个人音乐网页

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Obsidian配置图床(PicGo:SM.MS)

前言 在使用了一段时间obsidian之后&#xff0c;发现了一个很致命的问题&#xff0c;就是图片的存储&#xff0c;与传统的富文本编辑器不一样的是markdown属于纯文本语言&#xff0c;文字和图片是分离的&#xff0c;这就导致了当你想插入图片时&#xff0c;发现图片被保存在了…

[附源码]计算机毕业设计驾校预约管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

项目运营后阶段发力(有人问我字节为啥要考算法,然后我就跑去问我同学)

前言 我记得之前有人跑过来问我&#xff1a;你知道为啥字节面试总会考算法吗&#xff1f;我没有回答&#xff0c;一方面是算法是大厂必考的东西&#xff0c;既然是必须的东西究竟个为什么有点白费心机&#xff0c;第二方面我没有进去过字节&#xff0c;所以我也拿捏不准为什么。…

元宇宙是下个风口?浅析元宇宙中的新商业模式

元宇宙的热度似乎还是高涨不下&#xff0c;那么今天由林工来浅析一下元宇宙有哪些机会可以把握&#xff1f; 随着2021年&#xff0c;扎克伯格将公司改名为Meta&#xff0c;宣布将一家社交媒体公司转变为一家元宇宙公司&#xff0c;并计划投入五千万美元来构建与元宇宙,许多科技…

保姆式计算机组件简介

目录 1&#xff0c;cpu 主频 cpu缓存&#xff08;位于cpu与内存的临时储存器&#xff0c;容量小但交换速度快&#xff09; 2&#xff0c;memory&#xff08;也就是储存器&#xff09; 1&#xff0c;外存储器 2&#xff0c;内存储器 3&#xff0c;l/o 4&#xff0c;bus&a…

【消息中间件】RocketMQ如何集成到SpringBoot

目录 ​ 一、前言 二、RocketMQ如何集成到SpringBoot项目 1、如果不用SpringBoot项目 1.1、引入依赖 1.2、启动BrokerStartup和NamesrvStartup服务端 2&#xff09;启动NamesrvStartup 1.3、生产者创建并启动以及发送消息 1.4、消费者创建并启动 2、RocketMQ集成到Sp…

谷歌seo外链建设指南

今天我分享的这些绝对是最接地气、最基础、最实用的&#xff0c;你用来做英文外链用这些技巧也会事半功倍。 发外链之前&#xff0c;首先是搜索&#xff0c;搜索可以发外链的地方。 通常只有两处地方可以让我们又简单、又轻松的发布优质的免费外链。 这两处地方就是博客和论…

客快物流大数据项目(九十五):ClickHouse的CollapsingMergeTree入了解

文章目录 ClickHouse的CollapsingMergeTree入了解 一、创建CollapsingMergeTree引擎表的语法 二、创建CollapsingMergeTree引擎的表

关于Integer

/*** 基本数据类型 包装类型* ----------------------------------------------* byte java.lang.Byte (父类是java.lang.Number)* short java.lang.Short (父类是java.lang.Number)* int …

基于微信小程序的springboot客运汽车票购票系统源码和论文

在客运公司工作 7 年之余&#xff0c;对客运管理的难度深有感触。特别是在春运期 间购票难依旧是长途汽车订票的一大难题。长途汽车和火车的订票管理虽然有 差异&#xff0c;但大体上是相同的。长途汽车在售票的过程中需要对旅客的起始地、目 的地、车次、订票和退票进行管理。…

论文精读:《DETR3D: 3D Object Detection from Multi-view Images via 3D-to-2D Queries》

DETR3D: 3D Object Detection from Multi-view Images via 3D-to-2D Queries 文章目录DETR3D: 3D Object Detection from Multi-view Images via 3D-to-2D Queries论文精读摘要&#xff08;Abstract&#xff09;1. 介绍&#xff08;Introduction&#xff09;2. 相关工作&#x…

优维科技EasyOps®一体化运维平台入选“大信创产品目录”

以云计算、大数据为代表的新一代信息技术正在带来新的架构模式和应用模式&#xff0c;IT行业整个技术体系正面临一次大的换代升级机遇。在新技术更新换代的同时&#xff0c;中国IT产业也正面临前所未有的供应链安全问题&#xff0c;自主可控的信息技术应用创新&#xff08;信创…

Oracle项目管理之Primavera Unifier三种管理员模式

目录 一、系统管理员 二、公司管理员 三、项目管理员 Oracle Primavera Unifier 中有不同类型或级别的管理员&#xff0c;它们包括&#xff1a; 站点管理员&#xff08;也称为系统管理员&#xff09;公司管理员项目管理员或外壳管理员&#xff08;项目/外壳管理员&#xff0…

Servlet(三):基于Servlet实现程序、Cookie和Session、实现用户登录、上传文件

目录表白墙Cookie和Session实现用户登录上传文件表白墙 【服务器版的表白墙】 在之前通过前端代码实现的表白墙有一个问题&#xff0c;当我们关闭页面后&#xff0c;表白的数据也就丢失了&#xff0c;下面我们要做的是做一个服务器版的表白墙&#xff0c;这样即使关闭页面&…

RocketMq01_概述及背景、主题、标签、队列、生产者、消费者、注册中心、工作流程

文章目录①. RocketMQ - 概述、背景②. 消息、主题、标签、队列、唯一标识③. 生产者、消费者、NameServer、Broker④. RocketMq - 工作流程⑤. Topic的创建模式、读写队列①. RocketMQ - 概述、背景 ①. RocketMQ是⼀款阿⾥巴巴开源的消息中间件。2016年11⽉28⽇,阿⾥巴巴向Ap…

Metal每日分享,波动滤镜/涂鸦滤镜效果

本案例的目的是理解如何用Metal实现图像波动效果滤镜&#xff0c;还可类似涂鸦效果&#xff0c;主要就是对纹理坐标进行正余弦偏移处理&#xff1b; Demo HarbethDemo地址 实操代码 // 波动效果 let filter C7Fluctuate.init(extent: 50, amplitude: 0.003, fluctuate: 2.5…

GPB外链是什么?

GPB外链的意思是&#xff1a;Guangsuan Private Backlinks 全称&#xff1a;光算科技私人链接 拥有高质量&#xff0c;高权重&#xff0c;100%包收录的特点&#xff0c;且dofollow 因其效果明显&#xff0c;因其效果明显受到市场上广大的外贸SEO从业者喜欢。 它可以帮助网站…

图神经网络GNN

前言 图与图的表示 图是由一些点和一些线构成的&#xff0c;能表示一些实体之间的关系&#xff0c;图中的点就是实体&#xff0c;线就是实体间的关系。如下图&#xff0c;v就是顶点&#xff0c;e是边&#xff0c;u是整张图。attrinbutes是信息的意思&#xff0c;每个点、每条…

SQLite Expert 5.X 通用注册版-你的SQL好帮手

SQLITE 专家&#xff1a;发现 SQLITE 的力量 SQLite Expert 是一个强大的工具&#xff0c;旨在简化 SQLite3 数据库的开发。它是一个功能丰富的SQLite管理和开发工具&#xff0c;旨在满足所有用户的需求&#xff0c;从编写简单的 SQL 查询到开发复杂的数据库。 图形界面支持所…