[例子和习题出自数据结构(严蔚敏版), 本人使用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. HDU 2955 Robberies(01背包)

    Robberies Problem Description The aspiring Roy the Robber has seen a lot of American movies, and kno ...

  2. Vultr优惠码20美元享受20GB SSD和2T流量

    美国vps主机商vultr最新优惠码:20FOR30,只限新注册用户,点击注册链接,进入后台Billing,找到Gift code,输入20FOR30,点击apply,就能免费获得20美元的账户余额. ...

  3. 洛谷-火柴棒等式-NOIP2008提高组复赛

    题目描述 Description 给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0).用火柴棍拼数字0-9的拼法如图所示: ...

  4. java的String类型为什么是final

    (转自:http://www.cnblogs.com/ikuman/archive/2013/08/27/3284410.html) 最佳答案: 主要是为了“效率” 和 “安全性” 的缘故.若 Str ...

  5. (转载)CSS中zoom:1的作用

    CSS中zoom:1的作用兼容IE6.IE7.IE8浏览器,经常会遇到一些问题,可以使用zoom:1来解决,有如下作用:触发IE浏览器的haslayout解决ie下的浮动,margin重叠等一些问题. ...

  6. The Linux Storage Stack Diagram 内核 4.0 版的 I/O 栈

  7. samba server 设置

     samba server  设置yum install samba.x86_64systemctl start smb.servicesystemctl enable smb.servicesamb ...

  8. SVN ---文件加锁,执行clean up命令

    一.SVN 中 clean up 的功能 当Subversion改变你的工作拷贝(或是.svn中的任何信息),它会尽可能的小心,在修改任何事情之前,它把意图写到日志文件中去,然后执行log文件中的命令 ...

  9. Git客户端SourceTree回滚到远程仓库和切换分支

    使用SourceTree将远程仓库回滚到某一次提交 原理:在本地需要回滚的commit上创建一个分支,将该分支合并到远程仓库. 步骤 1.在需要回滚的commit上右键创建分支 创建分支 2.输入新的 ...

  10. tomcat各目录(文件)作用

    以tomcat7.0.50为例,主目录下有bin,conf,lib,logs,temp,webapps,work 7个文件夹 bin目录主要是用来存放tomcat的命令,主要有两大类,一类是以.sh结 ...