数据结构与算法_01【动态数组】

1.静态数组与动态数组
静态数组的特点:
数组的长度一旦确定则不可更改
数组只能存储同一类型的数据
数组中每个存储空间地址是连续且相等的
数组提供角标的方式访问元素
缺点:
长度不可变,数据量大了怎么办?扩容可以解决(创建新数组)
地址连续且提供角标,访问很快,但移动元素只能挨个挨个移
最重要的,数组只有length这个属性,没有其他的方法!
动态数组,主要是解决其缺点3:
将数组本身和在其上的相关操作进行封装,生成一个类
今后只需创建该类的对象,就可以进行对其所包装的数组进行增删改查操作
为什么要说动态数组的,其实动态数组就是顺序存储结构的具体实现!
2.动态数组——线性表的顺序存储结构
线性表
零个或多个数据元素的有限序列
可通过索引访问元素
除了第一个元素没有前驱,最后一个元素没有后继,其他元素都有唯一的前驱和后继
是否允许存储重复元素(看需求)
是否允许存储空值NULL(看需求)
是否允许元素有序(这必须),有序指元素的进场顺序和退场顺序一致
是否允许元素顺序(看需求),顺序指元素在该数据结构内部是否已经被排序
用动态数组实现的线性表也称为顺序表
在这里插入图片描述
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(看需求)
是否允许元素有序(这必须),有序指元素的进场顺序和退场顺序一致
是否允许元素顺序(不需要),顺序指元素在该数据结构内部是否已经被排序
用动态数组实现的线性表也称为顺序队列
在这里插入图片描述
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.动态数组——循环队列的顺序存储结构
顺序队列本质上是由顺序表实现的,但是每次出队一个元素,都需要将后续所有元素前
移,影响效率。
在这里插入图片描述
能否在出队时保持其他元素位置不变?可以,但是这样子的话,出队的元素多了,其顺
序表中当前队首元素之前会有很多闲置空间。
在这里插入图片描述
如何利用闲置空间?此处就需要将顺序表收尾相连,形成循环表。
在这里插入图片描述
我们把这种队列的这种头尾相接的顺序存储结构称为循环队列
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()

猜你喜欢

转载自blog.csdn.net/weixin_44561640/article/details/89242844