二叉链表的 遍历 是 二叉链表 各种 操作的 基础,例如 :创建 二叉树;求树的 长度;求树的 叶子节点数;求 节点的 层 数;求 树的 深度,宽度 等等。
总之 不掌握 遍历,就没有 掌握 二叉树;
二叉链表的 遍历 根据 根节点的访问顺序有:先(根节点)序,中(根节点)序,后(根节点)序, 和 层序;
算法思路 有两类:
1. 递归 算法,算法 清晰,容易 证明算法的正确性,但是 效率较低 和 受 系统 栈区 大小的限制,不能 递归太多层次
2.非 递归算法,算法 较复杂一些,但是效率高,又 不受 栈区大小的限制
下面 讲解 这两种 算法:
1.递归算法 ,递归没什么 说的,比较 简单
//递归算法 先序
void preOrderTraverse(Tree tree){
if (tree != NULL)
{
printf("%d\t",tree->data);
preOrderTraverse(tree->leftChild);
preOrderTraverse(tree->rightChild);
}
}
//递归算法 中序
void inOrderTraverse(Tree tree){
if (tree != NULL)
{
inOrderTraverse(tree->leftChild);
printf("%d\t",tree->data);
inOrderTraverse(tree->rightChild);
}
}
//递归算法 后序
void postOrderTraverse(Tree tree){
if (tree != NULL)
{
postOrderTraverse(tree->leftChild);
postOrderTraverse(tree->rightChild);
printf("%d\t",tree->data);
}
}
2.1 非递归 先序 算法 总共 有 三种 方法:
下面 的两种算法 思路一致,都是 找左子树最左下角节点的同时访问节点,然后 将 节点的 右子树入栈。然后 重复寻找..
void preOrderTraverse1(Tree t){
linkStack stack;
stackInit(&stack);
stackPush(&stack,t);
while (!stackEmpty(stack))
{
while (stackGetTop(stack,&t) && t)
{
printf("%d\t",t->data);
stackPush(&stack,t->leftChild);
}
stackPop(&stack,&t);//NULL 出栈
if (!stackEmpty(stack))
{
stackPop(&stack,&t);
stackPush(&stack,t->rightChild);
}
}
stackDestory(&stack);
}
void preOrderTraverse2(Tree tree){
linkStack stack;
stackInit(&stack);
while (tree || !stackEmpty(stack))
{
if (tree)
{
printf("%d\t",tree->data);
stackPush(&stack,tree);
tree = tree->leftChild;
}
else
{
stackPop(&stack,&tree);
tree = tree->rightChild;
}
}
stackDestory(&stack);
}第三种 思路 较 前两种 清晰,更加 易懂
1.空树 不操作 2.将 树根入栈 3.访问 根 节点 4. 右子树不为空,将 右子树 入栈 5. 左子树 不为空,将左子树入栈 6.重复 3~ 5 步
比较 奇思妙想的是 先 将 右子树入栈 ,再将 左子树入栈,这样每次 都 先 访问 栈顶 的 左子树。
void preOrderTraverse3(Tree tree){
if (tree != NULL)
{
linkStack stack;
stackInit(&stack);
stackPush(&stack,tree);
while (!stackEmpty(stack))
{
stackPop(&stack,&tree);
printf("%d\t",tree->data);
if (tree->rightChild != NULL)
{
stackPush(&stack,tree->rightChild);
}
if (tree->leftChild != NULL)
{
stackPush(&stack,tree->leftChild);
}
}
}
}2.2 非递归 中序 有两种算法
算法 思路 同 先序 前两种 算法 的思路 一致,只是 先序是在 在 找 左子树的时候 访问,而终须 是 在 退栈的时候访问
//中序非递归
void inOrderTraverse1(Tree tree){
linkStack stack;
stackInit(&stack);
stackPush(&stack,tree);
while (!stackEmpty(stack))
{
while (stackGetTop(stack,&tree) && tree) stackPush(&stack,tree->leftChild);
stackPop(&stack,&tree);
if (!stackEmpty(stack))
{
stackPop(&stack,&tree);
printf("%d\t",tree->data);
stackPush(&stack,tree->rightChild);
}
}
stackDestory(&stack);
}
void inOrderTraverse2(Tree tree){
linkStack stack;
stackInit(&stack);
while (tree || !stackEmpty(stack))
{
if (tree)
{
stackPush(&stack,tree);
tree = tree->leftChild;
}
else
{
stackPop(&stack,&tree);
printf("%d\t",tree->data);
tree = tree->rightChild;
}
}
stackDestory(&stack);
}
大致 的思路 是 :只有 底下 三种情况的时候 访问 根节点。
1. 节点的 左子树 为空 并且 右 子树 为空 ,2. 刚访问过 右子树 3. 刚访问过左子树 并且 右子树 为空的 时候
这个算法 需要 记住 上一个 访问的 节点 和 利用 先 右子树 入栈 后 左子树 入栈,始终 先访问 左子树。
void postOrderTraverse1(Tree tree){
if (tree != NULL)
{
linkStack stack;
stackInit(&stack);
stackPush(&stack,tree);
Tree pre = NULL;
while (!stackEmpty(stack))
{
stackGetTop(stack,&tree);
//左右子树都为空,或者 左子树刚访问过,并且 右子树为空,或者 刚访问过 右子树. 可以直接访问
if ((tree->leftChild == NULL && tree->rightChild == NULL) || (pre != NULL && (tree->leftChild == pre || tree->rightChild == pre)))
{
printf("%d\t",tree->data);
stackPop(&stack,&tree);
pre = tree;
}
else
{
if (tree->rightChild != NULL)
{
stackPush(&stack,tree->rightChild);
}
if(tree->leftChild != NULL)
{
stackPush(&stack,tree->leftChild);
}
}
}
}
}这个算法 有一个特点,左子树 一定 在 右子树 前 访问,左子树的 孩子 一定 在 右子树的 孩子前 访问。
大概的思路:1. 将根节点入队列,访问 根节点 2. 将左 子树 入队列, 3.将 右子树 入队列 4.重复 1~3
//层序
//利用队列
void levelOrderTraverse(Tree tree){
if (tree != NULL)
{
LinkQueue queue;
queueInit(&queue);
enqueue(&queue,tree);
while (dequeue(&queue,&tree) && tree)
{
printf("%d\t",tree->data);
if (tree->leftChild != NULL)
{
enqueue(&queue,tree->leftChild);
}
if (tree->rightChild != NULL)
{
enqueue(&queue,tree->rightChild);
}
}
queueDestory(&queue);
}
}// binaryTree.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <cstdlib>
#include "stack.h"
#include "queue.h"
typedef int ElementType;
typedef struct TreeNode
{
ElementType data;
TreeNode * leftChild;
TreeNode * rightChild;
} * Tree;
void treeInit(Tree * tree){
*tree = NULL;
}
//其实 自己 不懂 这个 函数 初始化...
E_State treeCreate(Tree *tree){
ElementType data;
scanf("%d",&data);
if (data == 0)
{
*tree = NULL;
}else
{
*tree = (Tree)malloc(sizeof(TreeNode));
(*tree)->data = data;
treeCreate(&(*tree)->leftChild);
treeCreate(&(*tree)->rightChild);
}
return E_State_Ok;
}
//后序遍历
void treeClear(Tree * tree){
if (tree != NULL)
{
if ((*tree)->leftChild != NULL)
{
treeClear(&(*tree)->leftChild);
}
else if((*tree)->rightChild != NULL)
{
treeClear(&(*tree)->rightChild);
}
free(*tree);
*tree = NULL;
}
}
void treeDestory(Tree * tree){
treeClear(tree);
}
//递归算法 先序
void preOrderTraverse(Tree tree){
if (tree != NULL)
{
printf("%d\t",tree->data);
preOrderTraverse(tree->leftChild);
preOrderTraverse(tree->rightChild);
}
}
//递归算法 中序
void inOrderTraverse(Tree tree){
if (tree != NULL)
{
inOrderTraverse(tree->leftChild);
printf("%d\t",tree->data);
inOrderTraverse(tree->rightChild);
}
}
//递归算法 后序
void postOrderTraverse(Tree tree){
if (tree != NULL)
{
postOrderTraverse(tree->leftChild);
postOrderTraverse(tree->rightChild);
printf("%d\t",tree->data);
}
}
//非递归 算法
void preOrderTraverse1(Tree t){
linkStack stack;
stackInit(&stack);
stackPush(&stack,t);
while (!stackEmpty(stack))
{
while (stackGetTop(stack,&t) && t)
{
printf("%d\t",t->data);
stackPush(&stack,t->leftChild);
}
stackPop(&stack,&t);//NULL 出栈
if (!stackEmpty(stack))
{
stackPop(&stack,&t);
stackPush(&stack,t->rightChild);
}
}
stackDestory(&stack);
}
void preOrderTraverse2(Tree tree){
linkStack stack;
stackInit(&stack);
while (tree || !stackEmpty(stack))
{
if (tree)
{
printf("%d\t",tree->data);
stackPush(&stack,tree);
tree = tree->leftChild;
}
else
{
stackPop(&stack,&tree);
tree = tree->rightChild;
}
}
stackDestory(&stack);
}
void preOrderTraverse3(Tree tree){
if (tree != NULL)
{
linkStack stack;
stackInit(&stack);
stackPush(&stack,tree);
while (!stackEmpty(stack))
{
stackPop(&stack,&tree);
printf("%d\t",tree->data);
if (tree->rightChild != NULL)
{
stackPush(&stack,tree->rightChild);
}
if (tree->leftChild != NULL)
{
stackPush(&stack,tree->leftChild);
}
}
}
}
//中序非递归
void inOrderTraverse1(Tree tree){
linkStack stack;
stackInit(&stack);
stackPush(&stack,tree);
while (!stackEmpty(stack))
{
while (stackGetTop(stack,&tree) && tree) stackPush(&stack,tree->leftChild);
stackPop(&stack,&tree);
if (!stackEmpty(stack))
{
stackPop(&stack,&tree);
printf("%d\t",tree->data);
stackPush(&stack,tree->rightChild);
}
}
stackDestory(&stack);
}
void inOrderTraverse2(Tree tree){
linkStack stack;
stackInit(&stack);
while (tree || !stackEmpty(stack))
{
if (tree)
{
stackPush(&stack,tree);
tree = tree->leftChild;
}
else
{
stackPop(&stack,&tree);
printf("%d\t",tree->data);
tree = tree->rightChild;
}
}
stackDestory(&stack);
}
void postOrderTraverse1(Tree tree){
if (tree != NULL)
{
linkStack stack;
stackInit(&stack);
stackPush(&stack,tree);
Tree pre = NULL;
while (!stackEmpty(stack))
{
stackGetTop(stack,&tree);
//左右子树都为空,或者 左子树刚访问过,并且 右子树为空,或者 刚访问过 右子树. 可以直接访问
if ((tree->leftChild == NULL && tree->rightChild == NULL) || (pre != NULL && (tree->leftChild == pre || tree->rightChild == pre)))
{
printf("%d\t",tree->data);
stackPop(&stack,&tree);
pre = tree;
}
else
{
if (tree->rightChild != NULL)
{
stackPush(&stack,tree->rightChild);
}
if(tree->leftChild != NULL)
{
stackPush(&stack,tree->leftChild);
}
}
}
}
}
//层序
//利用队列
void levelOrderTraverse(Tree tree){
if (tree != NULL)
{
LinkQueue queue;
queueInit(&queue);
enqueue(&queue,tree);
while (dequeue(&queue,&tree) && tree)
{
printf("%d\t",tree->data);
if (tree->leftChild != NULL)
{
enqueue(&queue,tree->leftChild);
}
if (tree->rightChild != NULL)
{
enqueue(&queue,tree->rightChild);
}
}
queueDestory(&queue);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
Tree tree;
printf("---------------创建树(先序,0代表子树为空)-----------------\n");
treeCreate(&tree);
printf("------------先序递归遍历----------------\n");
preOrderTraverse(tree);
printf("------------先序非递归遍历1----------------\n");
preOrderTraverse1(tree);
printf("------------先序非递归遍历2----------------\n");
preOrderTraverse2(tree);
printf("------------先序非递归遍历3----------------\n");
preOrderTraverse3(tree);
printf("\n------------中序递归遍历----------------\n");
inOrderTraverse(tree);
printf("\n------------中序非递归遍历1----------------\n");
inOrderTraverse1(tree);
printf("\n------------中序非递归遍历2----------------\n");
inOrderTraverse2(tree);
printf("\n------------后序递归遍历----------------\n");
postOrderTraverse(tree);
printf("\n------------后序非递归遍历1----------------\n");
postOrderTraverse1(tree);
printf("\n------------层序遍历----------------\n");
levelOrderTraverse(tree);
//及时释放内存是个好习惯..
treeDestory(&tree);
return 0;
}
运行截图:
看数据结构写代码(24) 二叉链表的递归遍历 和 非递归遍历 算法 总结
原文:http://blog.csdn.net/fuming0210sc/article/details/44587009