[例子和习题出自数据结构(严蔚敏版), 本人使用java进行实现.  转载请注明作者和出处,  如有谬误, 欢迎在评论中指正. ]

栈的实现

栈是一种先进后出的数据结构, 首先定义了栈需要实现的接口:

  1. public interface MyStack<T> {
  2. /**
  3. * 判断栈是否为空
  4. */
  5. boolean isEmpty();
  6. /**
  7. * 清空栈
  8. */
  9. void clear();
  10. /**
  11. * 栈的长度
  12. */
  13. int length();
  14. /**
  15. * 数据入栈
  16. */
  17. boolean push(T data);
  18. /**
  19. * 数据出栈
  20. */
  21. T pop();
  22. }

栈的数组实现, 底层使用数组:

  1. public class MyArrayStack<T> implements MyStack<T> {
  2. ];
  3. ;
  4. @Override
  5. public boolean isEmpty() {
  6. ;
  7. }
  8. @Override
  9. public void clear() {
  10. // 将数组中的数据置为null, 方便GC进行回收
  11. ; i < size; i++) {
  12. objs[size] = null;
  13. }
  14. ;
  15. }
  16. @Override
  17. public int length() {
  18. return size;
  19. }
  20. @Override
  21. public boolean push(T data) {
  22. // 判断是否需要进行数组扩容
  23. if (size >= objs.length) {
  24. resize();
  25. }
  26. objs[size++] = data;
  27. return true;
  28. }
  29. /**
  30. * 数组扩容
  31. */
  32. private void resize() {
  33. / 2 + 1];
  34. ; i < size; i++) {
  35. temp[i] = objs[i];
  36. objs[i] = null;
  37. }
  38. objs = temp;
  39. }
  40. @SuppressWarnings("unchecked")
  41. @Override
  42. public T pop() {
  43. ) {
  44. return null;
  45. }
  46. return (T) objs[--size];
  47. }
  48. @Override
  49. public String toString() {
  50. StringBuilder sb = new StringBuilder();
  51. sb.append("MyArrayStack: [");
  52. ; i < size; i++) {
  53. sb.append(objs[i].toString());
  54. ) {
  55. sb.append(", ");
  56. }
  57. }
  58. sb.append("]");
  59. return sb.toString();
  60. }
  61. }

栈的链表实现, 底层使用链表:

  1. public class MyLinkedStack<T> implements MyStack<T> {
  2. /**
  3. * 栈顶指针
  4. */
  5. private Node top;
  6. /**
  7. * 栈的长度
  8. */
  9. private int size;
  10. public MyLinkedStack() {
  11. top = null;
  12. ;
  13. }
  14. @Override
  15. public boolean isEmpty() {
  16. ;
  17. }
  18. @Override
  19. public void clear() {
  20. top = null;
  21. ;
  22. }
  23. @Override
  24. public int length() {
  25. return size;
  26. }
  27. @Override
  28. public boolean push(T data) {
  29. Node node = new Node();
  30. node.data = data;
  31. node.pre = top;
  32. // 改变栈顶指针
  33. top = node;
  34. size++;
  35. return true;
  36. }
  37. @Override
  38. public T pop() {
  39. if (top != null) {
  40. Node node = top;
  41. // 改变栈顶指针
  42. top = top.pre;
  43. size--;
  44. return node.data;
  45. }
  46. return null;
  47. }
  48. /**
  49. * 将数据封装成结点
  50. */
  51. private final class Node {
  52. private Node pre;
  53. private T data;
  54. }
  55. }

两种实现的比较, 主要比较数据入栈和出栈的速度:

  1. @Test
  2. public void testSpeed() {
  3. MyStack<Person> stack = new MyArrayStack<Person>();
  4. ;
  5. long start = System.currentTimeMillis();
  6. ; i < num; i++) {
  7. ));
  8. }
  9. long temp = System.currentTimeMillis();
  10. System.out.println("push time: " + (temp - start));
  11. while (stack.pop() != null)
  12. ;
  13. System.out.println("pop time: " + (System.currentTimeMillis() - temp));
  14. }

MyArrayStack中入栈和出栈10,000,000条数据的时间:

push time: 936
pop time: 47

将MyArrayStack改为MyLinkedStack后入栈和出栈的时间:

push time: 936

pop time: 126

可见两者的入栈速度差不多, 出栈速度MyArrayStack则有明显的优势.

为什么测试结果是这样的? 可能有些朋友的想法是数组实现的栈应该具有更快的遍历速度, 但增删速度应该比不上链表实现的栈才对. 但是栈中数据的增删具有特殊性: 只在栈顶入栈和出栈. 也就是说数组实现的栈在增加和删除元素时并不需要移动大量的元素, 只是在数组扩容时需要进行复制. 而链表实现的栈入栈和出栈时都需要将数据包装成Node或者从Node中取出数据, 还需要维护栈顶指针和前驱指针.

栈的应用举例

1. 将10进制正整数num转换为n进制

  1. private String conversion(int num, int n) {
  2. MyStack<Integer> myStack = new MyArrayStack<Integer>();
  3. Integer result = num;
  4. while (true) {
  5. // 将余数入栈
  6. myStack.push(result % n);
  7. result = result / n;
  8. ) {
  9. break;
  10. }
  11. }
  12. StringBuilder sb = new StringBuilder();
  13. // 按出栈的顺序倒序排列即可
  14. while ((result = myStack.pop()) != null) {
  15. sb.append(result);
  16. }
  17. return sb.toString();
  18. }

2. 检验符号是否匹配. '['和']', '('和')'成对出现时字符串合法. 例如"[][]()", "[[([]([])()[])]]"是合法的; "([(])", "[())"是不合法的.

