8.栈的最大值问题
问题的描述和思路可以参考这里
Java实现代码如下:
import java.util.Stack;
/**
* 栈的最大值问题 Title: Description: Company:
*
* @author 郑伟
* @date 2018年4月12日下午8:57:29
*/
public class SpecialStack {
Stack<Integer> stack = new Stack<>();
Stack<Integer> maxStack = new Stack<>();
public void push(Integer num) {
if (stack.isEmpty()) {
maxStack.push(num);
stack.push(num - maxStack.peek());
} else {
stack.push(num - maxStack.peek());
if (num > maxStack.peek()) {
maxStack.pop();
maxStack.push(num);
}
}
}
public int pop() {
if (!stack.isEmpty()) {
if (stack.peek() >= 0 && !maxStack.isEmpty()) {
int result = maxStack.pop();
maxStack.push(result - stack.pop());
return result;
} else if (stack.peek() < 0 && !maxStack.isEmpty()) {
return (maxStack.peek() + stack.pop());
} else {
return -1;
}
} else {
return -1;
}
}
public int max() {
if (stack.isEmpty()) {
return 0;
}
if (maxStack.isEmpty())
return -1;
return maxStack.peek();
}
public static void main(String[] args) {
int arr[] = { 5, 4, 1, 2, 3, 10, 9, 8, 6, 7, 15 };
SpecialStack specialStack = new SpecialStack();
for (int i = 0; i < arr.length; i++) {
specialStack.push(arr[i]);
System.out.print("入栈:" + arr[i]);
System.out.println("最大值:" + specialStack.max());
}
for (int i = 0; i < arr.length; i++) {
System.out.print("出栈:" + specialStack.pop());
System.out.println("最大值:" + specialStack.max());
}
}
}
9.非递归实现二叉树的遍历
前序遍历:
对于树中的任意一个节点cur:
(1)访问cur,并将节点入栈;
(2)判断节点cur的左孩子是否为空。若不为空,则将cur的左孩子cur.left置为当前的结点cur;
(3)若为空,则取栈顶节点并进行出栈操作(根据出栈节点去找该节点的右孩子),并将栈顶结点的右孩子cur.right置为当前的结点cur,循环至1);
中序遍历:
对于树中的任意节点cur:
(1)若cur的左孩子不为空,将p压栈,并将cur的左子树置为当前节点cur,然后对当前节点重复操作。
(2)若cur的左孩子为空,将栈顶元素出栈并进行访问,把当前节点置为cur的右孩子。
(3)直到栈为空且cur为空
后序遍历:
对于树中的任意节点cur
(1) 如果该节点没有左孩子和右孩子可以直接访问该节点;
如果其左孩子和右孩子被访问过了,可以直接访问该节点;
(2)如果不是情况(1),那么就先将右孩子压栈,再将左孩子压栈,这样出栈顺序就是先出左孩子再出右孩子。
import java.util.Stack;
/**
* 非递归的树的遍历 Title: Description: Company:
*
* @author 郑伟
* @date 2018年4月13日下午3:37:12
*/
public class Print_Tree {
// 先序遍历非递归
// 如果发现右儿子没有了,那么出栈,指向cur,如果cur右儿子有那么久打印右儿子,把右儿子入栈,如果没有右儿子,那么久继续出栈,出栈的节点设为cur
public static void preOrder(TreeNode pNode) {
Stack<TreeNode> stack = new Stack<>();
while (pNode != null || !stack.isEmpty()) {
while (pNode != null) {
// 先打印当前节点
System.out.print(pNode.val+" ");// 若节点不为空先访问再压栈
stack.push(pNode);// 当前节点入栈
pNode = pNode.left;// 将当前节点置为p的左孩子,若不为空继续访问并压栈
}
// 当p为空时,说明根节点和左孩子打印遍历完毕了,接下来出栈遍历右孩子
if (!stack.isEmpty()) {// 左子树不存在,那么就是讲栈顶弹出,作为当前 节点
pNode = stack.pop();
// 讲当前节点设置为右边的节点
pNode = pNode.right;
}
}
}
// 中序遍历非递归
// 就只如果節點有左子树就不停的入栈,直到左边没有左子树,然后出栈,打印当前值,然后cur指向右节点。
public static void InOrder(TreeNode pNode) {
Stack<TreeNode> stack = new Stack<TreeNode>();
while (pNode != null || !stack.isEmpty()) {
// 不停的把左子樹入棧
while (pNode != null) {
stack.push(pNode);
pNode = pNode.left;
}
// 当左子树没有的时候,也就是如到底部了
if (stack != null) {
pNode = stack.pop();// 弹出一个节点
System.out.print(pNode.val+" ");
pNode = pNode.right;// 开始答应右边的节点
}
}
}
// 后续遍历
// 先右子树压栈,再左子树压栈
public static void PostOrder(TreeNode pNode) {
if (pNode == null)
return;
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode preNode = null;
TreeNode curNode;
stack.push(pNode);// 根节点先入栈
while (!stack.isEmpty()) {
curNode = stack.peek();
// 如果当前节点的左右子节点都为null,那么就直接答应当前节点;
// 当前一个节点不为空并且是当前节点的左孩子或者右孩子,当是左孩子时说明当前节点右孩子为空,
// 当是右孩子时,说明左右孩子都访问过了,且都不为空
if (curNode.left == null
&& curNode.right == null
|| (preNode != null && (preNode == curNode.left || preNode == curNode.right))) {
System.out.print(curNode.val+" ");// 访问当前节点
preNode = curNode;
// curNode指向栈顶,由于打印过了,就直接出栈
stack.pop();
} else {
// 当前节点为栈顶元素 如果当前节点不是叶子节点,在当前节点之前访问的那个节点不是当前节点的孩子,则进行压栈
// 先压栈右节点再压栈左节点 这样出栈时是先左后右
if (curNode.right != null)
stack.push(curNode.right);
if (curNode.left != null)
stack.push(curNode.left);
}
}
}
public TreeNode buildTree(int[] nums, int i) {
if (i >= nums.length)
return null;
TreeNode root = new TreeNode(nums[i]);
root.left = buildTree(nums, i * 2 + 1);
root.right = buildTree(nums, i * 2 + 2);
return root;
}
public static void main(String[] args) {
Print_Tree pTree = new Print_Tree();
int[] nums = {1,2,3,4,5,6};
TreeNode buildTree = pTree.buildTree(nums, 0);
System.out.println("前序遍历");
Print_Tree.preOrder(buildTree);
System.out.println();
System.out.println("中遍历");
Print_Tree.InOrder(buildTree);
System.out.println();
System.out.println("后序遍历");
Print_Tree.PostOrder(buildTree);
}
}
/**
*前序遍历
*1 2 4 5 3 6
*中遍历
*4 2 5 1 6 3
*后序遍历
*4 5 2 6 3 1
*/