java栈的应用_栈的java实现和栈的应用举例

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

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

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

栈的实现

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

Java代码 b9d4d579c718c41c98e67a9d9dd228b2.gif 428e3c96f6dd48b80fd5cb1d605362cf.png

f69c59c8ea4a054854d3a9f6d7909e22.gif

public interface MyStack {

/**

* 判断栈是否为空

*/

boolean isEmpty();

/**

* 清空栈

*/

void clear();

/**

* 栈的长度

*/

int length();

/**

* 数据入栈

*/

boolean push(T data);

/**

* 数据出栈

*/

T pop();

}

public interface MyStack {

/**

* 判断栈是否为空

*/

boolean isEmpty();

/**

* 清空栈

*/

void clear();

/**

* 栈的长度

*/

int length();

/**

* 数据入栈

*/

boolean push(T data);

/**

* 数据出栈

*/

T pop();

}

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

Java代码 b9d4d579c718c41c98e67a9d9dd228b2.gif 428e3c96f6dd48b80fd5cb1d605362cf.png

f69c59c8ea4a054854d3a9f6d7909e22.gif

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 

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 

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 

sb.append(objs[i].toString());

if (i != size - 1) {

sb.append(", ");

}

}

sb.append("]");

return sb.toString();

}

}

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代码 b9d4d579c718c41c98e67a9d9dd228b2.gif 428e3c96f6dd48b80fd5cb1d605362cf.png

f69c59c8ea4a054854d3a9f6d7909e22.gif

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;

}

}

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代码 b9d4d579c718c41c98e67a9d9dd228b2.gif 428e3c96f6dd48b80fd5cb1d605362cf.png

f69c59c8ea4a054854d3a9f6d7909e22.gif

@Test

public void testSpeed() {

MyStack stack = new MyArrayStack();

int num = 10000000;

long start = System.currentTimeMillis();

for (int i = 0; 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));

}

@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进制

Java代码 b9d4d579c718c41c98e67a9d9dd228b2.gif 428e3c96f6dd48b80fd5cb1d605362cf.png

f69c59c8ea4a054854d3a9f6d7909e22.gif

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();

}

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代码 b9d4d579c718c41c98e67a9d9dd228b2.gif 428e3c96f6dd48b80fd5cb1d605362cf.png

f69c59c8ea4a054854d3a9f6d7909e22.gif

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();

}

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代码 b9d4d579c718c41c98e67a9d9dd228b2.gif 428e3c96f6dd48b80fd5cb1d605362cf.png

f69c59c8ea4a054854d3a9f6d7909e22.gif

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();

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值