1.静态数组与动态数组

静态数组的特点:

数组的长度一旦确定则不可更改

数组只能存储同一类型的数据

数组中每个存储空间地址是连续且相等的

数组提供角标的方式访问元素

缺点:

长度不可变,数据量大了怎么办?扩容可以解决(创建新数组)

地址连续且提供角标,访问很快,但移动元素只能挨个挨个移

最重要的,数组只有length这个属性,没有其他的方法!

动态数组,主要是解决其缺点3:

将数组本身和在其上的相关操作进行封装,生成一个类

今后只需创建该类的对象,就可以进行对其所包装的数组进行增删改查操作

为什么要说动态数组的,其实动态数组就是顺序存储结构的具体实现!

2.动态数组——线性表的顺序存储结构

线性表

零个或多个数据元素的有限序列

可通过索引访问元素

除了第一个元素没有前驱,最后一个元素没有后继,其他元素都有唯一的前驱和后继

是否允许存储重复元素(看需求)

是否允许存储空值NULL(看需求)

是否允许元素有序(这必须),有序指元素的进场顺序和退场顺序一致

是否允许元素顺序(看需求),顺序指元素在该数据结构内部是否已经被排序

用动态数组实现的线性表也称为顺序表

java动态开辟数组和静态的区别 动态数组和静态数组_ci


List 线性表接口定义

1.定义接口

public interface List<E> //E代表任意数据类型(数字、字符串等)支持泛型

2.定义功能

public int getSize();		//获取列表中元素的个数
	public boolean isEmpty();	//判断当前列表是否为空
	public void add(int index,E e);	//在列表中指定角标index处添加元素e
	public void addFirst(E e);		//在列表中第一个位置添加元素e
	public void addLast(E e);		//在列表中最后一个位置添加元素e
	public E get(int index);		//获取列表中指定角标index处的元素
	public E getFirst();			//获取列表中第一个位置的元素,E代表返回这个元素
	public E getLast();				//获取列表中最后一个位置的元素
	public E remove(int index);		//删除列表中指定角标位置的元素并返回
	public E removeFirst();			//删除列表中第一个位置的元素
	public E removeLast();			//删除列表中最后一个位置的元素
	public void set(int index,E e);	//修改列表中指定角标index位置处的元素为新元素e
	public boolean contains(E e);	//判断列表中是否包含指定元素e
	public int find(E e);			//在列表中查找指定元素e的角标
	public void removeElement(E e);	//在列表中删除指定元素e
	public void clear();			//清空列表

ArrayList 顺序表类定义

  1. 定义类
public class ArrayList<E> implements List<E> //ArrayList是List的一种具体实现
  1. 定义成员属性
private E[] data; //用于存储数据,data.length表示容器的容量(capacity)
private int size; //表示顺序表中当前有效元素的个数,
size==0表示顺序表为空表
  1. 定义构造函数
public ArrayList() //默认创建容量为N的容器(N自行定义),在此默认为10
public ArrayList(int capacity) //创建指定容量为capacity的容器
public ArrayList(E[] arr) //将一个数组初始化为一个顺序表
  1. 定义成员函数
    实现List接口函数
