前面讲到了如何用数组以及链表实现一个基本的堆栈和队列,这篇文章介绍如何实现一个可以在O(1)时间复杂度下得到最小元素的堆栈,以及用堆栈实现一个队列,用队列实现一个堆栈。
1,实现一个可以得到最小元素的堆栈, 要求pop(),push(),getMin()的时间复杂度都为O(1).
如果我们按照普通的思路,类中有两个成员变量,value和minValue,当pop一个元素后,我们就需要更新minValue, 从而要遍历堆栈里剩余的元素,时间复杂度为O(n),假设堆栈中有n个元素,因此这个方法不符合题意。
我们想到用每个元素都记录当前的最小元素,当push一个新的元素进来,这个新的元素连同最小元素都被记录在堆栈中,我们先不考虑pop,实现代码如下:
public class StackWithMin extends Stack<EleWithMin>{
public void push(int val) {
int min = Math.min(val, min());
super.push(new EleWithMin(val, min));
}
public int pop() {
/*
after we pop a element,
how can we update the min in
stack if this is the minimum value
*/
super.pop().value;
}
public int min(){
if(this.isEmpty()){
return Integer.MAX_VALUE;
} else {
return peek().min;
}
}
}
class EleWithMin {
public int value;
public int min;
public EleWithMin(int value, int min) {
this.value = value;
this.min = min;
}
}
他的确可以在O(1)的时间内得到最小元素,但是pop后,我们仍然需要更新最小值,时间复杂度大于O(n)。并且浪费空间,因为每个元素都要记录一个当前的最小元素。我们换另一种方法,用另外一个堆栈来记录最小元素。代码如下:
import java.util.Stack;
public class StackWithMin extends Stack<Integer> {
Stack<Integer> minStack;
public StackWithMin() {
minStack = new Stack<Integer>();
}
public void push(int val) {
super.push(val);
if(minStack.isEmpty() || minStack.peek() >= getMin()){
minStack.push(val);
}
}
public Integer pop(){
int value = super.pop();
if(value == getMin()){
minStack.pop();
}
return value;
}
public int getMin() {
if(minStack.isEmpty()) {
return Integer.MAX_VALUE;
} else {
return minStack.peek();
}
}
}
2,用队列实现一个堆栈
借用两个队列,实现堆栈后进先出的原理。代码如下:
import java.util.LinkedList;
import java.util.Queue;
public class MyStack {
Queue<Integer> q1 = new LinkedList<Integer>();
Queue<Integer> q2 = new LinkedList<Integer>();
public void push(int val) {
q1.offer(val);
}
public int pop() {
while(q1.size() > 1) q2.offer(q1.poll());
int result = q1.poll();
Queue<Integer> q = q1;
q1 = q2;
q2 = q1;
return result;
}
public int peek() {
while(q1.size() > 1) q2.offer(q1.poll());
int result = q1.poll();
q2.offer(result);
Queue<Integer> q = q1;
q1 = q2;
q2 = q;
return result;
}
public boolean isEmpty() {
if(q1.size() == 0) {
return true;
} else {
return false;
}
}
}
3,用堆栈实现队列
思路和上一题类似,这里用两个堆栈来实现队列先进先出的原理。代码如下:
import java.util.Stack;
public class MyQueue {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void offer(int val) {
stack1.push(val);
}
public int element() {
while(!stack1.isEmpty())
stack2.push(stack1.pop());
int result = stack2.pop(); //删除第一个元素
while(!stack2.isEmpty())
stack1.push(stack2.pop());
return result;
}
public int peek() {
while(!stack1.isEmpty())
stack2.push(stack1.pop());
int result = stack2.peek(); //不删除第一个的元素
while(!stack2.isEmpty())
stack1.push(stack2.pop());
return result;
}
public boolean empty() {
if(stack1.isEmpty())
return true;
return false;
}
}
分享到:
相关推荐
除了基本的栈和队列,还有一些变体,如带优先级的堆栈(Priority Stack)和循环队列(Circular Queue)。优先级栈允许根据元素的优先级决定何时弹出,常用于事件驱动系统;循环队列则解决了普通队列在满或空时的边界...
数据结构是计算机科学中的核心概念,它涉及到如何高效地组织和管理数据,以便于执行各种计算和操作。在本章中,我们将深入探讨其中的两...熟练掌握这些基本数据结构的原理和实现方式,对于提升编程能力有着重要的作用。
总结来说,堆栈和队列作为基本数据结构,在计算机科学和软件开发中有着广泛的应用,它们的实现和操作对理解算法和程序设计至关重要。通过学习和熟练掌握这些概念,可以有效地提高编程效率和代码质量。
另外,还有循环队列和双端队列等变体,分别提供更好的性能和灵活性。 “最小生成树”是图论中的一个经典问题,用于找到连接所有顶点的边的权重总和最小的子集,这在网络设计、成本计算等领域有广泛应用。Prim算法和...
栈和队列的变体,如堆栈和双端队列,也具有重要应用。 ### 第4—5章 串和数组 字符串是特殊的线性表,通常用于处理文本数据。数组则是固定大小的一维或多维数据集合,提供连续存储和快速访问,适合处理矩阵等结构。...
队列是一种基础且重要的数据...学习队列数据结构不仅可以帮助你理解和解决实际问题,也是进一步学习更复杂数据结构如堆栈、树、图等的基础。通过不断实践和应用,你将能够更好地掌握队列的精髓,提升自己的编程能力。
堆栈和队列的变体,如双端队列(deque)和优先级队列,提供了更灵活的操作选项。 动画演示通常会通过生动的例子展示这些数据结构的插入、删除、查找等操作过程,以及它们在实际问题中的应用。例如,它可能会通过...
实验可能包括栈和队列的实现,以及它们在实际问题中的应用。 4. **树结构**:二叉树是最常见的树形数据结构,包括二叉搜索树、完全二叉树、满二叉树和平衡二叉树。实验中可能需要实现基本的树操作,如查找、插入和...
6. **堆栈和队列的变体**:如双端队列(deque)允许在两端进行插入和删除,栈和队列的组合(如队列堆栈)提供灵活的操作。 数据结构的重要性在于它直接影响到算法的效率。选择合适的数据结构可以显著提升算法性能,...
9. **堆栈、队列和双端队列的变体**:除了基本的栈和队列,还有多种变体,如循环队列、堆栈队列(又称双端队列)等,它们提供了更灵活的操作。 《数据结构笔记》的作者可能会详细讨论这些数据结构的实现、特性以及...
堆栈和队列的变体,如双端队列(deque)和堆栈,也十分重要。deque允许在两端进行插入和删除操作,而堆栈允许在顶部进行操作的同时保持其LIFO属性。 图论中的数据结构,如最小生成树(Prim算法或Kruskal算法)、...
还有堆栈和队列的变体,如双端队列(deque)和优先级队列(Priority Queue),它们在算法设计中也有广泛应用。 在进行数据结构试验时,可能会涉及以下几个方面: 1. 实现基本数据结构:如编写链表、栈、队列、树和...
6. **特殊数据结构**:如哈希表、堆栈、队列的变体(如双端队列)、图的最小生成树(如Prim算法和Kruskal算法)等。 7. **动态规划和贪心策略**:在解决一些优化问题时,数据结构与动态规划和贪心策略相结合,能...
包括栈和队列的顺序存储和链式存储实现,以及它们在进制转换、括号匹配检测和迷宫求解中的应用。本章通过实际的例子展示了这些基本数据结构的强大应用。 第五章“递归”着重讲述了递归的概念、与堆栈的关系,以及...
堆栈和队列的变体,如双端队列和优先队列,进一步扩展了其功能。 散列表(哈希表)是一种通过哈希函数将键映射到数组索引的数据结构,提供了快速的查找、插入和删除操作。它的平均时间复杂度可以达到O(1),但在最坏...
6. **其他高级数据结构**:例如堆栈、队列的变体,如双端队列、优先队列;集合和映射结构,如字典和关联数组;图的搜索算法,如拓扑排序和最小生成树算法(Prim或Kruskal)。 严蔚敏数据结构习题集中的答案提供了对...
7. **堆栈和队列的变体**:如双端队列(deque)提供了在两端插入和删除的能力,循环队列解决了队列满或空的问题。 8. **动态数组**:如C++中的`std::vector`,在内存不足时自动扩展,同时提供了数组的功能。 在...
接下来是高级数据结构,如堆、队列和优先队列、堆栈、队列的变体(如双端队列)、图的遍历算法(如深度优先搜索和广度优先搜索)。这些数据结构在解决实际问题中有着广泛的应用,如任务调度、网络路由等。 此外,...
第九章和第十章可能涉及到高级数据结构,如堆、栈、队列的变体(如堆栈、堆队列),以及特殊用途的数据结构,如二叉索引树(B树)、红黑树等。这部分习题可能会设计复杂的数据结构操作,要求你理解它们的平衡性质和...
读者还会接触到一些高级数据结构,如堆栈、队列的变体(如堆栈队列、循环队列),树的遍历(前序、中序、后序),树的平衡(如AVL树、红黑树),图的遍历和最短路径算法(如Dijkstra算法、Floyd算法),以及动态规划...