栈的java实现和栈的应用
[例子和习题出自数据结构(严蔚敏版), 本人使用java进行实现. 转载请注明作者和出处, 如有谬误, 欢迎在评论中指正. ]
栈的实现
栈是一种先进后出的数据结构, 首先定义了栈需要实现的接口:
- public interface MyStack<T> {
- /**
- * 判断栈是否为空
- */
- boolean isEmpty();
- /**
- * 清空栈
- */
- void clear();
- /**
- * 栈的长度
- */
- int length();
- /**
- * 数据入栈
- */
- boolean push(T data);
- /**
- * 数据出栈
- */
- T pop();
- }
栈的数组实现, 底层使用数组:
- public class MyArrayStack<T> implements MyStack<T> {
- ];
- ;
- @Override
- public boolean isEmpty() {
- ;
- }
- @Override
- public void clear() {
- // 将数组中的数据置为null, 方便GC进行回收
- ; i < size; i++) {
- objs[size] = null;
- }
- ;
- }
- @Override
- public int length() {
- return size;
- }
- @Override
- public boolean push(T data) {
- // 判断是否需要进行数组扩容
- if (size >= objs.length) {
- resize();
- }
- objs[size++] = data;
- return true;
- }
- /**
- * 数组扩容
- */
- private void resize() {
- / 2 + 1];
- ; i < size; i++) {
- temp[i] = objs[i];
- objs[i] = null;
- }
- objs = temp;
- }
- @SuppressWarnings("unchecked")
- @Override
- public T pop() {
- ) {
- return null;
- }
- return (T) objs[--size];
- }
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("MyArrayStack: [");
- ; i < size; i++) {
- sb.append(objs[i].toString());
- ) {
- sb.append(", ");
- }
- }
- sb.append("]");
- return sb.toString();
- }
- }
栈的链表实现, 底层使用链表:
- public class MyLinkedStack<T> implements MyStack<T> {
- /**
- * 栈顶指针
- */
- private Node top;
- /**
- * 栈的长度
- */
- private int size;
- public MyLinkedStack() {
- top = null;
- ;
- }
- @Override
- public boolean isEmpty() {
- ;
- }
- @Override
- public void clear() {
- top = null;
- ;
- }
- @Override
- public int length() {
- return size;
- }
- @Override
- public boolean push(T data) {
- Node node = new Node();
- node.data = data;
- node.pre = top;
- // 改变栈顶指针
- top = node;
- size++;
- return true;
- }
- @Override
- public T pop() {
- if (top != null) {
- Node node = top;
- // 改变栈顶指针
- top = top.pre;
- size--;
- return node.data;
- }
- return null;
- }
- /**
- * 将数据封装成结点
- */
- private final class Node {
- private Node pre;
- private T data;
- }
- }
两种实现的比较, 主要比较数据入栈和出栈的速度:
- @Test
- public void testSpeed() {
- MyStack<Person> stack = new MyArrayStack<Person>();
- ;
- long start = System.currentTimeMillis();
- ; i < num; i++) {
- ));
- }
- long temp = System.currentTimeMillis();
- System.out.println("push time: " + (temp - start));
- while (stack.pop() != null)
- ;
- System.out.println("pop time: " + (System.currentTimeMillis() - temp));
- }
MyArrayStack中入栈和出栈10,000,000条数据的时间:
将MyArrayStack改为MyLinkedStack后入栈和出栈的时间:
push time: 936
pop time: 126
可见两者的入栈速度差不多, 出栈速度MyArrayStack则有明显的优势.
为什么测试结果是这样的? 可能有些朋友的想法是数组实现的栈应该具有更快的遍历速度, 但增删速度应该比不上链表实现的栈才对. 但是栈中数据的增删具有特殊性: 只在栈顶入栈和出栈. 也就是说数组实现的栈在增加和删除元素时并不需要移动大量的元素, 只是在数组扩容时需要进行复制. 而链表实现的栈入栈和出栈时都需要将数据包装成Node或者从Node中取出数据, 还需要维护栈顶指针和前驱指针.
栈的应用举例
1. 将10进制正整数num转换为n进制
- private String conversion(int num, int n) {
- MyStack<Integer> myStack = new MyArrayStack<Integer>();
- Integer result = num;
- while (true) {
- // 将余数入栈
- myStack.push(result % n);
- result = result / n;
- ) {
- break;
- }
- }
- StringBuilder sb = new StringBuilder();
- // 按出栈的顺序倒序排列即可
- while ((result = myStack.pop()) != null) {
- sb.append(result);
- }
- return sb.toString();
- }
2. 检验符号是否匹配. '['和']', '('和')'成对出现时字符串合法. 例如"[][]()", "[[([]([])()[])]]"是合法的; "([(])", "[())"是不合法的.
遍历字符串的每一个char, 将char与栈顶元素比较. 如果char和栈顶元素配对, 则char不入栈, 否则将char入栈. 当遍历完成时栈为空说明字符串是合法的.
- public boolean isMatch(String str) {
- MyStack<Character> myStack = new MyArrayStack<Character>();
- char[] arr = str.toCharArray();
- for (char c : arr) {
- Character temp = myStack.pop();
- // 栈为空时只将c入栈
- if (temp == null) {
- myStack.push(c);
- }
- // 配对时c不入栈
- else if (temp == '[' && c == ']') {
- }
- // 配对时c不入栈
- else if (temp == '(' && c == ')') {
- }
- // 不配对时c入栈
- else {
- myStack.push(temp);
- myStack.push(c);
- }
- }
- return myStack.isEmpty();
- }
3. 行编辑: 输入行中字符'#'表示退格, '@'表示之前的输入全都无效.
使用栈保存输入的字符, 如果遇到'#'就将栈顶出栈, 如果遇到@就清空栈. 输入完成时将栈中所有字符出栈后反转就是输入的结果:
- private String lineEdit(String input) {
- MyStack<Character> myStack = new MyArrayStack<Character>();
- char[] arr = input.toCharArray();
- for (char c : arr) {
- if (c == '#') {
- myStack.pop();
- } else if (c == '@') {
- myStack.clear();
- } else {
- myStack.push(c);
- }
- }
- StringBuilder sb = new StringBuilder();
- Character temp = null;
- while ((temp = myStack.pop()) != null) {
- sb.append(temp);
- }
- // 反转字符串
- sb.reverse();
- return sb.toString();
- }
栈的java实现和栈的应用的更多相关文章
- 剑指Offer——栈的java实现和栈的应用举例
剑指Offer--栈的java实现和栈的应用举例 栈是一种先进后出的数据结构, 栈的实现如下: 首先定义了栈需要实现的接口: public interface MyStack<T> { / ...
- java堆和栈的区别
java 的内存分为两类,一类是栈内存,一类是堆内存.栈内存是指程序进入一个方法时,会为这个方法单独分配一块私属存储空间,用于存储这个方法内部的局部变量,当这个方法结束时,分配给这个方法的栈会释放,这 ...
- Java堆、栈和常量池以及相关String的详细讲解(经典中的经典) (转)
原文链接 : http://www.cnblogs.com/xiohao/p/4296088.html 一:在JAVA中,有六个不同的地方可以存储数据: 1. 寄存器(register). 这是最快的 ...
- Java堆、栈和常量池
摘录自 http://www.cnblogs.com/xiohao/p/4296088.html 1. 栈(stack)与堆(heap)都是Java用来在RAM中存放数据的地方.与C++不同,Java ...
- Java堆、栈和常量池以及相关String的详细讲解
一:在JAVA中,有六个不同的地方可以存储数据: 1. 寄存器(register). 这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部.但是寄存器的数量极其有限,所以寄存器由编译器根据 ...
- Java堆和栈详解
Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...
- java堆、栈、堆栈的区别
1.栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. 2. 栈的优势是,存取速度比堆要快,仅次于直接位于CP ...
- JAVA数据结构系列 栈
java数据结构系列之栈 手写栈 1.利用链表做出栈,因为栈的特殊,插入删除操作都是在栈顶进行,链表不用担心栈的长度,所以链表再合适不过了,非常好用,不过它在插入和删除元素的时候,速度比数组栈慢,因为 ...
- java与数据结构(6)---java实现链栈
栈之链式存储结构链栈 链栈 栈的链式存储结构成为链栈.链栈是没有头结点,头结点就是栈顶指针top. 代码结构 package list; public interface Stackable;公共接口 ...
随机推荐
- hdu 2546 饭卡 (01背包)
Problem Description 电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额.如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负) ...
- chapter 12_1 数据文件
Lua的一个重要特性,就是可以作为配置文件,利用到table构造式来定义一种文件格式. 只需要在写数据时做一点额外的工作,读取数据就会变得相当容易.也就是将数据作为Lua代码输出. 当运行这些代码时, ...
- Linux下好用的简单实用命令
1.你是否为在输入了一大串命令之后发现第一个字符打错了而苦恼?只能删除重来嘛?或者一步步左移光标? NO,一个组合键轻松搞定 Ctrl+A -----到命令行首 Ctrl+E ------到命令行末 ...
- Win7的64位系统如何搭建安卓Android开发环境
在搭建安卓Android开发环境,那么现在比较主流的Win7的64位操作系统如何搭建呢?其实很简单,不需要设置任何环境变量,只需要下载两个程序包(ADT和JDK),下载的时候注意选择相应的64位程序包 ...
- div盒布局
最近在应用程序中内嵌webkit浏览器显示网页,网页的布局是自适应的,采用盒布局模型,能够实现较好的自适应效果. <style> html,body { height: 100%; mar ...
- IP子网掩码格式转换
def exchange_maskint(mask_int): bin_arr = [' for i in range(32)] for i in range(mask_int): bin_arr[i ...
- LR错误整理
1.LoadRunner超时错误: 在录制Web服务器端,如果超过120秒服务器协议脚本回放时超时情况经常出现,产生错误的原因也有很多,解决的方法也不同. 错误现象1:Action.c(16): Er ...
- Spring线程池开发实战
Spring线程池开发实战 作者:chszs,转载需注明. 作者博客主页:http://blog.csdn.net/chszs 本文提供了三个Spring多线程开发的例子,由浅入深,由于例子一目了然, ...
- Spring的Bean,AOP以及工具类初探
1.Bean(Ioc) BeanWrapper 根据JavaDoc中的说明,BeanWrapper提供了设置和获取属性值(单个的或者是批量的),获取属性描述信息.查询只读或者可写属性等功能.不仅如此, ...
- LeetCode OJ 108. Convert Sorted Array to Binary Search Tree
Given an array where elements are sorted in ascending order, convert it to a height balanced BST. 把一 ...