写在前面
栈是算法学习的第一个知识,在这里开启了算法学习的道路。通过栈的学习,巩固了泛型,接口等概念。下面就开始实现吧!!
(一)栈的API以及用例
要想深入了解一个内容,首先从使用它开始。
栈的API中包括了入栈,出栈,判断为空和输出栈的大小操作。
由于我们需要栈内可以接受任意的数据类型,java中的泛型正是、解决这一问题的方法。
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import java.util.Stack;
public class StackUsage {
public static void main(String[] args) {
Stack<Integer> s = new Stack<Integer>();
while (!StdIn.isEmpty()) {
s.push(StdIn.readInt());
}
//这里使用foreach语句并不能翻转
//使用foreach输出时候是按照数组从索引0开始的方式遍历的!!
//即:从栈底到栈顶;刚好和弹栈的方式相反!!! 所以反转实现用pop语句
for(int i:s){
StdOut.print(i+",");
}
/**
int N = s.size();
int[] a = new int[N];
for (int i = 0; i < N; i++) {
a[i] = s.pop();
}
for (int i = 0; i < N; i++) {
StdOut.print(a[i] + ",");
}
**/
}
}
上述代码中,实现了输入一串整数序列,将其反转的操作
注意:这里使用foreach语句来进行反转是有问题的,所以可以使用pop操作来进行反转
(二)定容栈
在这里我使用数组来进行数据的存储。而数组的大小是设定之初就设置好的。
2、1固定类型的定容栈
这里实现了一个String类型的定容栈
//用数组来实现栈 动态调整数组大小
public class FixedCapacityStackOfStrings{
//设计一个定容栈
private String []a;
private int N;
//构造方法 初始化一个数组
public FixedCapacityStackOfStrings(int cap){
a=new String[cap];
}
public boolean isEmpty(){
return N==0;
}
public int size(){
return N;
}
public void push(String item){
a[N++]=item;
}
public String pop(){
return a[--N];
}
}
2、1使用泛型实现任意参数类型的定容栈
使用泛型实现
//用数组来实现栈 动态调整数组大小
public class FixedCapacityStackOfItem<Item> {
private Item a[];
private int N;
public FixedCapacityStackOfItem(int cap){
//创建泛型数组是不允许的,采用类型转换
a=(Item[])new Object[cap];
}
public boolean isEmpty(){
return N==0;
}
public int size(){
return N;
}
public void push(Item item){
a[N++]=item;
}
public Item pop(){
return a[--N];
}
}
注意:创建泛型数组是不允许的,采用类型转换
(三)动态栈
3、1如何调整数组大小?
在定容栈中,我们需要在入栈和出栈操作之前,先检查栈中是否满或空。而这挺烦的。如何去除这些操作呢?
在这里定义一个resize的方法,将大小N《=Max的栈移动到一个新的大小为Max的数组中。
private void resize(int max) {
Item[]temp=(Item[]) new Object[max];
for(int i=0;i<N;i++){
temp[i]=a[i];
}
a=temp;
}
在push操作中,我们会先检查栈的大小N和数组大小a.length是否相等来检查数组是否能够容纳新元素
注意栈的大小是《=数组长度的
public void push(Item item){
if(N==a.leghth)
resize(a.length*2);
}
同理对于pop操作
public Item pop(){
if(N>0&&N==a.length/4)
resize(a.length/4);
return a[--N];
}
3、2迭代的实现
集合类数据类型的基本操作之一就是能够使用foreach语句通过迭代遍历并处理集合中的每个元素。
3、2、1可迭代的集合数据类型中,我们需要实现什么?
1、首先使一个类可迭代,需要在其申明中加入Implements Iterable 《Item》
public interface Iterable<Item>{
Iterator<Item> iterator();
}
2、集合数据类型必须实现一个iterator方法并返回一个iterator对象
public Iterator<Item> iterator(){
return new ReverseArrayIterator();
}
3、iterator中需要包含两个方法hasNext和next
public interface Iterator<Item>{
boolean hasNext();
Item next();
void remove();
}
3、2、2实现可迭代的动态栈
import java.util.Iterator;
//用数组来实现栈 动态调整数组大小
import java.util.Iterator;
//用数组来实现栈 动态调整数组大小
public class StackRealize<Item> implements Iterable<Item> {
private Item a[]=(Item[])new Object[1];
private int N=0;
public boolean isEmpty(){
return N==0;
}
public int size(){
return N;
}
private void resize(int max) {
Item[]temp=(Item[]) new Object[max];
for(int i=0;i<N;i++){
temp[i]=a[i];
}
a=temp;
}
public void push(Item item){
if(N==a.length)
resize(a.length*2);
a[N++]=item;
}
public Item pop(){
Item item=a[--N];
//避免游离
a[N]=null;
if(N>0&&N==a.length/4)
resize(a.length/4);
return item;
}
public Iterator<Item> iterator(){
return new ReverseArrayIterator();
}
public class ReverseArrayIterator implements Iterator<Item>{
private int i=N;
public boolean hasNext(){
return i>0;
}
public Item next(){
return a[--i];
}
public void remove(){
}
}
}
(四)链栈的实现
通过使用链表,这里实现向栈顶添加元素(这里的栈顶是头指针的指向)。
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import java.util.Iterator;
//实现链栈
public class LineStack<Item> implements Iterable<Item> {
private class Node {
Item item;
Node next;
}
private Node head;
private int N;
public boolean isEmpty() {
return head==null;
}
public void push(Item item) {
Node x = head;
head = new Node();
head.item = item;
head.next = x;
N++;
}
public Item pop() {
Item item = head.item;
head = head.next;
N--;
return item;
}
public int size() {
return N;
}
public Iterator iterator(){
return new ListIterator();
}
public class ListIterator implements Iterator<Item> {
private Node current = head;
public boolean hasNext() {
return current != null;
}
public void remove() {
}
public Item next() {
Item item = current.item;
current = current.next;
return item;
}
}
public static void main(String[] args){
LineStack<Integer> s=new LineStack<Integer>();
while(!StdIn.isEmpty()){
Integer item=StdIn.readInt();
if(!item.equals(5))
s.push(item);
else if(!s.isEmpty())
StdOut.print(s.pop());
}StdOut.print(s.size());
}
}