博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
栈的java实现和栈的应用举例
阅读量:5377 次
发布时间:2019-06-15

本文共 7856 字,大约阅读时间需要 26 分钟。

转自:http://coolxing.iteye.com/blog/1468674

——————————————————————————————————————————————————————————

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

栈的实现

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

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. }  
public interface MyStack
{ /** * 判断栈是否为空 */ boolean isEmpty(); /** * 清空栈 */ void clear(); /** * 栈的长度 */ int length(); /** * 数据入栈 */ boolean push(T data); /** * 数据出栈 */ T pop();}

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

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

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

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

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

Java代码  
  1. @Test  
  2. public void testSpeed() {   
  3.     MyStack<Person> stack = new MyArrayStack<Person>();   
  4.     int num = 10000000;   
  5.     long start = System.currentTimeMillis();   
  6.     for (int i = 0; i < num; i++) {   
  7.         stack.push(new Person("xing", 25));   
  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. }  
@Testpublic void testSpeed() {	MyStack
stack = new MyArrayStack
(); int num = 10000000; long start = System.currentTimeMillis(); for (int i = 0; i < num; i++) { stack.push(new Person("xing", 25)); } 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条数据的时间:

push time: 936
pop time: 47

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

push time: 936

pop time: 126

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

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

 

栈的应用举例

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

Java代码  
  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.         if (result == 0) {   
  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. }  
private String conversion(int num, int n) {	MyStack
myStack = new MyArrayStack
(); Integer result = num; while (true) { // 将余数入栈 myStack.push(result % n); result = result / n; if (result == 0) { break; } } StringBuilder sb = new StringBuilder(); // 按出栈的顺序倒序排列即可 while ((result = myStack.pop()) != null) { sb.append(result); } return sb.toString();}

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

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

Java代码  
  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. }  
public boolean isMatch(String str) {	MyStack
myStack = new MyArrayStack
(); 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. 行编辑: 输入行中字符'#'表示退格, '@'表示之前的输入全都无效.

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

Java代码  
  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.        
  14.     StringBuilder sb = new StringBuilder();   
  15.     Character temp = null;   
  16.     while ((temp = myStack.pop()) != null) {   
  17.         sb.append(temp);   
  18.     }   
  19.     // 反转字符串   
  20.     sb.reverse();   
  21.     return sb.toString();   
  22. }  

转载于:https://www.cnblogs.com/kaikailele/p/4007490.html

你可能感兴趣的文章
第四周作业
查看>>
腾讯分析系统架构解析
查看>>
UglifyJS压缩JS
查看>>
PHP array_diff_uassoc
查看>>
Word添加论文引用标注
查看>>
根据地图上的两个点各自的x,y坐标,计算出2点之间的直线距离。显示为公里、米...
查看>>
【总结】线段树
查看>>
前端必备 CSS Sprites雪碧图生成工具
查看>>
面试题51:数组中重复的数字
查看>>
java多线程整理
查看>>
api中locale或language字段,传送客户端地域信息,一般为下划线
查看>>
spark1.3.1安装和集群的搭建
查看>>
linux useradd 的一个用法
查看>>
MySQL开启远程连接的方法
查看>>
Spring学习笔记之五----Spring MVC
查看>>
ionic v1.1.0 select 安卓不工作
查看>>
智能的API、云服务和SOA测试解决方案——Parasoft SOAtest
查看>>
前端之html的常用标签2和css基本使用
查看>>
去掉 map area 在IE里点击时出现的框
查看>>
[HDU 3652] B-number
查看>>