一、队列
1.1 栈的性质
- 先进先出
1.2 优先级队列(堆结构)
1.3 双端队列
双端队列的首部和尾部都可以亚压入元素
1.4 宽度优先遍历
二、栈
2.1 栈的性质
- 先进后出
- 栈的基本操作都是o(1)的操作
2.2 栈的基本操作
- pop操作
- top或者peek操作
- push操作
- size操作
2.3 深度度优先遍历(DFS)
三、案例
3.1 实现一个特殊的栈,在基本栈的功能上,再实现返回栈中最小元素的操作getMin
-
要求:pop,push,getMin的时间复杂度都是o(1)
-
思路:
两个栈:一个保存数据,一个保存当前栈中的最小值
public class statck {
public static void main(String[] args) {
int[] array = new int[]{4,3,4,2,5,3};
stackTest(array);
}
public static void stackTest(int[] array){
Stack<Integer> data = new Stack<Integer>();
Stack<Integer> Min = new Stack<Integer>();
for (int i = 0; i < array.length; i++) {
if(Min.isEmpty() && data.isEmpty()){
Min.push(array[i]);
data.push(array[i]);
}else {
if(array[i] > Min.peek()){
Min.push(Min.peek());
}else {
Min.push(array[i]);
}
data.push(array[i]);
}
}
System.out.println("每一步栈的最小值:");
while (!Min.isEmpty()){
System.out.print(Min.pop() + " ");
}
System.out.println();
System.out.println("data栈:");
while (!data.isEmpty()){
System.out.print(data.pop() + " ");
}
}
}
3.2 两个栈模拟队列,支持队列的基本操作
注意:
- 数据要一次性的从statck1倒到statck2,其间不允许新的数据加入模拟的队列,不然会出错。
public class statck {
static Stack<Object> objects1 = new Stack<>();
static Stack<Object> objects2 = new Stack<>();
public static void main(String[] args) {
int[] array = new int[]{4,3,4,2,5,3};
add(array);
pop(array);
peek(array);
pop(array);
}
public static void add(int[] array){
for (int i = 0; i < array.length; i++) {
objects1.push(array[i]);
}
for (int i = 0; i < array.length; i++) {
objects2.push(objects1.pop());
}
}
public static void pop(int[] array){
System.out.print("模拟元素出队列:" + " ");
if(!objects2.isEmpty()){
System.out.print(objects2.pop() + " ");
}
}
public static void peek(int[] array){
System.out.println();
if(!objects2.isEmpty()){
System.out.print("栈顶元素是: " + objects2.peek() + " ");
}
System.out.println();
}
}
3.3 实现栈的逆序,但是只能用递归函数和这个栈的本身的操作来实现,而不能自己申请另外的数据结构。
- 思路:
- 递归取出栈底的元素,然后入栈。使用递归实现。
public class statck {
public static void main(String[] args) {
Stack stack = new Stack();
stack.push(3);
stack.push(2);
stack.push(1);
reserve(stack);
while (!stack.isEmpty()){
System.out.print(stack.pop() + " ");
}
}
//取栈底的值
public static int getBottom(Stack<Integer> stack) {
Integer pop = stack.pop();
if(stack.isEmpty()){
return pop;
}else {
int bottom = getBottom(stack);
stack.push(pop);
return bottom;
}
}
//逆序栈
public static void reserve(Stack<Integer> stack){
if(stack.isEmpty()){
return;
}else{
int bottom = getBottom(stack);
reserve(stack);
stack.push(bottom);
}
}
}
3.4 将栈中的元素按照从大到小排序,只允许额外申请一个栈
注意点:
- 第二个栈为空时要跳出循环
- 每步从栈2拿出来的元素记得放回栈1或者栈2
public class statck {
public static void main(String[] args) {
Stack stack = new Stack();
stack.push(3);
stack.push(2);
stack.push(6);
stack.push(1);
stack.push(4);
compare(stack);
}
public static void compare(Stack<Integer> integers1){
int mid = 0;
Stack<Integer> integers2 = new Stack<>();
if(!integers1.isEmpty()){
integers2.push(integers1.pop());
}
while (!integers1.isEmpty() && integers2.size() >= 0){
Integer pop1 = integers1.pop();
mid = pop1;
Integer pop2 = integers2.pop();
int count = 0;
while (mid > pop2){
integers1.push(pop2);
if(integers2.isEmpty()){
break;
}
if(!integers2.isEmpty()) {
pop2 = integers2.pop();
}
count ++;
}
if(mid <= pop2) {
integers2.push(pop2);
}
integers2.push(mid);
for (int i = 0; i < count; i++) {
integers2.push(integers1.pop());
}
}
while (!integers2.isEmpty()){
integers1.push(integers2.pop());
}
while (!integers1.isEmpty()){
System.out.print(integers1.pop() + " ");
}
}
//取栈底的值
}
3.5 有一个整形数组arr和一个大小为w的窗口从数组的最左边滑到最右边,窗口每次向右边滑一个位置,返回一个长度为n-w+1的数据res,res[i]表示每一种窗口下的最大值。
最优解可以做到时间复杂度为:o(N)
思路:
- 使用双端队列
- 初始化
- 0放到双端队列中
- 依次从数组中取一个数进入双端队列中,从双端队列的最顶端的数依次比较,>比顶端的数所对应的数组元素大,移除顶端的数,再取顶端的数比较,直到小于等于顶端的数,将该数的下标添加进去。
- 一直重复步骤2,直到数组的小标到达w-1。
思路:
初始化完成之后:
- 滑动窗口,判断顶端的数据是否符合所在的窗口范围,在,保留顶端数据,不在,移除顶端数据,像初始化那添加数据,把最顶端的数据保留在一个score数组,该数据记录每次窗口的最大值。
- 重复上一步骤,直到窗口滑动结束。
public class DQueueTest {
public static void main(String[] args) {
int[] ints = new int[]{1,2,3,4,5,6,7,8,9};
getMax(ints, 3);
}
//初始化双端队列,双端队列中存储的是元素的下标,新来的数把比他小的数全踢出去,后来的小的数保留
public static Deque getInitialMax(int[] array, int length) {
Deque dQueue = new LinkedList();
if (length > array.length) {
return null;
}
dQueue.push(0);
int i = 1;
while (i < length) {
if (!dQueue.isEmpty() && array[i] >= array[(int) dQueue.peekFirst()]) {
dQueue.pop();
} else {
dQueue.push(i);
i++;
}
}
Iterator iterator = dQueue.iterator();
System.out.println();
return dQueue;
}
public static void getMax(int[] array, int length){
Deque initialMax = getInitialMax(array, length);
int[] score = new int[array.length - length + 1];
int key = 1;
score[0] = array[(int)initialMax.peekLast()];
int start = length;
while (start < array.length){
//先判断头部的数有效没
if(!initialMax.isEmpty() && (int)initialMax.peekLast() >= start-length + 1){
}else {
initialMax.removeLast();
}
//接着将数据放到合适的位置
while (!initialMax.isEmpty() && array[start] >= (int)initialMax.peekFirst()){
initialMax.removeFirst();
}
initialMax.push(array[start]);
score[key++] = (int)initialMax.peekLast();
start ++ ;
}
for (int i = 0; i < score.length; i++) {
System.out.print(score[i] + " ");
}
}
}
3.6 给定一个没有重复元素的数组arr,写出生成这个数组的MaxTree的函数,要求如果数组长度为N,则时间复杂度为o(N),额外空间复杂度为o(N)。* *
- MaxTree是一颗二叉树,数组的每一个值对应一个二叉树节点。
- 包括MaxTree树在内且在其中的每一颗子树上,值最大的节点都是树的头。
思路:
对于数组中的每一个元素,找左边比他大的第一个元素,再找右边比他大的第一个元素,两个元素中最小的数作为其父节点即可。
public class BuileTree {
public static void main(String[] args) {
Node[] node = new Node[7];
node[0] = new Node("8");
node[1] = new Node("4");
node[2] = new Node("3");
node[3] = new Node("5");
node[4] = new Node("7");
node[5] = new Node("9");
node[6] = new Node("2");
Node[] lnode = new Node[7];
Node[] rnode = new Node[7];
Deque deque = new LinkedList<>();
deque.push(node[0]);
for (int i = 1; i < node.length; i++) {
while (!deque.isEmpty() && Integer.parseInt(node[i].getValue()) > Integer.parseInt(((Node)deque.peekFirst()).getValue())){
deque.pollFirst();
}
if(deque.isEmpty()){
}else {
lnode[i] = (Node)deque.peekFirst();
}
deque.push(node[i]);
}
Deque deque1 = new LinkedList<>();
for (int i = node.length - 1; i >= 0; i--) {
while (!deque1.isEmpty() && Integer.parseInt(node[i].getValue()) > Integer.parseInt(((Node)deque1.peekFirst()).getValue())){
deque1.pollFirst();
}
if(deque1.isEmpty()){
}else {
rnode[i] = (Node)deque1.peekFirst();
}
deque1.push(node[i]);
}
for (int i = 0; i < node.length; i++) {
if (lnode[i] == null && rnode[i] != null) {
if (rnode[i].getlNode() == null) {
rnode[i].setlNode(node[i]);
} else {
rnode[i].setrNode(node[i]);
}
}
else if (rnode[i] == null && lnode[i] != null) {
if (lnode[i].getlNode() == null) {
lnode[i].setlNode(node[i]);
} else {
lnode[i].setrNode(node[i]);
}
}
else if(rnode[i] == null && lnode[i] == null){}
else if(lnode[i] != null && rnode[i] != null){
if (Integer.parseInt(lnode[i].getValue()) > Integer.parseInt(rnode[i].getValue())) {
if (rnode[i].getlNode() == null) {
rnode[i].setlNode(node[i]);
} else {
rnode[i].setrNode(node[i]);
}
} else {
if (lnode[i].getlNode() == null) {
lnode[i].setlNode(node[i]);
} else {
lnode[i].setrNode(node[i]);
}
}
}
}
Node node1 = (Node) deque.pollLast();
sortNode(node1);
}
public static void sortNode(Node node){
if(node != null){
System.out.print(node.getValue() + " ");
}
if(node.getlNode() != null){
sortNode(node.getlNode());
}
if(node.getrNode() != null){
sortNode(node.getrNode());
}
}
}