public int getCapacity() //获取顺序表的最大容量
private void resize(int newLen) //改变顺序表长度为新长度newLen
public void swap(int i,int j) //交换顺序表中指定角标i,j的两个元素
public String toString() //返回该顺序表的字符串形式
package 数据结构与算法;
	//动态数组实现的线性表->顺序表
		
	/* List	
	 * 	——ArrayList
	 * 增删O(n) 改查O(1)
	 * 1.元素是否排序? 没有
	 * 2.元素是否允许重复?允许
	 * 3.元素是否允许空值?允许
	 * 4.元素是否有序?元素的进场顺序和出场顺序一致
	 * */
	public class ArrayList<E> implements List<E>{
		private E[] data;	//容器-存储元素 data.length 最大容量
		private int size;	//当前列表中元素的个数 有效长度
		private static final int DEFAULT_CAPACITY=10;
		public ArrayList(){	//默认构造函数中创建一个容量为10的列表
			this(DEFAULT_CAPACITY);
		}
		public ArrayList(int capacity){	//构造函数中创建一个指定容量为capacity的列表
			if(capacity<0){		//非法角标
				capacity=DEFAULT_CAPACITY;
			}
			this.data=(E[]) new Object[capacity];	//强转
			this.size=0;
		}
	
		public void add(int index, E e) {		//指定角标添加指定元素
			if(index<0||index>size) {			//应为多了一个元素所以要考虑有效容量
				throw new IllegalArgumentException("角标非法");	//非法参数异常
			}
			if(size==data.length) {				//如果有效长度等于最大容量
				resize(data.length*2);			//重置容量
			}
			for(int i=size;i>index;i--) {
				data[i]=data[i-1];
			}
			data[index]=e;
			size++;
		}
		public void addFirst(E e) {
			add(0,e);
		}
	
		public void addLast(E e) {
			add(size,e);
		}
	
		public E remove(int index) {	//删除指定角标元素并返回新的数组
			if(index<0||index>=size) {
				throw new IllegalArgumentException("角标非法");
			}
			E res=data[index];			//取出指定角标元素
			for(int i=index;i<size-1;i++) {
				data[i]=data[i+1];
			}
			size--;						//删除了元素所以减
			if(size==data.length/4&&data.length>DEFAULT_CAPACITY) {	//同时满足大于一定长度时缩容
				resize(data.length/2);
			}
			return res;
		}
	
		public E removeFirst() {
				return remove(0);
		}
	
		public E removeLast() {
			return remove(size-1);
		}
		
		@Override
		public void removeElement(E e) {
			int index=find(e);
			if(index!=-1) {
				remove(index);
			}
		}
		
		private void resize(int newLen) {	//创建一个新的数组即扩容
			E[] newData=(E[]) new Object[newLen];
			for(int i=0;i<Math.min(data.length,newData.length);i++) {	//扩容取决于小数组谁小遍历谁
				newData[i]=data[i];
			}
			data=newData;
		}
		
		public int getSize() {
			return this.size;
		}
		public boolean isEmpty() {
			return this.size==0;
		}
		
		public E get(int index) {
			if(index<0||index>=data.length) {
				throw new IllegalArgumentException("角标非法");
			}
			return data[index];
		}
		public E getFirst() {
			return get(0);
		}
		public E getLast(){
			return get(size-1);
		}
		
		public void set(int index, E e) {
			if(index<0||index>=size) {
				throw new IllegalArgumentException("角标非法");
			}
			data[index]=e;
		}
		
		public int find(E e) {
			for(int i=0;i<size;i++) {
				if(data[i]==e) {
					return i;
				}
			}
			return -1;
		}
		public boolean contains(E e) {
			return find(e)!=-1;	//不等于-1说明存在返回一个true
		}
		public int getCapacity(){	//获取当前链表的最大容量
			return data.length;
		}
		public void clear() {	//清空数组
			this.data=(E[]) new Object[DEFAULT_CAPACITY];	//相当于重建一个数组
			this.size=0;		//重置size为0
		}
		public void swap(int i,int j){
			if(i<0||i>=size||j<0||j>=size) {
				throw new IllegalArgumentException("角标非法");
			}
			E temp=data[i];
			data[i]=data[j];
			data[j]=temp;
		}
		@Override
		public String toString() {
			StringBuilder sb=new StringBuilder();
			if(isEmpty()) {
				sb.append(String.format("ArrayList:[] %d/%d \n",size,data.length));//String.format字符串格式化
			}else {
				sb.append("ArtrayList:[");
				for(int i=0;i<size;i++) {
					if(i==size-1) {
						sb.append(data[i]+"]");//最后一个元素
					}else {
						sb.append(data[i]+",");
					}
				}
				sb.append(String.format("%d/%d \n",size,data.length));
			}
			return sb.toString();
		}
	}

3.动态数组——栈的顺序存储结构

