C语言实现二叉树的非递归遍历

C语言实现二叉树的非递归遍历:

        代码解释:

非递归前序遍历:
        1> 首先建立一个二维指针,用来存储每个结点的地址,定义栈顶指针top,初始值为-1,并将根结点存入栈中,top++;
        2> 进入while循环,栈顶指针不为-1,则进入while循环,输出当前栈顶元素p的数据域,代表前序遍历的第一个结点为根结点;
        3> 如果当前的p结点拥有右子树,将这个右子树结点存入栈中,没有则不存;
                因为栈的特点是先进后出,所以先存右子树,在存左子树;
        4> 如果当前的p结点拥有左子树,将这个左子树结点存入栈中,没有则不存;
        5> 如果这个结点为叶子结点,那么直接将这个结点输出,不需要存结点;
        6> 再判断top是否为-1,之后重复执行2,3,4步骤;

非递归中序遍历:
        1> 与非递归前序遍历相同,同样需要一个二维指针的栈,栈顶元素初始化为-1;
        2> 首先判断if的判断条件,这个二叉树不为空;
        3> 在进入if条件语句中的while循环,这个循环是将与根结点相连的所有左子树全部存入栈中;
        4> 退出循环后,在判断第二个while循环的条件,栈不为空,则进入while循环;
        5> 首先输出距离与根结点相连最远的左子树;
        6> 如果这个结点拥有右子树,先将这个右子树结点存入栈中;
        7> 在判断这个结点是否拥有左子树,有的话,将与这个结点相连的所有左子树存入栈中,没有就不执行while循环,并且结束判断结点是否拥有右子树的循环;
        7> 在判断top是否为-1,成立进入循环,重复上述步骤即可;
        存储总结:就是一直将与跟结点的所有左子树存入栈中,判断左后一个结点是否拥有右子树,有的话就把与这个结点相连的所有左子树存入栈中;

非递归后序遍历:
        1> 同样建立一个二维指针的栈,用来存储每个结点的地址;
        2> 进入do-while循环,首先,将与根结点相连的所有左子树都存入栈中;
        3> 将BitTree类型的指针p赋空,判断while循环是否成立;
        4> 如果这个最后一个结点的右子树==p,则输出当前结点的数据域,栈顶指针--;
        5> 并将这个结点赋给指针p表示这个结点已经访问过,并且已经输出;
        6> 如果当前结点的右子树!=p,则接着访问这个结点的右子树,并且结束while循环,判断do-while循环的判断条件;
        7> 重复上述过程,知道不满足do-while循环的判断条件;
        存储总结:先将与根结点相连的所有左子树全部存入栈中,在判断左后一个结点是否有右子树,如果有则访问这个结点,没有的话就输出当前结点,
            当do-while循环中的两个while循环完成后,在判断do-while循环的条件,之后重复上述过程,直到不满足do-while循环条件;

        代码实现:

#include <stdio.h>
#include <stdlib.h>
#define N 20

//二叉树结点的结构体表示形式
typedef struct tree
{
    char ch;
    struct tree *lchild;
	struct tree *rchild;
}BitTree;

//创建二叉树,利用递归的方法
//按前序次序输入。 如 A # #(#表示空树)
BitTree *CreateTree()
{
	BitTree *bt;
    char str; 
    scanf("%c",&str);
    if (str=='#')
        return NULL;
    else
    {
        bt=(BitTree *)malloc(sizeof(BitTree));
        bt->ch=str;
        bt->lchild=CreateTree();
        bt->rchild=CreateTree();
        return bt;
    }
}

//前序遍历的非递归实现
/*
 思想:利用栈来实现;根结点进栈,之后栈非空,弹出,接着根节点的右结点进栈,
 之后,左节点进栈;接着,弹出栈顶元素(输出),

 此结点的右结点进栈,之后左节点进栈,弹出栈顶元素(输出)...一直这样下去,
 直到栈为空。
 */
void PreOrder(BitTree *bt)
{
    BitTree **s;
	BitTree *p;
	int top=-1;
	//创建栈;
	s=(BitTree **)malloc((N+1)*sizeof(BitTree *));
	//初始化栈;
	s[++top]=bt;
	//非递归前序遍历;
	while(top!=-1)
	{
		p=s[top--];
		printf("%c ",p->ch);    //栈的特点,先进后出;
		if(p->rchild)
			s[++top]=p->rchild;
		if(p->lchild)
			s[++top]=p->lchild;
	}
	free(s);
}


//中序遍历,非递归实现
/*
 思想:利用栈。从根节点开始循环,只要有左子节点则进栈,直到左子节点为空。
 接着弹出栈顶输出,判断该结点是否有右子节点,

 若有则进栈,若没有继续弹栈。有右子节点的情况,判断该节点是否有左子节点,
 有则进栈,直到左子节点为空;若该右子节点没有

 左子节点,则弹栈;判断弹出的节点,是否有右子节点,若有则进栈,没有继续弹栈;
 接着又要判断刚进栈的这个节点,是否有左子节点,

 有则进栈,没有则继续弹栈。重复下去....

 栈空,是判定条件。
 */
