二叉树的遍历

文章目录

二叉树的遍历是二叉树操作中的一个基本且重要的操作,它指的是按照某种规则访问二叉树中的每个节点,并且每个节点仅被访问一次。常见的二叉树遍历方法包括前序遍历(Preorder Traversal)、中序遍历(Inorder Traversal)、后序遍历(Postorder Traversal)以及层次遍历(Level-Order Traversal)。


一、前序遍历

前序遍历的顺序是:先访问根节点,然后遍历左子树,最后遍历右子树。在遍历左子树和右子树时,也按照同样的前序遍历方式。

递归方法 

void preorderTraversal(TreeNode* root) {  
    if (root == NULL) return;  
    // 访问根节点  
    printf("%d ", root->val);  
    // 遍历左子树  
    preorderTraversal(root->left);  
    // 遍历右子树  
    preorderTraversal(root->right);  
}

非递归方法 

// 前序遍历二叉树(非递归)
void preorderTraversalIterative(struct TreeNode* root) {  
    if (root == NULL) return;  
    
    // 创建栈存储节点
    struct TreeNode** stack = (struct TreeNode**)malloc(sizeof(struct TreeNode*) * 1000);
    if(stack == NULL)
    {
    	printf("fail to create satck!\n");
    	return;
    }
    
    // 栈中节点数量
    int cnt = 0;
    
    // 根节点入栈
    stack[cnt++] = root;
    
    while (cnt) { 
     	
     	// 取栈顶元素
		struct TreeNode* temp = stack[cnt-1];
		
		// 出栈
		cnt--;
		
        // 访问节点  
        printf("%d ", temp->val);  
        // 先右后左入栈,保证左子树先遍历  
        if(temp->right) stack[cnt++] = temp->right;
        if(temp->left)  stack[cnt++] = temp->left;
         
    } 
    
    free(stack); 
} 

非递归方法是用堆内存去模拟一个栈(数据先入后出),用这个栈模拟前序遍历过程。具体的实现过程见http://t.csdnimg.cn/O4v1jO4v1j 。


二、中序遍历

中序遍历的顺序是:先遍历左子树,然后访问根节点,最后遍历右子树。在遍历左子树和右子树时,也按照同样的中序遍历方式。

递归方法

// 中序遍历二叉树(递归)
void inorderTraversal(struct TreeNode* root) {  
    if (root == NULL) return;  
    // 遍历左子树  
    inorderTraversal(root->left);  
    // 访问根节点  
    printf("%d ", root->val);  
    // 遍历右子树  
    inorderTraversal(root->right);  
}

非递归方法

// 中序遍历二叉树(非递归)
void inorderTraversalIterative(struct TreeNode* root) {  
    if (root == NULL) return;  
    
    struct TreeNode **stack = malloc(sizeof(struct TreeNode *) * 1000);
    
    if(stack == NULL) 
    {
    	printf("fail to create satck!\n");
    	return;
    }
    
    int cnt = 0;
    struct TreeNode* curr = root;  
    
    while (curr != NULL || cnt != 0) {  
        // 遍历到最左节点  
        while (curr != NULL) {  
            stack[cnt++] = curr; 
            curr = curr->left;  
        }  
        // 访问节点  
        curr = stack[cnt-1];  
        
        cnt--;
          
        printf("%d ", curr->val);  
        // 转向右子树  
        curr = curr->right;  
    }  
    
    free(stack);
}

 类似前序遍历这里同样模拟栈的存储方法(先入后出)去实现中序遍历过程,具体的入栈出栈过程见http://t.csdnimg.cn/O4v1j


三、后续遍历 

递归方法

// 后序遍历(递归)
void postorderTraversal(struct TreeNode* root) 
{
	if (root == NULL) return;  
    // 遍历左子树  
    postorderTraversal(root->left);  
    // 遍历右子树  
    postorderTraversal(root->right);  
    // 访问根节点  
    printf("%d ", root->val); 
}

非递归方法 

// 后序遍历(非递归)
void postorderTraversalIterative(struct TreeNode* root) 
{
	// 创建栈存储节点
    struct TreeNode** stack1 = (struct TreeNode**)malloc(sizeof(struct TreeNode*) * 1000);
    struct TreeNode** stack2 = (struct TreeNode**)malloc(sizeof(struct TreeNode*) * 1000);
    if(stack1 == NULL || stack2 == NULL)
    {
    	printf("fail to create satck!\n");
    	return;
    }
    
    // 栈中节点数量
    int cnt1 = 0, cnt2 = 0;
    
    // 根节点入栈
    stack1[cnt1++] = root;
    
    while (cnt1) { 
     	
     	// 取栈顶元素
		struct TreeNode* temp = stack1[cnt1-1];
		stack2[cnt2++] = temp; // 栈顶元素入栈2
		// 出栈
		cnt1--;
		 
        // 先右后左入栈,保证左子树先遍历  
        if(temp->right) stack1[cnt1++] = temp->right;
        if(temp->left)  stack1[cnt1++] = temp->left;
         
    } 
    
    // 取出栈2中的元素
    while(cnt2)
    {
    	printf("%d ", stack2[--cnt2]->val);
    }
    
    free(stack1); 
    free(stack2);
}
  

 后序遍历的非递归实现相对复杂,这里的思路是创建两个栈先使用非递归方式实现前序遍历,然后将结果压入另一个栈,最后依次出栈逆序输出。


四、层序遍历 

层次遍历是按照二叉树的层次从上到下、从左到右遍历。

非递归实现(常用队列)

// 层次遍历二叉树  
void levelOrderTraversal(struct TreeNode* root) {  
    if (root == NULL) return;  
  
    // 创建一个队列用于存储节点  
    struct TreeNode** queue = (struct TreeNode**)malloc(sizeof(struct TreeNode*) * 1000); // 假设队列大小足够   
    int front = 0, rear = 0;  
  
    // 根节点入队  
    queue[rear++] = root;  
  
    while (front < rear) {  
        // 访问队首元素  
        struct TreeNode* temp = queue[front++];  
        printf("%d ", temp->val);  
  
        // 如果左子节点存在,则左子节点入队  
        if (temp->left) {  
            queue[rear++] = temp->left;  
        }  
  
        // 如果右子节点存在,则右子节点入队  
        if (temp->right) {  
            queue[rear++] = temp->right;  
        }  
    }  
  
    // 释放队列内存(如果需要)  
    free(queue);  
}  

 实现思路是用堆内存以及两个头尾指针去模拟队列(先入先出),再用队列模拟层次遍历。其过程可参考如下图示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值