栈本质上就是一种特殊的线性表
栈是限定仅在表尾进行插入和删除操作的线性表,先进后出的结构
元素插入叫进栈,元素删除叫出栈
是否允许存储重复元素(看需求)
是否允许存储空值NULL(看需求)
是否允许元素有序(这必须),有序指元素的进场顺序和退场顺序一致
是否允许元素顺序(不需要),顺序指元素在该数据结构内部是否已经被排序
用动态数组实现的线性表也称为顺序栈
Stack 栈接口定义
1.接口定义

public interface Stack<E>

2.功能定义

public int getSize(); //获取栈中元素的个数
public boolean isEmpty(); //判断栈是否为空
public void push(E e); //将指定元素e进栈
public E pop(); //出栈一个元素
public E peek(); //获取当前栈顶元素
public void clear(); //清空栈

ArrayStack 顺序栈类定义

  1. 定义类
public class ArrayStack<E> implements Stack<E>
  1. 定义成员属性
private ArrayList<E> list //栈本质上就是一种线性表,所以此处用顺序表实现一个栈
  1. 定义构造函数
public ArrayStack() //创建栈且默认容量为10
public ArrayStack(int capacity) //创建栈且指定容量capacity
  1. 定义成员函数
    实现Stack接口函数
public int getCapacity() //获取栈的最大容量
public String toString() //返回该顺序栈的字符串形式

4.动态数组——双端栈的顺序存储结构
双端栈:是指从一个线性表的两端当做栈底进行分别的入栈和出栈操作
ArrayStackDoubleEnd 顺序双端栈类定义
1.定义类

public class ArrayStackDoubleEnd<E> implements Stack<E>

2.定义成员变量

public static final int L=0; //表示左边的栈
public static final int R=1; //表示右边的栈
private E[] data; //本质还是一个线性表
private int left; //左边栈的栈顶 开始为­1
private int right; //右边栈的栈顶 开始为data.length

3.定义构造函数

public ArrayStackDoubleEnd() //创建默认容量为

DEFAULT_SIZE的栈

public ArrayStackDoubleEnd(int capacity)//创建容量为指定capacity的栈

4.定义成员函数
实现Stack接口函数

public void push(int which,E e) //向指定栈which进栈指定元素e
public E pop(int which) //指定栈which出栈一个元素
private void resize(int newLen) //改变栈的容量为newLen
public int getCapacity() //获取栈容量
public int getSize(int which) //获取指定栈which的元素个数
public E peek(int which) //获取指定站which的栈顶元素
public boolean isEmpty(int which) //判断指定栈which是否为空
public String toString() //返回该栈的字符串形式
public void clear(int which); //清空指定栈which
package 数据结构与算法;



import java.util.Arrays;

public class ArrayStackDoubleEnd<E> implements Stack<E>{
	private E[] data;	//元素容器
	private int left;	//左端栈的栈顶 -1
	private int right;	//右端栈的栈顶 data.length
	public static final int L=0;	//左端栈标记
	public static final int R=1;	//右端栈标记
	private int size;	//栈中元素的总个数
	