void InOrder(BitTree *bt)
{
	BitTree **s;
    BitTree *p,*q;
    int top=-1;
	//创建栈;
	s=(BitTree **)malloc((N+1)*sizeof(BitTree *));
	//非递归中序遍历;
    if(bt)
    {
        while(bt)   //一直遍历左子树直到该结点的左孩子空为止;
        {
            s[++top]=bt;   //将所有左孩子存入栈中;
            bt=bt->lchild;     //指向下一个左子树;
        }
        while(top!=-1)  //栈空时结束循环;
        {
            p=s[top--];//刚开始将最p指向左下角的左孩子,并且移向该结点的父结点;
            printf("%c ",p->ch);  //输出左下角的结点;
            while(p->rchild)  //遍历移动后结点有没有右结点;
            {
                s[++top]=p->rchild;   //将这个结点的右子树入栈;
                q=p->rchild;		  //这个右子树结点赋给q;
                while(q->lchild)      //判断结点q有没有左子树;
                {
                    s[++top]=q->lchild;  //有左子树,将与这个结点相连的所有左子树都入栈;
                    q=q->lchild;
                }
                break;   //结束当前循环,回到第二个while循环继续刚才的步骤;
            }
        }
    }
}

//后序遍历,非递归实现
/*
 算法思想:利用栈来实现。从根结点开始,只要左子节点非空,则进栈,直到左子节点
 为空为止。取出栈顶元素(只是取,并非弹栈),判断:

 1:取出的栈顶元素是否有右子节点,或者右子节点是否被访问过,若满足条件(无右子
 节点,或者右子节点被访问过),则输出该结点,同时弹栈,并且记录下该访问的节点。

 2:取出的栈顶元素,若有右子节点,且未被访问过,则指针继续移动到右子节点,
 重复一开始是否又左子节点的判断。
*/
void PostOrder(BitTree *bt)
{	
	BitTree **s;
	BitTree *p;
    int top=-1;
	//创建栈;
	s=(BitTree **)malloc((N+1)*sizeof(BitTree *));
	//非递归后序遍历;
    do
    {
        while(bt)     //一直遍历左子树直到该左子树的左孩子空为止;
        {
            s[++top]=bt;     //将所有左孩子存入栈中;
            bt=bt->lchild;   //指向下一个左子树;
        }
        p=NULL;
        while(top!=-1)
        {
            bt=s[top];
            if(bt->rchild==p)  //p:表示为null,或者右子节点被访问过了;
            {
                printf("%c ",bt->ch);   //输出结点数据域;
                top--;           //输出以后,top--;
                p=bt;  //p记录下刚刚访问的节点;
            }
            else
            {
                bt=bt->rchild;   //访问右子树结点;
                break;
            }
        }
    }while(top!=-1);
}

int main()
{
    printf("请以顺序输入二叉树(#表示该结点的子结点为空):\n");
    BitTree *btr=CreateTree();
    printf("前序遍历非递归实现:\n");
    PreOrder(btr);
    printf("\n");
    printf("中序遍历非递归实现:\n");
    InOrder(btr);
    printf("\n");
    printf("后序遍历非递归实现:\n");
    PostOrder(btr);
    printf("\n");
    return 0;
}

        实现截图:   

    

        
  • 46
    点赞
  • 245
    收藏
    觉得还不错? 一键收藏
  • 22
    评论
二叉树的中序遍历可以通过非递归的方式实现,常用的方法是利用栈。具体的实现方法如下: 1. 初始化一个栈,将根节点入栈。 2. 循环执行以下步骤,直到栈为空: 1. 将栈顶节点弹出,并将其右子节点(如果有)压入栈中。 2. 将当前节点压入栈中,并将其左子节点(如果有)置为当前节点。 3. 遍历完成。 下面是具体的代码实现: ```c #include <stdio.h> #include <stdlib.h> // 二叉树节点结构体 typedef struct TreeNode { int val; struct TreeNode* left; struct TreeNode* right; } TreeNode; // 栈节点结构体 typedef struct StackNode { TreeNode* node; struct StackNode* next; } StackNode; // 初始化栈 StackNode* initStack() { return NULL; } // 入栈 StackNode* push(StackNode* stack, TreeNode* node) { StackNode* new_node = (StackNode*)malloc(sizeof(StackNode)); new_node->node = node; new_node->next = stack; return new_node; } // 出栈 StackNode* pop(StackNode* stack) { if (stack == NULL) { return NULL; } StackNode* top = stack; stack = stack->next; free(top); return stack; } // 获取栈顶节点 TreeNode* top(StackNode* stack) { if (stack == NULL) { return NULL; } return stack->node; } // 中序遍历二叉树非递归) void inorderTraversal(TreeNode* root) { StackNode* stack = initStack(); // 初始化栈 TreeNode* cur = root; // 当前节点 while (stack != NULL || cur != NULL) { if (cur != NULL) { stack = push(stack, cur); // 当前节点入栈 cur = cur->left; // 左子节点置为当前节点 } else { cur = top(stack); // 获取栈顶节点 stack = pop(stack); // 栈顶节点出栈 printf("%d ", cur->val); // 打印节点值 cur = cur->right; // 右子节点置为当前节点 } } } int main() { // 构造二叉树 TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode)); root->val = 1; root->left = (TreeNode*)malloc(sizeof(TreeNode)); root->left->val = 2; root->left->left = NULL; root->left->right = NULL; root->right = (TreeNode*)malloc(sizeof(TreeNode)); root->right->val = 3; root->right->left = (TreeNode*)malloc(sizeof(TreeNode)); root->right->left->val = 4; root->right->left->left = NULL; root->right->left->right = NULL; root->right->right = (TreeNode*)malloc(sizeof(TreeNode)); root->right->right->val = 5; root->right->right->left = NULL; root->right->right->right = NULL; // 中序遍历二叉树 inorderTraversal(root); printf("\n"); return 0; } ``` 上述代码中,`push`、`pop` 和 `top` 操作均是常规的栈操作,不再赘述。在 `inorderTraversal` 函数中,每次循环都将当前节点的左子节点置为当前节点,并将当前节点入栈,直到当前节点为空。然后,取出栈顶节点,打印节点值,并将右子节点置为当前节点。循环执行这个过程,直到栈为空。
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值