剑指Offer——栈的java实现和栈的应用举例
剑指Offer——栈的java实现和栈的应用举例
栈是一种先进后出的数据结构, 栈的实现如下:
首先定义了栈需要实现的接口:
public interface MyStack<T> {
/**
* 判断栈是否为空
*/
boolean isEmpty();
/**
* 清空栈
*/
void clear();
/**
* 栈的长度
*/
int length();
/**
* 数据入栈
*/
boolean push(T data);
/**
* 数据出栈
*/
T pop();
}
接下来定义了栈的数组实现:
package cn.edu.ujn.stack;
/**
* 栈的数组实现, 底层使用数组
* @author SHQ
*
* @param <T>
*/
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重新设置为栈空间
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();
}
}
然后定义了栈的链表实现:
package cn.edu.ujn.stack;
/**
* 栈的链表实现, 底层使用链表
* @author SHQ
*
* @param <T>
*/
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;
}
}
两种实现的比较, 主要比较数据入栈和出栈的速度:
package cn.edu.ujn.stack;
public class Test {
public static void main(String[] args) {
testSpeed();
}
private static void testSpeed() {
// 测试数组实现
//MyStack<Person> stack = new MyArrayStack<Person>();
// 测试链表实现
MyStack<Person> stack = new MyLinkedStack<Person>();
int num = 1000000;
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则有明显的优势.
为什么测试结果是这样的? 可能有些朋友的想法是:数组实现的栈应该具有更快的遍历速度, 但增删速度应该比不上链表实现的栈才对。但是栈中数据的增删具有特殊性: 只在栈顶入栈和出栈。也就是说数组实现的栈在增加和删除元素时并不需要移动大量的元素, 只是在数组扩容时需要进行复制。而链表实现的栈入栈和出栈时都需要将数据包装成Node或者从Node中取出数据, 还需要维护栈顶指针和前驱指针。
栈的应用举例
1.将10进制正整数num转换为n进制
package cn.edu.ujn.stack;
public class StackApp {
/**
* @param args
*/
public static void main(String[] args) {
//System.out.println(conversion4D2X(22, 2));
//System.out.println(isMatch("[()]"));
System.out.println(lineEdit("Hello #world"));
}
/**
*栈的应用举例-将10进制正整数num转换为n进制
* @param num 待转化十进制数
* @param n 转化进制
* @return
*/
private static String conversion4D2X(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入栈. 当遍历完成时栈为空说明字符串是合法的.
/**
* 栈的应用举例-检验符号是否匹配:
* '['和']', '('和')'成对出现时字符串合法. 例如"[][]()", "[[([]([])()[])]]"是合法的; "([(])", "[())"是不合法的.
* @param str
* @return boolean
*/
private static 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.行编辑
输入行中字符'#'表示退格, '@'表示之前的输入全都无效.
使用栈保存输入的字符, 如果遇到'#'就将栈顶出栈, 如果遇到@就清空栈. 输入完成时将栈中所有字符出栈后反转就是输入的结果:
/**
* 栈的应用举例-行编辑:
* 输入行中字符'#'表示退格, '@'表示之前的输入全都无效.
* @param input
* @return String
*/
private static 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);
}
}
// StringBuffer线程安全,StringBuilder线程不安全效率高
StringBuilder sb = new StringBuilder();
Character temp = null;
while ((temp = myStack.pop()) != null) {
sb.append(temp);
}
// 反转字符串
sb.reverse();
return sb.toString();
}
美文美图
剑指Offer——栈的java实现和栈的应用举例的更多相关文章
- 剑指offer题解(Java版)
剑指offer题解(Java版) 从尾到头打印链表 题目描述 输入一个链表,按从尾到头的顺序返回一个ArrayList. 方法1:用一个栈保存从头到尾访问链表的每个结点的值,然后按出栈顺序将各个值存入 ...
- 剑指 Offer 30. 包含min函数的栈 + 双栈实现求解栈中的最小值
剑指 Offer 30. 包含min函数的栈 Offer_30 题目描述: 题解分析: 题目其实考察的是栈的知识,本题的目的是使用两个栈来求解最小值. 第二个栈主要用来维护第一个栈中的最小值,所以它里 ...
- 剑指Offer——知识点储备-Java基础
剑指Offer--知识点储备-Java基础 网址来源: http://www.nowcoder.com/discuss/5949?type=0&order=0&pos=4&pa ...
- 《剑指offer》 包含min函数的栈
本题来自<剑指offer> 包含min函数的栈 题目: 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)). 思路: 举例子让抽象问题具体 ...
- 剑指Offer(二十一):栈的压入、弹出序列
剑指Offer(二十一):栈的压入.弹出序列 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net/b ...
- 剑指 Offer 30. 包含min函数的栈
剑指 Offer 30. 包含min函数的栈 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min.push 及 pop 的时间复杂度都是 O(1). 示例 ...
- 力扣 - 剑指 Offer 30. 包含min函数的栈
题目 剑指 Offer 30. 包含min函数的栈 思路1 使用一个辅助栈min_stack,用来维护栈的最小的元素 每次添加元素入栈时候,data_stack和min_stack都要同时维护 dat ...
- 【剑指Offer】包含min函数的栈 解题报告
[剑指Offer]包含min函数的栈 解题报告 标签(空格分隔): 牛客网 题目地址:https://www.nowcoder.com/questionTerminal/beb5aa231adc45b ...
- 【Java】 剑指offer(30) 包含min函数的栈
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min ...
- 剑指offer编程题Java实现——面试题7相关题用两个队列实现一个栈
剑指offer面试题7相关题目:用两个队列实现一个栈 解题思路:根据栈的先入后出和队列的先入先出的特点1.在push的时候,把元素向非空的队列内添加2.在pop的时候,把不为空的队列中的size()- ...
随机推荐
- SPOJ COT(树上的点权第k大)
Count on a tree Time Limit: 129MS Memory Limit: 1572864KB 64bit IO Format: %lld & %llu Submi ...
- [BZOJ]1014 火星人prefix(JSOI2008)
一边听省队dalao讲课一边做题真TM刺激. BZOJ的discuss简直就是题面plus.大样例.SuperHINT.dalao题解的结合体. Description 火星人最近研究了一种操作:求一 ...
- bzoj 1974: [Sdoi2010]代码拍卖会
Description 随着iPig在P++语言上的造诣日益提升,他形成了自己一套完整的代 码库.猪王国想参加POI的童鞋们都争先恐后问iPig索要代码库.iPi g不想把代码库给所有想要的小猪,只想 ...
- 基于Android的高校饮水宝app
这是一个高校饮用水配送项目,是一个毕业设计,去年的,包括了服务端和客户端,是一个不错的项目,分享一下: 随着通讯行业的迅猛发展,我国的手机用户也在不断的增加.据信息部的统计数据显示,我国已有接近7. ...
- vim配置文件和插件管理
本文通过总结零碎的资料总结而成,更多是去引导学习vim配置文件及插件使用. .vimrc配置文件,内容如下(备注清晰) "引入插件pathogen使用 execute pathogen#in ...
- Weekly Contest 75题解
Q1. Rotate String(796) We are given two strings, A and B. A shift on A consists of taking string A a ...
- 从JVM角度看i++ 与++i
1.i++和++i的问题 反编译结果为 Code: 0: iconst_1 1: istore_1 2: iinc 1, 1 //这个个指令,把局部变量1,也就是i,增加1,这 ...
- BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext
这个坑爹的玩意 有几个出现错误的原因 服务器 1.服务器重复启动同一个部署 这个时候要停止然后启动 电脑差的 重启电脑 重启服务器就好了 代码 2.bean工厂不知道哪里关闭 3.bean工厂没有找到 ...
- session.save()返回值问题
正常都应该返回插入的主键 但是 如果你用sessionFactory来写就一定返回0 先科普下持久化数据库的三个状态方便下面理解 一次会话状态中,持久化对象经历以下三种状态:1 transient:对 ...
- 关于一些基础的Java问题的解答(四)
16. Java面向对象的三个特征与含义 java中的面向对象的三大基本特征分别是:封装.继承.多态: 封装:把过程和数据包围起来,对数据的访问只能通过已定义的界面,主要是方便类的修改 继承:对象的一 ...