	public ArrayStackDoubleEnd() {
		this(10);
	}
	public ArrayStackDoubleEnd(int capacity){
		data=(E[]) new Object[capacity];
		left=-1;
		right=data.length;
		size=0;
	}
	public void push(int which,E e){
		//满 size==data.length left+1=right
		if(size==data.length){
			throw new IllegalArgumentException("栈已满!");
			//resize
		}
		if(which==L){
			data[++left]=e;
		}else{
			data[--right]=e;
		}
		size++;
	}
	public E pop(int which){
		if(isEmpty(which)){
			throw new IllegalArgumentException("栈已空!");
		}
		size--;
		//resize
		if(which==L){
			return data[left--];
		}else{
			return data[right++];
		}
	}
	public int getCapacity(){
		return data.length;
	}
	public int getSize(int which){
		if(which==L){
			return left+1;
		}else{
			return data.length-right;
		}
	}
	public E peek(int which){
		if(isEmpty(which)){
			throw new IllegalArgumentException("栈为空!");
		}
		if(which==L){
			return data[left];
		}else{
			return data[right];
		}
	}
	public boolean isEmpty(int which){
		if(which==L){
			return left==-1;
		}else{
			return right==data.length;
		}
	}
	public void clear(int which){
		if(which==L){
			left=-1;
		}else{
			right=data.length;
		}
	}
	@Override
	public void push(E e) {
		if(size==data.length){
			throw new IllegalArgumentException("栈已满!");
		}
		if(getSize(L)<=getSize(R)){
			push(L,e);
		}else{
			push(R,e);
		}
	}
	@Override
	public E pop() {
		if(getSize(L)>=getSize(R)){
			return pop(L);
		}else{
			return pop(R);
		}
	}
	@Override
	public E peek() {
		if(getSize(L)>=getSize(R)){
			return peek(L);
		}else{
			return peek(R);
		}
	}
	@Override
	public boolean isEmpty() {
		return left==-1&&right==data.length&&size==0;
	}
	@Override
	public int getSize() {
		return size;
	}
	@Override
	public void clear() {
		left=-1;
		right=data.length;
		size=0;
	}
	@Override
	public String toString() {
		return Arrays.toString(data);
	}
}

5.动态数组——队列的顺序存储结构

队列

队列本质上就是一种特殊的线性表

队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表,先进先出的结构

元素插入叫入队,元素删除叫出队

是否允许存储重复元素(看需求)

是否允许存储空值NULL(看需求)

是否允许元素有序(这必须),有序指元素的进场顺序和退场顺序一致

是否允许元素顺序(不需要),顺序指元素在该数据结构内部是否已经被排序

用动态数组实现的线性表也称为顺序队列

java动态开辟数组和静态的区别 动态数组和静态数组_java动态开辟数组和静态的区别_02


Queue 队列接口定义

1.接口定义

public interface Queue<E>

2.功能定义

public int getSize(); //获取队列的元素个数
public boolean isEmpty(); //判断队列是否为空
public void enqueue(E e); //将指定元素e入队
public E dequeue(); //出队一个元素
public E getFront(); //获取队首元素
public E getRear(); //获取队尾元素
public void clear(); //清空队列
ArrayQueue 顺序队列类定义
  1. 定义类
    public class ArrayQueue<E>implements Queue<E>
  2. 定义成员变量
private ArrayList<E> list
  1. 定义构造函数
public ArrayQueue()
public ArrayQueue(int capacity)
  1. 定义成员函数
    实现Queue接口函数
public int getCapacity()
public String toString()

6.动态数组——循环队列的顺序存储结构

顺序队列本质上是由顺序表实现的,但是每次出队一个元素,都需要将后续所有元素前

移,影响效率。

java动态开辟数组和静态的区别 动态数组和静态数组_java动态开辟数组和静态的区别_03


能否在出队时保持其他元素位置不变?可以,但是这样子的话,出队的元素多了,其顺

序表中当前队首元素之前会有很多闲置空间。

java动态开辟数组和静态的区别 动态数组和静态数组_线性表_04


如何利用闲置空间?此处就需要将顺序表收尾相连,形成循环表。

java动态开辟数组和静态的区别 动态数组和静态数组_ci_05


我们把这种队列的这种头尾相接的顺序存储结构称为循环队列

ArrayQueueLoop 循环顺序队列类定义

1.定义类

public class ArrayQueueLoop<E> implements Queue<E>

2.定义成员变量

E[] data; //循环队列的元素容器,此时不能够再用顺序表实现,顺序表没有循环功能。
int size; //循环队列中元素的个数
int front; //队首指针 当rear==front时表示空队列,当(rear+1)%data.length==front时表示满队列
int rear; //队尾指针 当列表不为满时,rear始终指向一个空闲空间,这个空间需要考虑是否被计算在容量里!

3.定义构造函数

public ArrayQueueLoop()
public ArrayQueueLoop(int capacity)

4.定义成员函数
实现Queue接口函数

public int getCapacity()
private void resize(int newLen)
public String toString()