一、问题描述
如何设计一个括号匹配的功能?比如给你一串括号让你判断是否符合我们的括号原则,如下所示:
二、代码解决
1.构建基础栈
代码如下(示例):
public interface MyStack<Item> {
MyStack<Item> push(Item item); //入栈
Item pop(); //出栈
int size(); // 大小
boolean isEmpty();
}
public class ArrayStack<Item> implements MyStack<Item>{
private Item [] a = (Item[]) new Object[1]; //最好就是开始的时候就设置大小
private int n = 0; //大小 初始的元素个数
public ArrayStack(int cap) {
a = (Item[]) new Object[cap];
}
public MyStack<Item> push(Item item) { //入栈就完成了 //时间复杂度 O(1)
judgeSize();
a[n++] = item;//等于先用n,在对n+1
return null;
}
private void judgeSize(){
if(n >= a.length){ //元素个数已经超出了数组的个数
resize(2 * a.length); //10*2*2=40个大小了,我出栈了20个了,只剩下20了吧。
}else if(n > 0 && n <= a.length / 2){
resize(a.length / 2);
}
}
private void resize(int size){ //扩容O(n)
Item[] temp = (Item[]) new Object[size];
for(int i = 0 ; i < n; i ++){
temp[i] = a[i];
}
a = temp;
}
public Item pop() { //出栈 O(1)
if(isEmpty()){
return null;
}
Item item = a[--n]; //--n和n-- --n是先把n减了在用,n--先用了在减
a[n] = null;
/*int temp=n-1;
Item item=a[temp];
n--;
a[temp]=null;*/
return item;
}
public int size() {
return n;
}
public boolean isEmpty() {
return n == 0;
}
}
注意一下a[n++] = item
,等于先让n的位置是item,在对n进行+1
2.用栈的特性来进行匹配
原理:
我们从头开始遍历这个算术表达式:
1.遇到是数字 我们就直接入栈到数字栈里面去。
2.遇到是符合 就把符号栈的栈顶拿出来做比较。如果说他比栈顶符号的优先级高就直接入栈,如果比符号栈顶的优先级低或者相同,就从符号栈里面取栈顶进行计算(从数字栈中取栈顶的2个数),计算完的结果还要再放入到数字栈中。
public class KuoHaoStack {
public static boolean isOk(String s){ //s表示的就是待匹配的括号串 [}使用字符来表示 时间复杂度 O(n)
MyStack<Character> brackets = new ArrayStack<Character>(20);
char c[] = s.toCharArray();
Character top;
for(char x : c){
switch (x) {
case '{':
case '(':
case '[':
brackets.push(x);//O(1)
break;
case '}':
top = brackets.pop();//O(1)
if(top == null) return false;
if(top == '{'){
break;
}else{
return false;
}
case ')':
top = brackets.pop();//O(1)
if(top == null) return false;
if(top == '('){
break;
}else{
return false;
}
case ']':
top = brackets.pop();//O(1)
if(top == null) return false;
if(top == '['){
break;
}else{
return false;
}
default:
break;
}
}
return brackets.isEmpty();
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()){
String s = scanner.next();
System.out.println("s的匹配结果:"+isOk(s));
}
}
}
总结
栈其实就是一个特殊的链表或者数组。既然栈也是一个线性表,那么我们肯定会想到数组和链表,而且栈还有这么多限制,那为什么我们还要使用这个数据结构呢?
不如直接使用数组和链表来的更直接么?数组和链表暴露太多的接口,实现上更灵活了,有些技术理解不到位的人员就可能出错。
所以在某些特定场景下最好是选择栈这个数据结构。
栈的分类
基于数组的栈——以数组为底层数据结构时,通常以数组头为栈底,数组头到数组尾为栈顶的生长方向
基于单链表的栈——以链表为底层的数据结构时,以链表头为栈顶,便于节点的插入与删除,压栈产生的新节点将一直出现在链表的头部
最大的区别就是扩容,链表天然支持动态扩容。但是可能会栈溢出。