[转]stack(顺序、链式及应用)
(java版)
1. 顺序栈的实现
- package lang;
- import java.io.Serializable;
- import java.util.Arrays;
- /**
- * @ClassName: ArrayStack
- * @Description: 顺序栈
- * @date 2014年1月20日 上午8:47:19
- * @param <T>
- */
- public class ArrayStack<T> implements Serializable {
- /**
- * @Fields serialVersionUID : TODO
- */
- private static final long serialVersionUID = 74027006708386243L;
- private Object[] elementData;//定义一个数组用于保存顺序栈的元素
- private int size = 0;//保存顺序栈中元素的当前个数
- private int capacity;//保存数组的长度
- public ArrayStack() {
- elementData = new Object[10];//默认长度为10的栈
- }
- public ArrayStack(int initSize) {
- elementData = new Object[initSize];//默认长度为10的栈
- }
- public ArrayStack(T element) {
- this();
- elementData[0] = element;
- size++;
- }
- public ArrayStack(T element, int initSize) {
- this.capacity = initSize;
- elementData = new Object[capacity];
- elementData[0] = element;
- size++;
- }
- /**
- * @Title: size
- * @Description: 栈长度
- * @return
- */
- public int size() {
- return size;
- }
- /**
- * @Title: push
- * @Description: 入栈
- * @param element
- */
- public void push(T element) {
- ensureCapacity(size + 1);
- elementData[size++] = element;
- }
- private void ensureCapacity(int minCapacity) {
- //如果数组的原有长度小于目前所需的长度
- int oldCapacity = elementData.length;
- if (minCapacity > oldCapacity) {
- int newCapacity = (oldCapacity * 3) / 2 + 1;
- if (newCapacity < minCapacity)
- newCapacity = minCapacity;
- // minCapacity is usually close to size, so this is a win:
- elementData = Arrays.copyOf(elementData, newCapacity);
- }
- }
- /**
- * @Title: pop
- * @Description: 出栈
- * @return
- */
- public T pop() {
- if (!isEmpty()) {
- T oldValue = (T) elementData[size - 1];
- //释放栈顶元素
- elementData[--size] = null;
- return oldValue;
- } else {
- return null;
- }
- }
- /**
- * @Title: peek
- * @Description: 返回栈顶元素,但不删除栈顶元素
- * @return
- */
- public T peek() {
- if (!isEmpty()) {
- return (T) elementData[size - 1];
- } else {
- throw new IndexOutOfBoundsException("空栈异常");
- }
- }
- /**
- * @Title: empty
- * @Description: 判断顺序栈是否为空栈
- * @return
- */
- public boolean isEmpty() {
- return size == 0;
- }
- /**
- * @Title: clear
- * @Description: 清空顺序栈
- */
- public void clear() {
- //将底层数组所有元素赋为null
- Arrays.fill(elementData, null);
- size = 0;
- }
- public String toString() {
- if (size == 0) {
- return "[]";
- } else {
- StringBuilder sb = new StringBuilder("[");
- for (int i = size - 1; i > -1; i--) {
- sb.append(elementData[i].toString() + ", ");
- }
- int len = sb.length();
- return sb.delete(len - 2, len).append("]").toString();
- }
- }
- }
顺序栈实现2
- package lang;
- import java.util.ArrayList;
- import java.util.EmptyStackException;
- public class ArrayStack2<E> extends ArrayList<E> {
- /**
- * @Fields serialVersionUID : TODO
- */
- private static final long serialVersionUID = -4396620094929287983L;
- public ArrayStack2() {
- super();
- }
- public ArrayStack2(final int initialSize) {
- super(initialSize);
- }
- public boolean empty() {
- return isEmpty();
- }
- public E peek() throws EmptyStackException {
- final int n = size();
- if (n <= 0) {
- throw new EmptyStackException();
- } else {
- return get(n - 1);
- }
- }
- public E peek(final int n) throws EmptyStackException {
- final int m = (size() - n) - 1;
- if (m < 0) {
- throw new EmptyStackException();
- } else {
- return get(m);
- }
- }
- public E pop() throws EmptyStackException {
- final int n = size();
- if (n <= 0) {
- throw new EmptyStackException();
- } else {
- return remove(n - 1);
- }
- }
- public E push(final E item) {
- add(item);
- return item;
- }
- public int search(final Object object) {
- int i = size() - 1; // Current index
- int n = 1; // Current distance
- while (i >= 0) {
- final Object current = get(i);
- if ((object == null && current == null)
- || (object != null && object.equals(current))) {
- return n;
- }
- i--;
- n++;
- }
- return -1;
- }
- }
2. 链式栈的实现:
- package lang;
- import java.io.Serializable;
- /**
- * @ClassName: LinkStack
- * @Description: 链式栈
- * @date 2014年1月20日 下午3:46:40
- * @param <T>
- */
- public class LinkStack<T> implements Serializable{
- /**
- * @Fields serialVersionUID : TODO
- */
- private static final long serialVersionUID = -4378447264374701299L;
- private class Node{
- private T data; //保存节点的数据
- private Node next; //指向下个节点的引用
- public Node(){
- }
- public Node(T data, Node next){
- this.data = data;
- this.next = next;
- }
- }
- private Node top; //保存该链栈的栈顶元素
- private int size = 0; //保存该链栈中已包含的节点数,即栈的长度
- public LinkStack(){
- top = null;
- }
- public LinkStack(T element) {
- top = new Node(element , null);
- size++;
- }
- /**
- * @Title: size
- * @Description: 栈的长度
- * @return
- */
- public int size(){
- return size;
- }
- /**
- * @Title: push
- * @Description: 入栈
- * @param element
- */
- public void push(T element){
- top = new Node(element , top);
- size++;
- }
- /**
- * @Title: pop
- * @Description: 出栈
- * @return
- */
- public T pop(){
- Node oldTop = top;
- top = top.next;
- oldTop.next = null;
- size--;
- return oldTop.data;
- }
- /**
- * @Title: peek
- * @Description: 访问栈顶元素
- * @return
- */
- public T peek(){
- return top.data;
- }
- /**
- * @Title: empty
- * @Description: 判断顺序栈是否为空栈
- * @return
- */
- public boolean isEmpty() {
- return size == 0;
- }
- /**
- * @Title: clear
- * @Description: 清空顺序栈
- */
- public void clear() {
- top = null;//将栈所有元素赋为null
- size = 0;
- }
- public String toString() {
- //链栈为空链栈时
- if (isEmpty()) {
- return "[]";
- } else {
- StringBuilder sb = new StringBuilder("[");
- for (Node current = top ; current != null ; current = current.next ) {
- sb.append(current.data.toString() + ", ");
- }
- int len = sb.length();
- return sb.delete(len - 2 , len).append("]").toString();
- }
- }
- }
3. 栈的应用
3.1 将10进制正整数num转换为n进制
- package stack.apply;
- import org.junit.Test;
- import lang.ArrayStack;
- /**
- * @ClassName: Conversion
- * @Description: 将10进制正整数num转换为n进制
- * @date 2014年1月21日 上午9:47:22
- */
- public class Conversion {
- /**
- * @Title: conversion
- * @Description: 将10进制正整数num转换为n进制
- * @param num: 10进制正整数
- * @param n: n进制
- * @return 转换后的值
- */
- private String conversion(int num, int n) {
- ArrayStack<Integer> myStack = new ArrayStack<Integer>();
- 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();
- }
- @Test
- public void testConversion(){
- String s = conversion(13,2);
- System.out.println(s);
- }
- }
3.2 行编辑:
输入行中字符'#'表示退格, '@'表示之前的输入全都无效.
- package stack.apply;
- import org.junit.Test;
- import lang.ArrayStack;
- /**
- * @ClassName: LineEdit
- * @Description: 行编辑: 输入行中字符'#'表示退格, '@'表示之前的输入全都无效.
- * @date 2014年1月21日 上午10:17:06
- */
- public class LineEdit {
- /**
- * @Title: lineEdit
- * @Description: 行编辑
- * @param input
- * @return
- */
- private String lineEdit(String input) {
- ArrayStack<Character> myStack = new ArrayStack<Character>();
- 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();
- }
- @Test
- public void testLineEdit(){
- String s = lineEdit("abcd#dsa@#usera#22#8");
- System.out.println(s);
- }
- }
3.3 检验符号是否匹配.
'['和']', '('和')'成对出现时字符串合法.
例如"[][]()", "[[([]([])()[])]]"是合法的; "([(])", "[())"是不合法的
- package stack.apply;
- import org.junit.Test;
- import lang.ArrayStack;
- /**
- * @ClassName: Match
- * @Description: 检验符号是否匹配. '['和']', '('和')'成对出现时字符串合法.
- * 例如"[][]()", "[[([]([])()[])]]"是合法的; "([(])", "[())"是不合法的
- * @date 2014年1月21日 上午10:14:47
- */
- public class Match {
- /**
- * @Title: isMatch
- * @Description: 检验符号是否匹配
- * @param str 输入要匹配的字符串
- * @return 是否匹配
- */
- public boolean isMatch(String str) {
- ArrayStack<Character> myStack = new ArrayStack<Character>();
- 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();
- }
- @Test
- public void testMatch(){
- boolean b = isMatch("[[([]([])()[])]]");
- System.out.println(b);
- }
- }
- ===================================
- (java)
-
栈的实现
栈是一种先进后出的数据结构, 首先定义了栈需要实现的接口:
- public interface MyStack<T> {
- /**
- * 判断栈是否为空
- */
- boolean isEmpty();
- /**
- * 清空栈
- */
- void clear();
- /**
- * 栈的长度
- */
- int length();
- /**
- * 数据入栈
- */
- boolean push(T data);
- /**
- * 数据出栈
- */
- T pop();
- }
栈的数组实现,底层使用数组:
- public class MyArrayStack<T> implements MyStack<T> {
- 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<T> implements MyStack<T> {
- /**
- * 栈顶指针
- */
- 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<Person> stack = new MyArrayStack<Person>();
- 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<Integer> myStack = new MyArrayStack<Integer>();
- 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<Character> myStack = new MyArrayStack<Character>();
- 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<Character> myStack = new MyArrayStack<Character>();
- 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();
- (c版)
-
判断一行字符串输入"各种括号"是否是合法的-----------------------栈用数组实现
如:[()]是合法的(balance)
[(])是不合法的(imbalance)
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- typedef struct Mystack *Stack;
- struct Mystack {
- int Capacity; /* 栈的容量 */
- int Top_of_stack; /* 栈顶下标 */
- char *Array; /* 存放栈中元素的数组 */
- };
- /* 栈的创建 */
- Stack CreateStack(int Max)
- {
- Stack S;
- S = malloc(sizeof(struct Mystack));
- if (S == NULL)
- printf("Create stack error!\n");
- S->Array = malloc(sizeof(char) * Max);
- if (S->Array == NULL)
- printf("Create stack error!\n");
- S->Capacity = Max;
- S->Top_of_stack = 0;
- return S;
- }
- /* 释放栈 */
- void DisposeStack(Stack S)
- {
- if (S != NULL)
- {
- free(S->Array);
- free(S);
- }
- }
- /* 判断一个栈是否是空栈 */
- int IsEmpty(Stack S)
- {
- return !S->Top_of_stack;
- }
- /* 判断一个栈是否满栈 */
- int IsFull(Stack S)
- {
- if (S->Top_of_stack == S->Capacity - 1)
- return 1;
- else
- return 0;
- }
- /* 数据入栈 */
- int Push(int x, Stack S)
- {
- if (IsFull(S))
- printf("The Stack is full!\n");
- else
- S->Array[S->Top_of_stack++] = x;
- }
- /* 数据出栈 */
- int Pop(Stack S)
- {
- if (IsEmpty(S))
- printf("The Stack is empty!\n");
- else
- S->Top_of_stack--;
- }
- /* 将栈顶返回 */
- char Top(Stack S)
- {
- if (!IsEmpty(S))
- return S->Array[S->Top_of_stack-1];
- printf("The Stack is empty!\n");
- return 0;
- }
- int main()
- {
- int i, len;
- char str[100];
- printf("Please input the symbol that you want to balance: \n");
- scanf("%s", str);
- len = strlen(str);
- /* 根据序列的长度来创建栈 */
- struct Mystack *my_stack = CreateStack(len+1);
- for (i = 0; i < len; i++)
- {
- if (str[i] == '{' || str[i] == '[' || str[i] == '(' )
- Push(str[i], my_stack);
- if (str[i] == '}')
- {
- if (Top(my_stack) == '{')
- Pop(my_stack);
- else
- break;
- }
- else if (str[i] == ']')
- {
- if (Top(my_stack) == '[')
- Pop(my_stack);
- else
- break;
- }
- else if (str[i] == ')')
- {
- if (Top(my_stack) == '(')
- Pop(my_stack);
- else
- break;
- }
- }
- /* 如果最后占空则序列是合法的 */
- if(IsEmpty(my_stack))
- printf("The symbol that you input is balance!\n");
- else
- printf("The symbol that you input is imbalance!\n");
- DisposeStack(my_stack);
- return 0;
- }
测试:
- shang@shang:~/C$ ./a.out
- Please input the symbol that you want to balance:
- {[]}
- The symbol that you input is balance!
- shang@shang:~/C$ ./a.out
- Please input the symbol that you want to balance:
- [(])
- The symbol that you input is imbalance!
- shang@shang:~/C$ ./a.out
- Please input the symbol that you want to balance:
- ([{}])
- The symbol that you input is balance!
- shang@shang:~/C$
- 用栈计算逆波兰式
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- typedef struct Mystack *Stack;
- struct Mystack {
- int Capacity; /* 栈的容量 */
- int Top_of_stack; /* 栈顶下标 */
- int *Array; /* 存放栈中元素的数组 */
- };
- /* 栈的创建 */
- Stack CreateStack(int Max)
- {
- Stack S;
- S = malloc(sizeof(struct Mystack));
- if (S == NULL)
- printf("Create stack error!\n");
- S->Array = malloc(sizeof(char) * Max);
- if (S->Array == NULL)
- printf("Create stack error!\n");
- S->Capacity = Max;
- S->Top_of_stack = 0;
- return S;
- }
- /* 释放栈 */
- void DisposeStack(Stack S)
- {
- if (S != NULL)
- {
- free(S->Array);
- free(S);
- }
- }
- /* 判断一个栈是否是空栈 */
- int IsEmpty(Stack S)
- {
- return !S->Top_of_stack;
- }
- /* 判断一个栈是否满栈 */
- int IsFull(Stack S)
- {
- if (S->Top_of_stack == S->Capacity - 1)
- return 1;
- else
- return 0;
- }
- /* 数据入栈 */
- int Push(int x, Stack S)
- {
- if (IsFull(S))
- printf("The Stack is full!\n");
- else
- S->Array[S->Top_of_stack++] = x;
- }
- /* 数据出栈 */
- int Pop(Stack S)
- {
- if (IsEmpty(S))
- printf("The Stack is empty!\n");
- else
- S->Top_of_stack--;
- }
- /* 将栈顶返回 */
- int Top(Stack S)
- {
- if (!IsEmpty(S))
- return S->Array[S->Top_of_stack-1];
- printf("The Stack is empty!\n");
- return 0;
- }
- int main()
- {
- int i, len, result;
- char str[100];
- printf("Please input the postfix that you want to compute: \n");
- scanf("%s", str);
- len = strlen(str);
- /* 根据序列的长度来创建栈 */
- struct Mystack *my_stack = CreateStack(len+1);
- for (i = 0; i < len; i++)
- {
- if (str[i] >= '0' && str[i] <= '9')
- Push((int)str[i]-48, my_stack);
- else if (str[i] == '+')
- {
- int x = Top(my_stack);
- Pop(my_stack);
- int y =Top(my_stack);
- Pop(my_stack);
- Push(x+y, my_stack);
- //printf("%d\n", Top(my_stack));
- }
- else if (str[i] == '-')
- {
- int x = Top(my_stack);
- Pop(my_stack);
- int y = Top(my_stack);
- Pop(my_stack);
- Push(x-y, my_stack);
- //printf("%d\n", Top(my_stack));
- }
- else if (str[i] == '*')
- {
- int x = Top(my_stack);
- Pop(my_stack);
- int y = Top(my_stack);
- Pop(my_stack);
- Push(x*y, my_stack);
- //printf("%d\n", Top(my_stack));
- }
- else if (str[i] == '/')
- {
- int x = Top(my_stack);
- Pop(my_stack);
- int y = Top(my_stack);
- Pop(my_stack);
- Push(x/y, my_stack);
- //printf("%d\n", Top(my_stack));
- }
- }
- printf("The result is: %d\n", Top(my_stack));
- Pop(my_stack);
- /* A bug */
- // DisposeStack(my_stack);
- return 0;
- }