非递归遍历:
先根遍历
public void StackPreOrder(Node head)
{
Console.WriteLine("Pre-Order: ");
if (head !=null)
{
Stack<Node> stack = new Stack<Node>();
stack.Push(head);
while (stack.Count>0)
{
head = stack.Pop();
Console.WriteLine(head.Data+" ");
//压入栈顶 先进后出 (大的先进)
if (head.Right!=null)
{
stack.Push(head.Right);
}
if (head.Left !=null)
{
stack.Push(head.Left);
}
}
}
}
关键点:
1.栈顶先插入Root节点,随即将其Pop()。
2.大的先进,二元查找树右边最大,所以 Right先进栈,Left后进。
3.循环开始先置换Head节点,同时Pop栈顶元素。
中序遍历
public void StackInOrder(Node head)
{
Console.WriteLine("In-Order: ");
if (head != null)
{
Stack<Node> stack = new Stack<Node>();
while (stack.Count > 0 || head != null)
{
//先进后出 (从左往右 从小到大)
if (head != null)
{
stack.Push(head);
head = head.Left;
}
else
{
head = stack.Pop();
Console.WriteLine(head.Data + " ");
head = head.Right;
}
}
}
}
关键点:
1.每次操作前head指向当前操作节点。
2.head不为空,进栈。
3.直至索引到左子树为null,head==null,Pop()栈顶,head置为当前节点右子树,继续循环判定head。
*head不为空进栈,置换为下一左子树。继续循环判定。
*head为空出栈,置换为下一右子树。继续循环判定。
后根遍历
双栈遍历
public void DoubleStackPostOrder(Node head)
{
Console.WriteLine("POST-Order: ");
if (head != null)
{
//双栈实现 非迭代遍历 排序栈 输出栈
Stack<Node> orderStack = new Stack<Node>();
Stack<Node> outputStack = new Stack<Node>();
orderStack.Push(head);
while (orderStack.Count>0)
{
head = orderStack.Pop();
outputStack.Push(head);
if (head.Left !=null)
{
orderStack.Push(head.Left);
}
if(head.Right !=null)
{
orderStack.Push(head.Right);
}
}
while (outputStack.Count > 0)
{
Console.WriteLine(outputStack.Pop().Data + " ");
}
}
}
关键点:
1.输出栈的特点:根节点永远最先进栈,因为先进后出,正好符合后根遍历的特点。
2.排序栈的特点:根节点且右子树永远最后进栈,每一轮挑出最大的给输出栈。后进先出符合此条件。
3.每一轮循环操作的head结点,就是将要进输出栈的成员。也是排序栈最大的。
*以此循环,直到最小的节点进入输出栈,循环结束输出。
单栈遍历
public void SingleStackPostOrder(Node head)
{
Console.WriteLine("PSOT-Order : ");
if (head != null)
{
Stack<Node> stack = new Stack<Node>();
stack.Push(head);
Node current = null;
while (stack.Count>0)
{
//Peek 和 Pop 前者不改变栈的值,后者会Delete栈顶元素
current = stack.Peek();
if (current.Left != null&& head !=current.Left&&head !=current.Right)
{
stack.Push(current.Left);
}
else if (current.Right != null && head != current.Right)
{
stack.Push(current.Right);
}
else
{
Console.WriteLine(stack.Pop().Data + " ");
head = current;
}
}
}
}
关键点:
1.head在未进行Pop操作前就是Root节点。Pop操作后,记录出栈的栈顶元素。
2.再循环取这次循环的栈顶Current,而head是上一次循环的栈顶。
3.判定 左节点进栈 那么(左节点不为空,且head不为当前操作节点的子节点)
4.判定 右节点进栈 那么 (右节点不为空,且head不为当前节点的右节点。同父级节点下的左子节点比右子节点先进去先Pop,所以head有可能为左节点)
3 4两个判定:遵循左右根输出。层次递进,索引最深,左进 左出 右进 右出 根出(直至Root).......