遍历字符串的每一个char, 将char与栈顶元素比较. 如果char和栈顶元素配对, 则char不入栈, 否则将char入栈. 当遍历完成时栈为空说明字符串是合法的.

  1. public boolean isMatch(String str) {
  2. MyStack<Character> myStack = new MyArrayStack<Character>();
  3. char[] arr = str.toCharArray();
  4. for (char c : arr) {
  5. Character temp = myStack.pop();
  6. // 栈为空时只将c入栈
  7. if (temp == null) {
  8. myStack.push(c);
  9. }
  10. // 配对时c不入栈
  11. else if (temp == '[' && c == ']') {
  12. }
  13. // 配对时c不入栈
  14. else if (temp == '(' && c == ')') {
  15. }
  16. // 不配对时c入栈
  17. else {
  18. myStack.push(temp);
  19. myStack.push(c);
  20. }
  21. }
  22. return myStack.isEmpty();
  23. }

3. 行编辑: 输入行中字符'#'表示退格, '@'表示之前的输入全都无效.

使用栈保存输入的字符, 如果遇到'#'就将栈顶出栈, 如果遇到@就清空栈. 输入完成时将栈中所有字符出栈后反转就是输入的结果:

  1. private String lineEdit(String input) {
  2. MyStack<Character> myStack = new MyArrayStack<Character>();
  3. char[] arr = input.toCharArray();
  4. for (char c : arr) {
  5. if (c == '#') {
  6. myStack.pop();
  7. } else if (c == '@') {
  8. myStack.clear();
  9. } else {
  10. myStack.push(c);
  11. }
  12. }
  13. StringBuilder sb = new StringBuilder();
  14. Character temp = null;
  15. while ((temp = myStack.pop()) != null) {
  16. sb.append(temp);
  17. }
  18. // 反转字符串
  19. sb.reverse();
  20. return sb.toString();
  21. }

栈的java实现和栈的应用的更多相关文章

  1. 剑指Offer——栈的java实现和栈的应用举例

    剑指Offer--栈的java实现和栈的应用举例 栈是一种先进后出的数据结构, 栈的实现如下: 首先定义了栈需要实现的接口: public interface MyStack<T> { / ...

  2. java堆和栈的区别

    java 的内存分为两类,一类是栈内存,一类是堆内存.栈内存是指程序进入一个方法时,会为这个方法单独分配一块私属存储空间,用于存储这个方法内部的局部变量,当这个方法结束时,分配给这个方法的栈会释放,这 ...

  3. Java堆、栈和常量池以及相关String的详细讲解(经典中的经典) (转)

    原文链接 : http://www.cnblogs.com/xiohao/p/4296088.html 一:在JAVA中,有六个不同的地方可以存储数据: 1. 寄存器(register). 这是最快的 ...

  4. Java堆、栈和常量池

    摘录自 http://www.cnblogs.com/xiohao/p/4296088.html 1. 栈(stack)与堆(heap)都是Java用来在RAM中存放数据的地方.与C++不同,Java ...

  5. Java堆、栈和常量池以及相关String的详细讲解

    一:在JAVA中,有六个不同的地方可以存储数据: 1. 寄存器(register). 这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部.但是寄存器的数量极其有限,所以寄存器由编译器根据 ...

  6. Java堆和栈详解

    Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...

  7. java堆、栈、堆栈的区别

    1.栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. 2. 栈的优势是,存取速度比堆要快,仅次于直接位于CP ...

  8. JAVA数据结构系列 栈

    java数据结构系列之栈 手写栈 1.利用链表做出栈,因为栈的特殊,插入删除操作都是在栈顶进行,链表不用担心栈的长度,所以链表再合适不过了,非常好用,不过它在插入和删除元素的时候,速度比数组栈慢,因为 ...

  9. java与数据结构(6)---java实现链栈

    栈之链式存储结构链栈 链栈 栈的链式存储结构成为链栈.链栈是没有头结点,头结点就是栈顶指针top. 代码结构 package list; public interface Stackable;公共接口 ...

随机推荐

  1. CevaEclipse - 编译器attribute扩展

    1.函数与变量的 Section Attribute void foobar (void) __attribute__ ((section (".CSECT mmm"))); vo ...

  2. 日志输出--C#

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  3. java读写串口

    http://blog.csdn.net/xxyy888/article/details/8946046

  4. HttpServletResponse应用----生成验证码

    1.1生成随机图片用作验证码 生成图片主要用到BufferedImage类 package gacl.response.study;import java.awt.Color;import java. ...

  5. 正则表达式 替换 <img > 标签

    /** * 正则表达式过滤<img > 标签 * @param str * @return */ public static String cutOutImgPrefix(String s ...

  6. 执行 npm run update-webdriver 提示文件不能获取错误

    按照angularjs官网的入门教程中输入 npm run update-webdriver  总是提示 https://chromedriver.storage.googleapis.com/2.1 ...

  7. 转 精选37条强大的常用linux shell命令组合

    1 删除0字节文件 find . -type f -size 0 -exec rm -rf {} \; find . type f -size 0 -delete 2 查看进程,按内存从大到小排列 p ...

  8. css font简写规则

    是不是在很很多网站的公共样式中会看到这样的代码?font: 12px/150% Arial, Verdana, "\5b8b\4f53";意思为:字体大小/行高 字体族 " ...

  9. 学习笔记——迭代器模式Iterator

    迭代器模式,使用很多,但是很少实现.常用的集合都支持迭代器. 集合中的CreateIterator()可用于创建自己的迭代器,在里面通过调用迭代器的构造函数Iterator(Aggregate)来绑定 ...

  10. 解决ie阴影的兼容性

    box-shadow:0px 0px 10px #aba25b; -webkit-box-shadow:0px 0px 10px #aba25b; -moz-box-shadow:0px 0px 10 ...