线性表(1)——顺序表

概念:线性表的顺序存储结构称为顺序表,它使用一维数组依次存放线性表的数据元素。顺序表是一种随机存取结构。

下面我们来看一下顺序表类的设计与实现。

首先声明顺序类SeqList的泛型如下,有两个具有保护权限的成员变量element和n,element数组存放数据元素,元素类型为T,n表示顺序表元素个数,-1<n<element.length。

顺序表的实现代码如下:

package dataStructure;

//顺序表类,实现ADTList<T>声明的方法,T表示数据元素

public class SeqList<T> extends Object{
	protected Object[] element;		//对象数组存储顺序表的数据元素,保护成员
	protected int n;				//顺序表元素个数
	//构造容量为null的空表
	public SeqList(int length) {
		this.element=new Object[length];
		this.n=0;
	}
	//创建容量默认的空表,构造方法重载
	public SeqList() {
		this(64);    //调用上一个构造方法
	}
	//构造顺序表
	public SeqList(T[] values) {
		this(values.length); //创建容量为values.length的空表
		for(int i=0;i<values.length;i++)
			this.element[i]=values[i];
		this.n=element.length;
	}
	//判断顺序表是否为空,为空返回true
	public boolean isEmpty() {
		return this.n==0;
		
	}
	//返回顺序表元素个数
	public int size() {
		return this.n;
	}
	//返回第i个元素,越界返回null
	public T get(int i) {
		if(i>=0&&i<this.n)
			return (T)this.element[i];
		
		return null;
		
	}
	//设置第i个元素的值为x
	public void  set(int i,T x) {
		if(x==null)
			throw new NullPointerException("x==null");
		if(i>=0&&i<this.n)
			this.element[i]=x;
		else throw new java.lang.IndexOutOfBoundsException(i+"");
	}
	//返回顺序表所有元素的描述字符串,形式为“(,)”,覆盖Object类的toString()方法
	public String toString() {
		String str=this.getClass().getName()+"(";//返回类名
		if(this.n>0)
			str+=this.element[0].toString();
		for(int i=1;i<this.n;i++)
			str+=","+this.element[i].toString();
		return str+")";
	}
	public int insert(int i,T x) {
		if(x==null)
			throw new NullPointerException("x==null");  //抛出空对象异常
		if(i<0)
			i=0;
		if(i>this.n)
			i=this.n;   //插入在最后
		Object [] source=this.element;
		if(this.n==element.length) {
			this.element=new Object[source.length*2];
			//复制当前数组前i-1个元素
			for(int j=0;j<i;j++)
				this.element[j]=source[j];
		}
		//从i开始至表尾的元素向后移动,次序从后向前
		for(int j=this.n-1;j>=i;j--)
			this.element[j+1]=source[j];
		this.element[i]=x;
		this.n++;
		return i;    //返回x序号
			
	}
	public int insert(T x) {
		return this.insert(this.n ,x);
	}
	public T remove(int i) {
		
		if(i>=0&&i<this.n&&this.n>0) {
			T old=(T)this.element[i];
			for(int j=i;j<this.n-1;j++)
			{
				this.element[j]=this.element[j+1];
			}
			this.element[this.n-1]=null;
			this.n--;
			return old;
			
		}else {
		return null;}
		
		
	}
	public void clear() {
		for(int i=0;i<this.n;i++) {
			this.element[i]=null;
		}
	}
	//顺序查找首次出现与key相等元素,返回元素符号
	public int search(T key) {
		for(int i=0;i<this.n;i++) {
			if(key.equals(this.element[i]))
				return i;
			
		}
		return -1;   //空表或者未找到
	}
	//判断是否包含关键字为key元素
	public boolean contains(T key) {
		return this.search(key)!=-1;
	}
}

顺序表的效率分析:

判空isEmpty(),求长度size()以及获取元素例如get()以及set()等方法,时间复杂度都为O(1),而插入和删除以及toString()方法的时间复杂度都为O(n),其中插入和删除的时候平均移动表的一半,当n很大的时候,表的效率很低。顺序表适合用于查找,但如果需要频繁的插入以及删除,这需要使用到单链表。

求解Josephus环问题

本题目的:

(1)声明顺序表对象存储数据元素集合,以便插入、从操作并分析操作效率,删除操作需要返回被删除元素。

(2)线性表的泛型参数T的实际参数不能是基本数据类型,必须是对象,此处是String。

(3)环形的逻辑结构设计。按循环方式遍历顺序表。

约瑟夫环问题:古代某法官要判决number个犯人的死刑,他有一条荒唐的法律,将犯人站成一个圆圈,从第start个人开始数起,每数到第distance个犯人,就拉去处决,然后将从下一个人开始数distance个,数到的人再拉出去处决,直到剩下最后一个犯人予以赦免。当number=5,start=0,distance=2时,约瑟夫环问题执行过程如下所示:

在这里插入图片描述
使用顺序表求解这个问题,算法描述如下:

(1)创建一个拥有number个元素的顺序表对象list。

(2)从第start个元素开始,依次计数,每数到distance,就将该元素删除。

(3)重复计数并删除元素,直到剩下一个元素

代码如下:

package dataStructure;
import dataStructure.*;
public class Josephus {
	//创建Josephus环并求解,参数指定环长度,起始位置,计数
	public Josephus(int number,int start,int distance) {
		System.out.print("Josephus("+number+","+start+","+distance+"),");
		//创建顺序表实例,构造方法参数指定顺序表容量
		SeqList<String>list=new SeqList<String>(number);
		for(int i=0;i<number;i++)
			list.insert((char)('A'+i)+"");
		System.out.println(list.toString());
		int i=start;
		while(list.size()>1)
		{
			i=(i+distance-1) % list.size();
			System.out.print("删除"+list.remove(i)+",");
			System.out.println(list.toString());
		}
		System.out.println("被赦免者是"+list.get(0).toString());
	}
		public static void main(String [] args) {
			new Josephus(5,0,2);
		}

}

结果截图:
在这里插入图片描述
顺序表的浅拷贝与深拷贝

(1)顺序表的浅拷贝
在这里插入图片描述
分析:
1.当成员变量的数据类型是基本数据类型时,浅拷贝能够实现对象复制功能。

2.当成员变量的数据类型是引用数据类型时,浅拷贝复制的只是数组引用或者对象引用,并没有实现对象复制功能。此时需要深拷贝。

(2)顺序表的深拷贝

当一个类包含数组或者对象引用等引用类型的成员变量时,该类声明的拷贝构造方法,不仅要复制对象的所有基本类型成员变量值,还要引用类型变量申请存储空间,并复制其中所有元素/对象,这种就叫做深拷贝。
在这里插入图片描述
两者的区别:

简单来说就是浅拷贝能复制基本类型的属性,引用类型的属性复制,复制栈中的变量 和 变量指向堆内存中的对象的指针,不复制堆内存中的对象。
在这里插入图片描述
而深拷贝复制基本类型的属性;引用类型的属性复制,复制栈中的变量 和 变量指向堆内存中的对象的指针和堆内存中的对象。

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值