栈的实现

我们提供的服务有:网站设计制作、成都做网站、微信公众号开发、网站优化、网站认证、应城ssl等。为上千余家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的应城网站制作公司
栈是一种先进后出的数据结构, 首先定义了栈需要实现的接口:
- public interface MyStack
 { - /**
 - * 判断栈是否为空
 - */
 - boolean isEmpty();
 - /**
 - * 清空栈
 - */
 - void clear();
 - /**
 - * 栈的长度
 - */
 - int length();
 - /**
 - * 数据入栈
 - */
 - boolean push(T data);
 - /**
 - * 数据出栈
 - */
 - T pop();
 - }
 
栈的数组实现,底层使用数组:
- 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();
 - }
 - }
 
栈的链表实现,底层使用链表:
- 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;
 - }
 - }
 
两种实现的比较,主要比较数据入栈和出栈的速度:
- @Test
 - public 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进制
- 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入栈. 当遍历完成时栈为空说明字符串是合法的。
- 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. 行编辑: 输入行中字符'#'表示退格, '@'表示之前的输入全都无效。
使用栈保存输入的字符, 如果遇到'#'就将栈顶出栈, 如果遇到@就清空栈. 输入完成时将栈中所有字符出栈后反转就是输入的结果:
- private String lineEdit(String input) {
 - MyStack
 myStack = new MyArrayStack (); - 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实现和栈的应用举例
                
                浏览地址:http://www.csdahua.cn/qtweb/news20/114220.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网