链式栈就是基于单链表的栈
单链表的代码
主类和[单链表反转(JAVA)]一致(https://blog.youkuaiyun.com/cedarjo/article/details/88421448)
这里把代码再放一边,主要区别是把node
单列出来,以及在单链表主类中加入了从头从尾的增删节点代码
SinglyLinkedNode
public class SinglyLinkedNode<T> {
private T data;
private SinglyLinkedNode<T> next;
public SinglyLinkedNode(T data) {
this.data = data;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public SinglyLinkedNode<T> getNext() {
return next;
}
public void setNext(SinglyLinkedNode<T> next) {
this.next = next;
}
@Override
public String toString() {
return "current : " + data;
}
}
SinglyLinkedList
public class SinglyLinkedList<T> {
private SinglyLinkedNode<T> header;
private int size;
public SinglyLinkedNode<T> getHeader() {
return header;
}
public int getSize() {
return size;
}
/**
* 从尾加元素
* @param element
* @return
*/
public SinglyLinkedNode<T> addToTail(T element) {
SinglyLinkedNode<T> newNode = new SinglyLinkedNode<>(element);
if (this.header == null) {
this.header = newNode;
} else {
SinglyLinkedNode<T> current = this.header;
while (current.getNext() != null) {
current = current.getNext();
}
current.setNext(newNode);
}
this.size++;
return newNode;
}
/**
* 从尾删元素
* @return
*/
public SinglyLinkedNode<T> dropFromTail() {
if (this.header == null) {
System.out.println("empty linkedList");
return null;
}
if (this.header.getNext() == null) {
System.out.println("single element linkedList");
SinglyLinkedNode<T> temp = this.header;
this.header = null;
this.size--;
return temp;
}
SinglyLinkedNode<T> current = this.header;
while (current.getNext().getNext() != null) {
current = current.getNext();
}
SinglyLinkedNode<T> temp = current.getNext();
current.setNext(null);
this.size--;
return temp;
}
/**
* 从头加元素
* @param element
* @return
*/
public SinglyLinkedNode<T> addToHeader(T element) {
SinglyLinkedNode<T> newNode = new SinglyLinkedNode<>(element);
if (this.header == null) {
this.header = newNode;
} else {
newNode.setNext(this.header);
this.header = newNode;
}
this.size++;
return newNode;
}
/**
* 从头删元素
* @return
*/
public SinglyLinkedNode<T> dropFromHeader() {
if (this.header == null) {
System.out.println("empty linkedList");
return null;
}
SinglyLinkedNode<T> temp = this.header;
this.header = this.header.getNext();
this.size--;
return temp;
}
@Override
public String toString() {
SinglyLinkedNode<T> current = this.header;
StringBuilder stringBuilder = new StringBuilder("linkedList[");
while (current != null) {
stringBuilder.append(current.getData()).append(", ");
current = current.getNext();
}
stringBuilder.append("]");
return stringBuilder.toString();
}
}
单链表实现栈的思路
单链表中,因为链表方向,具体实现时有两种选择,一种是链表头在栈底(下图左侧),一种是链表头在栈顶(下图右侧)。
因为在链表中更方便操作header
节点,而入栈出栈都要操作栈顶元素,所以实现中更倾向于使用下图中右侧的方式,即链表头在栈顶
单链表的header
在栈顶,其tail
在栈底,入栈就是加入新的header
,出栈就是将header
替换为header.getNext()
链式栈的代码
public class LinkedStack<T> {
private SinglyLinkedList<T> linkedList;
private static final int MAX_SIZE = 10;
public LinkedStack() {
this.linkedList = new SinglyLinkedList<>();
}
public boolean push(T element) {
if (linkedList.getSize() == MAX_SIZE) {
System.out.println("stack is full");
return false;
}
linkedList.addToHeader(element);
return true;
}
public T pop() {
if (linkedList.getSize() == 0) {
System.out.println("stack is empty");
return null;
}
SinglyLinkedNode<T> dropNode = linkedList.dropFromHeader();
return dropNode == null ? null : dropNode.getData();
}
@Override
public String toString() {
return linkedList.toString();
}
public static void main(String[] args) {
LinkedStack<String> stack = new LinkedStack<>();
System.out.println(stack);
stack.push("A");
System.out.println(stack);
stack.push("B");
System.out.println(stack);
stack.push("A");
System.out.println(stack);
stack.push("B");
System.out.println(stack);
stack.push("A");
System.out.println(stack);
stack.push("B");
System.out.println(stack);
stack.push("A");
System.out.println(stack);
stack.push("B");
System.out.println(stack);
stack.push("A");
System.out.println(stack);
stack.push("B");
System.out.println(stack);
stack.push("A");
System.out.println(stack);
stack.push("B");
System.out.println(stack);
stack.pop();
System.out.println(stack);
stack.pop();
System.out.println(stack);
stack.pop();
System.out.println(stack);
stack.pop();
System.out.println(stack);
stack.push("C");
System.out.println(stack);
stack.push("C");
System.out.println(stack);
}
}
注意:入栈和出栈的实现中,要么都使用从头增删,要么都使用从尾增删
但如果使用从尾增删(上图中的左侧),因为单链表未保存tail
节点,每次操作都要遍历整个链表,时间复杂度为O(n)
;而如果使用从头增删(上图中的右侧),因为很方便拿到header
节点,时间复杂度为O(1)
。
执行结果
linkedList[]
linkedList[A, ]
linkedList[B, A, ]
linkedList[A, B, A, ]
linkedList[B, A, B, A, ]
linkedList[A, B, A, B, A, ]
linkedList[B, A, B, A, B, A, ]
linkedList[A, B, A, B, A, B, A, ]
linkedList[B, A, B, A, B, A, B, A, ]
linkedList[A, B, A, B, A, B, A, B, A, ]
linkedList[B, A, B, A, B, A, B, A, B, A, ]
stack is full
linkedList[B, A, B, A, B, A, B, A, B, A, ]
stack is full
linkedList[B, A, B, A, B, A, B, A, B, A, ]
linkedList[A, B, A, B, A, B, A, B, A, ]
linkedList[B, A, B, A, B, A, B, A, ]
linkedList[A, B, A, B, A, B, A, ]
linkedList[B, A, B, A, B, A, ]
linkedList[C, B, A, B, A, B, A, ]
linkedList[C, C, B, A, B, A, B, A, ]
如果在单链表中加入tail
字段,tail
为栈顶的方式是否可取
对应上图中左侧
入栈操作时
this.tail.setNext(newNode);
this.tail = newNode;
时间复杂度为O(1)
出栈操作时,由于无法快速获取到tail
的上一个节点,仍需从header
开始向后获取,时间复杂度依然是O(n)
综合来看,不可取