java栈--后进先出(顺序栈、链栈、单词逆序)

栈: 是限定仅在表尾插入和删除操作的线性表,允许插入和删除的一段称为栈顶,另一端为栈底。 栈的特点就是: 后进先出。

栈的实现非常简单,在生活中的也时常应用到,如:表达式求值、函数的调用用栈保存数据、语法的检验、函数的递归实现等都是基于栈的实现。在这里利用一张图就可以清晰的展示栈的操作。对栈的操作时间复杂度都是常数,都是对栈顶元素的操作。

栈的示意图

下面是笔者实现的一个顺序栈利用数组来存放元素

package org.TT.Stack;

/** 栈:后进先出
 *      栈是一个概念上的辅助工具。这里采用数组完成栈的操作,这里利用泛型,可以参入任何参数对象。
 *      栈的数据项的出栈、入栈时间复杂度为常数 O(1)。
 *
 */
public class Stack<T> {

	private int maxSize;   
	private Object[] stackArray;
	private int top;
	
	// 创建一个指定大小的新栈,并将top指向栈底。
	public Stack(int length){
		maxSize = length;
		stackArray = new Object[maxSize];
		top = -1;
	}
	
	// 入栈,将top值加1,是它指向原栈顶的上面一个位置,并将新的值存入这个位置。(插入前top先加1)
	public void push(T value){
		if(isFull()){
			throw new RuntimeException("栈满!不能插入!");  // 入栈前先判断是否已满
		}
		stackArray[++top] = value;
	}
	
	// 出栈, 返回top 标识的数据,然后减一。pop有效的从栈中移除了数据项,
	// 虽然数据项仍然存在数组中(新的数据项会覆盖旧的数据项),但不再能访问。
	@SuppressWarnings("unchecked")
	public T pop(){
		if(isEmpty()){
				throw new RuntimeException("栈空!没有元素可取!");   // 出栈前判断栈是否为空
		}
		return (T)stackArray[top--];
	}
	
	// 取得栈定数据项
	@SuppressWarnings("unchecked")
	public T peek(){
		return (T) stackArray[top];
	}
	
	// 判断栈是否为空,top 等于-1 时为空栈
	public boolean isEmpty(){
		return (top == -1);
	}
	
	// 判断栈是否栈满,top 等于maxSize -1 时栈满
	public boolean isFull(){
		return (top == maxSize -1);
	}
	
    @SuppressWarnings("unchecked")
	public T get(int index) {   
        return (T) stackArray[index];   
    } 
	
    public void display(String str) {   
        System.out.print(str);   
        System.out.print(" Stack (bottom-->top): ");   
        for (int i = 0; i < maxSize; i++) {   
            System.out.print(get(i)+" ");   
        }   
        System.out.println();   
    }
	
    // 测试 栈
	public static void main(String[] args) {
		Stack<String> stack = new Stack<>(5);
		stack.push("a");
		stack.push("b");
		stack.push("c");
		stack.push("d");
		stack.push("e");
		
		while(!stack.isEmpty()){           // 依次出栈
			String value = stack.pop();
			System.out.print(value + " ");
		}
	}
}
接下来笔者又用链接存储结构实现了一个-- 链栈。通常采用 单链表实现链栈,用单链表的头部做栈顶是最方便的,因为只能栈链栈的栈顶插入删除。

在这里,笔者采用前面说实现的 SingleLinkedList ,笔者可以参见前面的讲解,以下只是对链表进行了一次封装,进而实现了链栈。相信读者也能轻松理解栈的思想。

package org.TT.Stack;

import org.TT.LinkedList.Node;
import org.TT.LinkedList.SingleLinkedList;

public class LinkStack<T> {

	private SingleLinkedList<T> linkList;
	
	public LinkStack(){
		linkList = new SingleLinkedList<>();
	}
	
	public boolean isEmpty(){
		return linkList.isEmpty();
	}
	
	public void push(T item){
		linkList.insertFirst(item);
	}
	
	public Node<T> pop(){
		return linkList.removeFirst();
	}
	
	public Node<T> peek(){
		return linkList.getFirst();
	}
	
	public int stackSize(){
		return linkList.getSize();
	}
	
	public void displayStack(){
		linkList.printList();
	}
	
	public static void main(String[] args) {
		LinkStack<String> linkStack = new LinkStack<>();
		linkStack.push("A");
		linkStack.push("B");
		linkStack.push("C");
		
		System.out.println("查看栈顶:" + linkStack.peek().getNodeValue());
		
		System.out.println("栈的大小: " + linkStack.stackSize());
		
		System.out.println("栈顶(C)出栈: " + linkStack.pop().getNodeValue());
		
		System.out.print("C出栈后的栈:");
		linkStack.displayStack();
		
		// 进栈顺序 为 A、B、C 然后 把栈顶元素出栈(此时为:C), 所以再依次出栈为: B、 A
	}
	
}
下面给读者带来一个应用: 单词逆序。 将输入的单词,逆序输出,入输入abcd, 得到的结果就是dcba。 这个就是应用栈的思想, 先将输入的单词分成字母,并将得到的字母分别压入栈中,在将字母分别出栈,并拼接成原来单词的逆序。
package org.TT.Stack;

import java.util.Scanner;

/** 你用栈实现  单词逆序
 */
public class WordReversed {

	private String input;
	private String output;
	
	public WordReversed(String in) {
		input = in;
	}
	
	public String reversed(){
		output = "";
		int stackSize = input.length();
		Stack<String> stack = new Stack<>(stackSize);
		
		String str[] = input.split("");
		
		for(int i = 0; i <input.length(); i++){
			String ch = str[i];
			stack.push(ch);               // 将单词依次压栈,先进的单词就到了栈底,后进的在栈顶。
		}
		
		while(!stack.isEmpty()){
			String ch = stack.pop();  // 将单词依次弹出栈,并保持每次弹出的数据项。
			output = output + ch;   // 先弹出栈顶(后进单词),所有顺序颠倒
		}
		
		return output;
	}
	
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		
		String input, output;
		
		while(true){
			System.out.println("请输入字符串:");
			Scanner in = new Scanner(System.in);
			input = in.nextLine();
			
			WordReversed reversed = new WordReversed(input);
			output = reversed.reversed();
			System.out.println("逆序为: " + output);
			
		}
		
	}
	
}
如图:      

下面我们来简单说明一下,顺序栈和链栈的区别:顺序栈和链栈的操作的时间复杂度都是常数,但是顺序栈初始化时必须确认一个固定的长度,对于存储元素是有限制,并且还有可能浪费存储空间;链栈则没有栈满的情况,除非内存不足,当不确定元素个数是优先选择链栈。


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值