文章目录
栈的定义
栈是一种先进后出的数据结构。它的操作受限。
栈,是一种先进后出,或者后进先出的数据结构。跟数组和链表相比,有一定的限制性。毕竟,它也有自己的适用场景,比如:函数调用,表达式求值等等。栈有2个操作,入栈,出栈。时间复杂度都是O(1)。
实现一个栈
实现一个栈:怎么实现呢,有2种方式,用数组实现或者用链表实现。用数组实现的叫做顺序栈,用链表实现的叫做链式栈。
用数组实现栈
先用数组实现,不考虑扩容的情况,代码如下:
python
class Stack:
def __init__(self):
self.stack = []
# 入栈操作
def push(self, item):
self.stack.append(item)
# 出栈操作
def pop(self):
if not self.is_empty():
return self.stack.pop()
else:
return None
# 查看栈顶元素
def peek(self):
if not self.is_empty():
return self.stack[-1]
else:
return None
# 判断栈是否为空
def is_empty(self):
return len(self.stack) == 0
# 获取栈的大小
def size(self):
return len(self.stack)
这是python的实现方式。可以再看下java的实现方式,如下图:
java
public class Stack {
private int[] elements;
private int top;
private int capacity;
// 初始化栈,设置初始容量
public Stack(int capacity) {
this.capacity = capacity;
elements = new int[capacity];
top = -1; // 初始时栈顶为-1,表示栈为空
}
// 入栈操作
public void push(int item) {
if (!isFull()) {
top++;
elements[top] = item;
} else {
System.out.println("栈已满,无法添加元素");
}
}
// 出栈操作
public int pop() {
if (!isEmpty()) {
return elements[top--];
} else {
System.out.println("栈为空,无法删除元素");
return -1; // 或者可以抛出一个异常
}
}
// 查看栈顶元素
public int peek() {
if (!isEmpty()) {
return elements[top];
} else {
System.out.println("栈为空,没有元素可查看");
return -1; // 或者可以抛出一个异常
}
}
// 检查栈是否为空
public boolean isEmpty() {
return top == -1;
}
// 检查栈是否已满
private boolean isFull() {
return top == capacity - 1;
}
// 获取栈的大小
public int size() {
return top + 1;
}
// 展示栈的内容(可选)
public void displayStack() {
if (isEmpty()) {
System.out.println("栈为空");
} else {
for (int i = top; i >= 0; i--) {
System.out.print(elements[i] + " ");
}
System.out.println();
}
}
// 主函数,用于测试栈的实现
public static void main(String[] args) {
Stack stack = new Stack(5); // 创建一个容量为5的栈
stack.push(1);
stack.push(2);
stack.push(3);
stack.displayStack(); // 显示栈的内容
System.out.println("栈顶元素: " + stack.peek());
stack.pop();
stack.pop();
stack.displayStack(); // 再次显示栈的内容
System.out.println("栈的大小: " + stack.size());
System.out.println("栈是否为空: " + stack.isEmpty());
}
}
用链表实现栈
用数组实现完了,再用链表实现,如下图:
python
class Node:
def __init__(self, data=None):
self.data = data
self.next = None
class Stack:
def __init__(self):
self.top = None
# 入栈操作
def push(self, data):
if self.top is None:
self.top = Node(data)
else:
new_node = Node(data)
new_node.next = self.top
self.top = new_node
# 出栈操作
def pop(self):
if self.top is None:
return None
else:
popped = self.top.data
self.top = self.top.next
return popped
# 查看栈顶元素
def peek(self):
return self.top.data if self.top else None
# 判断栈是否为空
def is_empty(self):
return self.top is None
# 测试代码
s = Stack()
s.push(1)
s.push(2)
s.push(3)
print(s.pop()) # 输出:3
print(s.peek()) # 输出:2
print(s.is_empty()) # 输出:False
java的实现方式,如下图:
java
public class Node<T> {
private T data;
private Node<T> next;
public Node(T data) {
this.data = data;
this.next = null;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Node<T> getNext() {
return next;
}
public void setNext(Node<T> next) {
this.next = next;
}
}
public class LinkedListStack<T> {
private Node<T> top;
public LinkedListStack() {
this.top = null;
}
// 入栈操作
public void push(T data) {
Node<T> newNode = new Node<>(data);
newNode.setNext(top);
top = newNode;
}
// 出栈操作
public T pop() {
if (isEmpty()) {
throw new IllegalStateException("Stack is empty");
}
T data = top.getData();
top = top.getNext();
return data;
}
// 查看栈顶元素
public T peek() {
if (isEmpty()) {
throw new IllegalStateException("Stack is empty");
}
return top.getData();
}
// 判断栈是否为空
public boolean isEmpty() {
return top == null;
}
// 获取栈的大小
public int size() {
int size = 0;
Node<T> current = top;
while (current != null) {
size++;
current = current.getNext();
}
return size;
}
// 测试代码
public static void main(String[] args) {
LinkedListStack<Integer> stack = new LinkedListStack<>();
stack.push(200);
stack.push(300);
stack.push(600);
System.out.println(stack.pop());
System.out.println(stack.peek());
System.out.println(stack.isEmpty());
System.out.println(stack.size());
}
}
好了,实现方式就是这样的。再来看看动态扩容的栈是怎么实现的。
支持动态扩容的栈
这个跟普通的栈有一个不同的地方,在入栈的时候栈满了会进行扩容,然后复制之前的数据,再进行入栈操作。用java实现,如下图:
java
public class DynamicArrayStack<T> {
private static final int DEFAULT_CAPACITY = 10;
private static final int RESIZE_FACTOR = 2;
private Object[] elements;
private int top;
public DynamicArrayStack() {
elements = new Object[DEFAULT_CAPACITY];
top = -1;
}
// 入栈操作
public void push(T item) {
ensureCapacity();
elements[++top] = item;
}
// 出栈操作
public T pop() {
if (isEmpty()) {
throw new EmptyStackException();
}
return (T) elements[top--];
}
// 查看栈顶元素
public T peek() {
if (isEmpty()) {
throw new EmptyStackException();
}
return (T) elements[top];
}
// 判断栈是否为空
public boolean isEmpty() {
return top == -1;
}
// 获取栈的大小
public int size() {
return top + 1;
}
// 确保数组有足够的容量
private void ensureCapacity() {
if (top == elements.length - 1) {
resize();
}
}
// 调整数组大小
private void resize() {
int newSize = elements.length * RESIZE_FACTOR;
elements = Arrays.copyOf(elements, newSize);
}
// 测试代码
public static void main(String[] args) {
DynamicArrayStack<Integer> stack = new DynamicArrayStack<>();
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println(stack.pop()); // 输出:3
System.out.println(stack.peek()); // 输出:2
System.out.println(stack.size()); // 输出:2
System.out.println(stack.isEmpty()); // 输出:false
}
}
栈的应用
栈应用非常多,比如,在浏览器里有个向前,向后的箭头,就可以用2个栈来存储;函数的调用,也是可以用栈的。例子就不多举了。
小结
这篇文章讲述了栈的数据结构。
主要是讲解了栈的数据结构,以及实现,目的是了解底层的数据结构及应用,还有动态扩容的栈,栈的时间复杂度,空间复杂度都是O(1)。基本上就这么多。至于实现,用什么语言不重要,原理懂了,写一个,应该都不是什么难事。