数据结构-线性表-顺序表(JAVA)

暑假打算学一下数据结构,顺序表这个东西看着思路这么简单,没想到实现起来却有这么多细节。

首先声明一个接口,包括线性表所有需要的方法。这是线性表的基本部分。

public interface List<T> {
boolean isEmpty();				//判断是否为空
int size();						//线性表元素个数(长度)
T get(int i);					//返回第i个元素
void set(int i,T x);			//设置第i个元素为x
String toString();				//返回线性表所有元素为字符串
int insert(int i,T x);			//插入x作为第i和元素,x!=null返回值为x的序号
int insert(T x);				//在表的最后插入x,返回值为x的序号
T remove(int i);				//删除第i个元素,返回值为删除的元素
void clear();					//清除这个表
int search(T key);				//查找首次和key相等的元素,返回值为其下标
boolean contains(T key);		//查询是否包含key
int insertDifferent(T x);		//插入不重复元素
int remove(T key);				//删除首次出现和key相等的元素,返回其下标
boolean equals(Object obj);		//判断两个线性表是否相等
void addAll(List<T> list);		//在这个单链表中添加list所有元素,集合并运算
}

然后线性表内容继承前面的接口,实现里面的基本功能。

public class SeqList <T> implements List<T>{
	protected Object[] element;				//存储元素
	protected int n;						//存储现在元素的个数
	
	public SeqList(){
		this(64);
	}
	public SeqList(T[] values){
		this(values.length);
		for(int i=0;i<values.length;i++){
			element[i]=values[i];
			n=element.length;
		}
	}
	public SeqList(int length){
		element=new Object[length];
	}
	
	public boolean isEmpty() {				//判断是否为空
		return n==0;						//如果是0返回true
	}

	public int size() {						//线性表元素个数(长度)
		return n;							//返回n的值
	}

	public T get(int i) {				//返回第i个元素
		if(i>=0&&i<n)return (T) element[i];
		return null;						//如果在0-n范围内,返回这个元素,否则返回null
	}
											//设置第i个元素为x,如果x是null或者i不在范围内都抛出异常
	public void set(int i, T x) {		
		if(x==null)throw new NullPointerException("x==null");
		else if(i>=0&&i<n)element[i]=x;
		else throw new java.lang.IndexOutOfBoundsException(i+"");
	}
	
	public String toString(){				//返回这个链表的所有元素
		String str=this.getClass().getName()+"(";
		if(this.n>0)str+=element[0].toString();
		for(int i=1;i<n;i++){
			str+=","+element[i].toString();
		}
		str+=")";
		return str;
	}
	
	public int insert(int i, T x) {	//设置第i个元素为x
		if(x==null)throw new NullPointerException("x==null");	//如果x为空直接抛出异常
		i=i<0?0:i>n?n:i;					//如果x超出边界值,x取边界值
		Object[] source=element;			//把这个数组拷贝给另一个数组
		if(n==element.length){				//如果数据数量到了数组的范围,那数组长度扩大二倍,然后把刚才拷贝的数组第i位以前的赋值过去。
			element=new Object[source.length*2];		
			for(int j=0;j<i;j++)element[j]=source[j];
		}
		for(int j=n-1;j>=i;j--)
			element[j+1]=source[j];			//后面的数据需要移项
		n++;								//既然是插入元素,那元素个数是一定要增加的
		element[i]=x;						//然后把第i个设置为x
		return i;
	}

	public int insert(T x) {				//在顺序表的最后插入一个元素,调用上一个函数
		int n=this.n;
		insert(n,x);
		return n;
	}

	public T remove(int i) {				//删除第i个元素
		if(n>=0&&i>=0&&i<n){				//如果i在范围之内执行这个操作
			T old=(T)element[i];			//先把第i个元素储存起来
			for(int j=i;j<n;j++)
				element[j]=element[j+1];	//把第i个元素后面的都往前移动一格
			element[n-1]=null;				//把初始的最后一个元素清空
			n--;							//因为是删除操作,自然要把长度减1啦
			return old;						//把刚才储存起来的元素返回过去
		}
		return null;
	}

	public void clear() {
		for(int i=0;i<n;i++)element[i]=null;
		n=0;
	}

	public int search(T key) {			//查找首个和key相等的元素,返回下标,如果没有返回-1
		for(int i=0;i<n;i++){
			if(key.equals(element[i]))return i;
		}
		return -1;
	}

	public boolean contains(T key) {	//查询顺序表是否包含key,调用search函数,看其是否为-1
		return search(key)!=-1;
	}

	public int insertDifferent(T x) {	//插入不重复元素,查找不成功时候,尾插入
		int i=search(x);
		if(i==-1){
		i=n;		
		insert(x);
		}
		return i;
	}

