数据结构-栈和队列
- 栈—Stack
栈是一种用于存储数据的简单数据结构(与链表类似),栈只有一个开口,先进去的就到最底下,后进来的就在前面,要是拿出去的话,肯定是从开口端拿出去,所以说先进后出,后进先出,只允许在一端进行插入和删除操作。
试图对一个空栈执行栈操作称为下溢(underflow);
试图对一个满栈执行栈操作称为溢出(overflow)。
通常,溢出和下溢均认为是异常;
首先我们来看看Stack源码:
public class Stack<E> extends Vector<E> {
// 首先可以看出继承Vector,所以我们在使用API的过程有好多方法是Vector的方法,
// 而我们今天主要研究的是栈,所以忽略Vector提供的方法。
public Stack() {
}
public E push(E item) { //栈的添加方法--进栈
addElement(item);//线程安全的
return item;
}
public synchronized E pop() { //出栈
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
public synchronized E peek() { -- 取栈顶值(不出栈)
int len = size();
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}
public synchronized int search(Object o) {//方法调用返回从堆栈中,对象位于顶部的基于1的位置
int i = lastIndexOf(o);
if (i >= 0) {
return size() - i;
}
return -1;
}
通过实例来验证先入后出,后入先出的原则:
我最后插入的一个元素为“D”,现在进行了一次出栈操作,可以看出第一个输出的元素为“D",完全验证了栈的特点。
- 队列—Queue
队列是一种用于存储数据的数据结构(与链表和栈类似),数据到达的次序是队列的关键;在日常生活中队列是指从序列的开始按照顺序等待服务的一队人或物。
队列是一种只能在一端插入(队尾),在另一端删除(队首)的有序线性表。队列中第一个插入的元素也是第一个被删除的元素,所以队列是一种先进先出(FIFO,First In First Out)或后进后出(LiLO,Last In Last Out)线性表。
在队列中插入一个元素,称为入队(EnQueue),从队列中删除一个元素,称为出队(DeQueue);试图对一个空队列执行出队操作称为下溢(underflow),试图对一个满队列执行入队操作称为溢出(overflow);通常认为溢出和下溢是异常。
Queue常用方法:
- boolean add(E e);将指定的元素插入此队列(如果立即可行且不会违反容量限制),在成功时返回 true,如果当前没有可用的空间,则抛出 IllegalStateException。
- boolean offer(E e);将指定的元素插入此队列(如果立即可行且不会违反容量限制),当使用有容量限制的队列时,此方法通常要优于 add(E),后者可能无法插入元素,而只是抛出一个异常。
- E remove();获取并移除此队列的头。
- E poll();获取并移除此队列的头,如果此队列为空,则返回 null。
- E element();获取,但是不移除此队列的头。
- E peek();获取但不移除此队列的头;如果此队列为空,则返回 null。
代码示例:
Queue<String> queue=new LinkedList<>();
queue.offer("one");
queue.offer("two");
queue.offer("three");
queue.offer("four");
System.out.println(queue);
queue.add("1");
System.out.println(queue);
//返回队首的元素,但不进行删除
queue.element();
System.out.println(queue);
//将元素从队列的队首删除。
queue.remove();
//从队首取出元素并删除
String poll = queue.poll();
System.out.println(poll);
//从队首取出元素但是不删除
String peek = queue.peek();
System.out.println(peek);
System.out.println(queue);
//遍历队列,这里要注意,每次取完元素后都会删除,整个
//队列会变短,所以只需要判断队列的大小即可
while(queue.size() > 0) {
System.out.println(queue.poll());
}
输出结果:
[one, two, three, four]
[one, two, three, four, 1]
[one, two, three, four, 1]
two
three
[three, four, 1]
three
four
1
- Deque接口(双向队列)
Deque接口,是Queue接口的子接口,是指队列两端的元素,既能入队(offer)也能出队。
如果将Deque限制为只能从一端进行入队,和出队,就是栈的数据结构的实现。对于栈而言,有入栈(push)和出栈(pop),遵循先进后出的规则。
Deque与支持从数据结构的任一端添加或删除元素的双端队列相关,它可以用作队列(先进先出/ FIFO)或堆栈(LIFO)。这些比Stack和LinkedList更快。
几个重要特性是:
- 它提供可调整大小的阵列的支持,并有助于无限制容量,因此根据用途增长阵列。
- Array deques禁止使用Null元素,不接受任何此类元素。
- 不支持多线程的任何并发访问。
- 在没有外部同步的情况下,Deque不是线程安全的。
API文档:
- add(element):向尾部添加元素。
- addFirst(element):向头部添加元素。
- addLast(element):向尾部添加元素。
- offer(element):向尾部添加一个元素并返回一个布尔值来解释插入是否成功。
- offerFirst(element):向头部添加一个元素并返回一个布尔值来解释插入是否成功。
- offerLast(element):向尾部添加一个元素并返回一个布尔值来解释插入是否成功。
- iterator():返回此双端队列的迭代器。
- descendingIterator():返回一个迭代器,该迭代器具有此双端队列的相反顺序。
- push(element):向头部添加元素。
- pop(element):从头部移除一个元素并返回它。
- removeFirst():删除头部的元素。
- removeLast():删除尾部的元素。
- poll():检索并删除此双端队列表示的队列的头部(换句话说,此双端队列的第一个元素),如果此双端队列为空,则返回null。
- pollFirst():检索并删除此双端队列的第一个元素,如果此双端队列为空,则返回null。
- pollLast():检索并删除此双端队列的最后一个元素,如果此双端队列为空,则返回null。
- peek():检索但不删除此双端队列表示的队列的头部(换句话说,此双端队列的第一个元素),如果此双端队列为空,则返回null。
- peekFirst():检索但不删除此双端队列的第一个元素,如果此双端队列为空,则返回null。
- peekLast():检索但不删除此双端队列的最后一个元素,如果此双端队列为空,则返回null。
代码示例:
Deque<String> deque = new LinkedList<String>();
deque.add("Element 1 (Tail)"); // add to tail
deque.addFirst("Element 2 (Head)");
deque.addLast("Element 3 (Tail)");
deque.push("Element 4 (Head)"); //add to head
deque.offer("Element 5 (Tail)");
deque.offerFirst("Element 6 (Head)");
deque.offerLast("Element 7 (Tail)");
System.out.println(deque + "\n");
System.out.println("Standard Iterator");
Iterator iterator = deque.iterator();
while (iterator.hasNext())
System.out.println("\t" + iterator.next());
Iterator reverse = deque.descendingIterator();
System.out.println("Reverse Iterator");
while (reverse.hasNext())
System.out.println("\t" + reverse.next());
System.out.println("Peek " + deque.peek());
System.out.println("After peek: " + deque);
System.out.println("Pop " + deque.pop());
System.out.println("After pop: " + deque);
System.out.println("Contains element 3: " +
deque.contains("Element 3 (Tail)"));
deque.removeFirst();
deque.removeLast();
System.out.println("Deque after removing " +
"first and last: " + deque);
}
输出结果:
[Element 6 (Head), Element 4 (Head), Element 2 (Head), Element 1 (Tail), Element 3 (Tail), Element 5 (Tail), Element 7 (Tail)]
Standard Iterator
Element 6 (Head)
Element 4 (Head)
Element 2 (Head)
Element 1 (Tail)
Element 3 (Tail)
Element 5 (Tail)
Element 7 (Tail)
Reverse Iterator
Element 7 (Tail)
Element 5 (Tail)
Element 3 (Tail)
Element 1 (Tail)
Element 2 (Head)
Element 4 (Head)
Element 6 (Head)
Peek Element 6 (Head)
After peek: [Element 6 (Head), Element 4 (Head), Element 2 (Head), Element 1 (Tail), Element 3 (Tail), Element 5 (Tail), Element 7 (Tail)]
Pop Element 6 (Head)
After pop: [Element 4 (Head), Element 2 (Head), Element 1 (Tail), Element 3 (Tail), Element 5 (Tail), Element 7 (Tail)]
Contains element 3: true
Deque after removing first and last: [Element 2 (Head), Element 1 (Tail), Element 3 (Tail), Element 5 (Tail)]