看了LinkedList的源码,明白了LinkedList底层使用的是双向链表,一直想找个机会实现一下双向链表,今天写到力扣的每日一题20.有效的括号,正好此题需要使用到栈,所以借此机会来自己实现一下基于双向链表实现的栈,实现栈之前要了解以下知识
1.什么是双向链表
双向链表是指一个节点有一个数据域,两个指针域,一个指针域指向上一个节点,一个指针域指向下一个节点,现在将指向上一个节点的指针域命名为pre,将指向下一个节点的指针域命名为next,节点命名为node,一个合格的双向链表如下图所示
中间的node可以是多个,为了方便只画了一个
2.什么是栈
栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
在我实现的栈中,定义push()方法为向栈顶中加入一个元素,pop()方法为删除栈顶元素,top()方法为得到栈顶元素,isEmpty()为判断栈是否为空
3.实现基于双向链表的栈的步骤
根据上面的图片
-
第一步
首先需要创建一个Node类,里面有参数data,和两个Node pre和next -
第二步
创建双向链表类了,很显然双向链表中有两个属性,first和last用来保存头节点和尾节点 -
第三步
push()方法,向尾部添加一个元素如何实现,先用一张图来假设我们新加入的节点和last节点的关系
初始时,两个节点没有任何关系,只需参考合格的双向链表那张图片连线就好
第一步可以将last的next指针域指向node
显然,第二步为将node的pre指针域指向last
最后,不要忘记更新last的位置
- 第四步
pop()方法的实现,删除尾部元素,这个操作
明显一句话就能实现,last=last.pre
top和isEmpty方法也是很容易,直接在代码中解释
4.基于双向链表实现的栈代码
Node类
class Node<E> {
public E data;
public Node<E> next;
public Node<E> pre;
public Node(E data, Node<E> next, Node<E> pre) {
super();
this.data = data;
this.next = next;
this.pre = pre;
}
}
Link类
class Link<E> {
Node<E> first, last;
/**
* 向栈的尾部添加节点,数据域为data
*
* @param data
*/
public void push(E data) {
if (first == null) {// 如果栈为空,直接赋值
first = last = new Node<E>(data, null, null);
} else {
Node<E> node = new Node<E>(data, null, last);// 将node的pre域指向last
last.next = node;// last的next域指向node
last = node;// 更新last
}
}
/**
* 删除尾部节点
*
* @return 删除的节点的数据域的值
*/
public E pop() {
E data;
if (last == first) {// 如果last和first都指向同一个元素,显然栈中只有一个元素了,直接赋值为空
data = last.data;
last = first = null;
} else {
data = last.data;
last = last.pre;// last向前移动一位
last.next = null;
}
return data;
}
/**
* 得到栈顶元素,也就是尾巴的数据域
*
* @return 数据域的值
*/
public E top() {
return last.data;
}
/**
* 判断栈是的为空
*
* @return true表示为空,false表示不为空
*/
public boolean isEmpty() {
return first == null;
}
}
5.力扣题目的解答
只要左括号进栈,右括号判断栈顶左括号是否与之匹配就好,其他情况全部返回false,最后判断栈是否为空,为空证明匹配,否则不匹配
public boolean isValid(String s) {
if (s == null) {
return true;
}
if (s.length() == 0) {
return true;
}
Link<Character> stack = new Link<Character>();
int len = s.length();
for (int i = 0; i < len; i++) {
char ch = s.charAt(i);
if (ch == '(' || ch == '[' || ch == '{') {
stack.push(ch);
} else {
if (stack.isEmpty()) {
return false;
}
char top = stack.top();
if (top == '(' && ch == ')') {
stack.pop();
} else if (top == '[' && ch == ']') {
stack.pop();
} else if (top == '{' && ch == '}') {
stack.pop();
} else {
return false;
}
}
}
return stack.isEmpty();
}