	public int remove(T key) {			//删除首次出现和key相等的元素,返回其下标
		int i=search(key);		//先查找其下标
		if(i!=-1)remove(i);		//如果存在就删除
		return i;
	}

	public void addAll(List<T> list) {	
		if(list==null)throw new NullPointerException("x==null");	//如果list为空抛出异常
		int length=list.size();			
		Object[] source=element;
		if(element.length<n+length){		//如果添加后超过范围,那element范围扩大
			element=new Object[n+length];
			for(int i=0;i<n;i++)
				element[i]=source[i];
		}
		for(int i=0;i<length;i++){
			element[i+n]=list.get(i);
		}
		n+=length;
	}
}

最后是测试类,测试里面一些函数是否完善。

public class SeqListTest {

	public static void main(String[] args) {
		List l=new SeqList<Integer>();
		for(int i=0;i<10;i++)l.insert(i);
		System.out.println(l.toString());
		l.remove(5);
		l.remove(6);
		System.out.println(l.toString());
		l.set(1, 2);
		l.set(2, 1);
		System.out.println(l.toString());
		List l2=new SeqList<Integer>();
		l2.addAll(l);
		l.clear();
		System.out.println(l.toString());
		System.out.println(l2.toString());
	}
}

 

发现写的还行O(∩_∩)O

 

参考书籍《数据结构JAVA版》第四版。

### Java 线性表数据结构设计与实现 #### 一、线性表概述 线性表是一种基本的数据结构,其特点是元素之间存在一对一的关系。在线性表中,除了第一个和最后一个元素外,其他每个元素都有唯一的一个前驱和后继。 #### 二、顺序表实现 顺序表线性表的一种存储方式,在内存中占用连续的空间来保存各个节点的信息。下面是一个简单的顺序表示例: ```java public class ArrayLinearList { private Object[] elements; private int size; public ArrayLinearList() { this.elements = new Object[10]; this.size = 0; } // 添加元素到列表末尾 public boolean add(Object element) { ensureCapacity(size + 1); elements[size++] = element; return true; } // 获取指定位置上的元素 public Object get(int index) { checkIndex(index, false); return elements[index]; } // 移除并返回指定索引处的元素 public Object remove(int index){ rangeCheck(index); Object oldValue = elements[index]; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elements, index+1, elements, index, numMoved); elements[--size] = null; // Let gc do its work return oldValue; } // 扩展数组容量以容纳更多元素 private void ensureCapacity(int minCapacity) { if(minCapacity >= elements.length){ @SuppressWarnings("unchecked") Object[] oldElements = elements; elements = new Object[Math.max(2 * elements.length,minCapacity)]; System.arraycopy(oldElements, 0, elements, 0,oldElements.length ); } } // 检查给定索引是否有效 private void checkIndex(int index,boolean isAddOperation){ if(isAddOperation &&index>size || !isAddOperation&&index>=size||index<0){ throw new IndexOutOfBoundsException(); } } } ``` 此代码展示了如何创建一个基于数组的顺序表类 `ArrayLinearList`[^1]。 #### 三、链表实现 链表也是一种常见的线性表实现形式,它由一系列结点组成,这些结点不必在物理上相邻存放在一起;而是通过指针链接起来形成逻辑上的序列关系。以下是单向链表的具体实现: ```java class Node<T>{ T data; Node next; public Node(T data){ this.data=data; this.next=null; } } public class SinglyLinkedList<T> { private Node head; private int length; public SinglyLinkedList(){ this.head=null; this.length=0; } // 向链表头部插入新节点 public void insertAtBeginning(T newData){ Node newNode=new Node(newData); newNode.next=head; head=newNode; length++; } // 删除头节点 public T deleteFromBeginning(){ if(head==null)return null; T temp=(T)(head.data); head=head.next; length--; return temp; } // 显示整个链表的内容 public String toString(){ StringBuilder sb=new StringBuilder("["); Node current=head; while(current!=null){ sb.append(current.data.toString()); if(current.next != null)sb.append(", "); current=current.next; } sb.append("]"); return sb.toString(); } } ``` 这段代码定义了一个泛型化的单向链表类 `SinglyLinkedList`, 并实现了几个常用的操作函数[^2]. 对于双向链表,则是在上述基础上增加了对前后两个方向的支持,即每个节点不仅有指向下一个节点的引用(`next`)还有指向前一个节点的引用(`prev`). 这样可以更方便地遍历链表以及执行某些特定操作. 最后需要注意的是,无论是哪种类型的线性表,在实际应用过程中都需要考虑边界条件处理(比如越界访问)、异常情况下的健壮性和性能优化等问题.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值