引子
小时候好奇这么高的塔吊是怎么建的,后来知道下面部分是用吊车安装,上面塔吊都是依靠本身来升节的。开始时下面部分一节一节的搭高,完工后从上面一节一节的取掉,因此最底下那一节肯定是最后才取出来的,这种结构类似Stack。
Stack简介
Stack也称为栈,是一种后进先出的数据结构(last-in-first-out,LIFO),继承了Vector,并且扩充了五种方法,分别是push、pop、peek、empty、search
源码分析
public Stack() {
}
public E push(E item) {
addElement(item);
return item;
}
---------------Vector addElement()---------
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
在此栈顶部添加对象,调用Vector中addElement方法,采用synchronized锁,ensureCapacityHelper
实现了ensureCapacity
方法的非同步方式,不会产生额外同步的成本。
public synchronized E peek() {
int len = size();
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
peek返回此栈顶部的对象,采用synchronized实现方法同步,如果栈中没有对象,则抛出EmptyStackException
pop删除此栈顶部的对象,然后调用peek方法返回此对象,采用synchronized锁,实现方法同步
public boolean empty() {
return size() == 0;
}
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) {
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;
}
search返回在栈中的位置,对象在底部大小为size,顶部则为1,搜索的对象不存在则返回-1
举个栗子:
public class HelloStack {
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
stack.push("Duffy");
stack.push("Wang");
stack.push("South");
stack.push("East");
System.out.println("pop: " + stack.pop());
System.out.println("peek: " + stack.peek());
System.out.println("Stack size: " + stack.size());
System.out.println("Position by search: " + stack.search("Duffy"));
System.out.println("Stack is empty: " + stack.empty());
}
}
-----------------result:-------------------
pop: East
peek: South
Stack size: 3
Position by search: 3
Stack is empty: false
对比Queue
Queue只是一个接口,是一种先进先出的数据结构(first-in-first-out,FIFO),LinkedList、PriorityQueue以及阻塞队列LinkedBlockingQueue、ArrayBlockingQueue、PriorityBlockingQueue都实现了此接口
扩展
实现一个可返回栈中最小值的Stack,包括push,pop,top,getMin方法。
public class minStack {
private List<Integer> list;
private int min;
public minStack() {
list = new Vector<Integer>();
min = Integer.MAX_VALUE;
}
//当遇到比现在min小的值需要在list添加两次,否则添加添加一次
public void push(int n) {
if (n <= min) {
list.add(min);
min = n;
}
list.add(n);
}
//当当前pop的值是最小值,需要remove两次
public void pop() {
if (!list.isEmpty()) {
if (list.remove(list.size() - 1) == min) {
min = list.remove(list.size() - 2);
}
}
}
public int top() {
return list.get(list.size() - 1);
}
public int min() {
return min;
}
}
用两个栈实现一个队列,即实现先进先出功能
public class stack2Queue {
private Stack<Integer> stack1 = new Stack();
private Stack<Integer> stack2 = new Stack();
//stack1单纯添加元素
public void appendTail(int i) {
stack1.push(i);
}
//stack2通过将stack1顶部的元素放入底部,从而实现后进后出,也就是先进先出
public int deleteHead() throws Exception {
if (!stack2.isEmpty()) {
return stack2.pop();
}
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
return stack2.pop();
}
二叉树中序遍历非递归实现
//中序遍历顺序为 根-左-右
public void printInOrder(BinaryTreeNode head) {
Stack<BinaryTreeNode> stack = new Stack<>();
while (!stack.isEmpty() || head != null) {
while (head != null) {
stack.push(head);
head = head.left;
}
if (!stack.isEmpty()) {
//第一个head 为head.left为空,先pop再打印
head = stack.pop();
System.out.println(head.data);
head = head.right;
}
}
}
实现十进制转二进制
public class Dec2Binary {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
if (i > 0){
Stack<Integer> stack = new Stack<>();
while (i > 0) {
stack.push(i % 2);
i = i / 2;
}
while (!stack.isEmpty()) {
System.out.print(stack.pop());
}
}else {
System.out.println("Input again");
}
}
}