栈是限定仅在表尾进行插入和删除操作的线性表
允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出的线性表
栈的顺序存储结构:如用数组实现,栈底是:下标为0的一端
栈的链式存储结构:
Stack继承Vector,是栈结构,他们本质还是数组
public class Vector
extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable
{
protected Object[] elementData;//数组放数据
protected int elementCount; //元素个数
protected int capacityIncrement;//默认增量
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
public Vector() {
this(10);
}
public
class Stack extends Vector {
/**
* Creates an empty Stack.
*/
public Stack() {
}}
看看Stack的push方法:就是确定数组大小够用,不够扩容,在数组尾端加元素
public E push(E item) {
addElement(item);
return item;
}
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj; //elementCount++
}
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
peek:返回栈顶的元素(线性表尾端),而且不移除此元素。
栈里移除元素只需要把此元素设为null,ArrayList移除最后一个元素也是把数组尾端置null,但ArrayList移除其他索引的元素就得产生新数组复制元素,原因在于栈只能操作栈顶元素
public synchronized E peek() {
int len = size(); //元素的个数
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}
public synchronized E elementAt(int index) {
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
}
return elementData(index);
}
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
pop():弹出栈顶的元素
public synchronized E pop() {
E obj;
int len = size();
obj = peek(); //用peek找到栈顶元素
removeElementAt(len - 1);
return obj;
}
public synchronized void removeElementAt(int index) { //移除栈某个位置的元素
modCount++;
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
else if (index < 0) {
throw new ArrayIndexOutOfBoundsException(index);
}
int j = elementCount - index - 1; //j>0说明想移除的不是栈顶 而是数组中间的元素,就采用数组复制的方法
if (j > 0) {
System.arraycopy(elementData, index + 1, elementData, index, j);
}
elementCount--;
elementData[elementCount] = null; /* to let gc do its work */ //移除元素,就是原栈顶处为null,并且elementCount--,这样下次往栈push元素 依然会在数组此位置放元素
}
search:查询某个元素,从栈顶(数组尾端)往下遍历,返回索引
public synchronized int search(Object o) {
int i = lastIndexOf(o);
if (i >= 0) {
return size() - i;
}
return -1;
}
public synchronized int lastIndexOf(Object o) {
return lastIndexOf(o, elementCount-1);
}
public synchronized int lastIndexOf(Object o, int index) {
if (index >= elementCount)
throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
if (o == null) { //数组的元素可以为null
for (int i = index; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = index; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
栈的实例:逆波兰表达式法
中缀表达式转为后缀表达式:数字输出,运算符进栈,括号匹配出栈,栈顶优先级低出栈
队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
插入的一端称为duan队尾,删除的一端称为队头
队列的顺序存储方式:front是队头,rear是队尾
顺序方式就会想到用数组,看图入队方便,但出队会让数组前几个元素置空,就会出现前面出现一节数组里是空的情况,即假溢出,浪费了存储空间。 这里就不能像栈一样置null就行,因为栈只在栈顶操作。
循环队列:头尾相接的顺序存储,可以解决假溢出的问题
队列的链式存储及结构模式:这是我们采用的队列实现方式
public interface Queue extends Collection {
boolean add(E e);
boolean offer(E e);//这个是真正的入队操作
E remove();
E poll();//这个是出队操作
E element();//获取元素
E peek();
}
LinkedList 其实就实现了队列接口,Deque实现了Queue
public class LinkedList
extends AbstractSequentialList
implements List, Deque, Cloneable, java.io.Serializable
{
public boolean offer(E e) { //offer方法往队尾添加元素,跟链式线性表操作一样
return add(e);
}
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node l = last;
final Node newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
}
看出队操作:poll
public E poll() {
final Node f = first;
return (f == null) ? null : unlinkFirst(f);
}
private E unlinkFirst(Node f) {//把原first节点所有置空,下个next节点置位first节点
// assert f == first && f != null;
final E element = f.item;
final Node next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
看到了Deque接口定义了offerLast,offerFirst,pollLast等方法,LinkedList也实现了,就是从另外一端操作队列的方法,百度一下:
数据结构是描述数据间一种或多种特定关系的集合。
顺序表、链式表、栈、队列是数据结构,而ArrayList、LinkedList只是符合了这些数据结构的特点,就叫做他们的实现