C语言 堆栈非递归后序实现

C语言 堆栈非递归后序实现

原理

见注释

//非递归后序遍历
void HOrder(BiTree T){	
	BiTree p = T, q = NULL;//q指向上次访问的节点
	Stack S = CreateStack();
	Push(S,p);//压入根节点	
	while(!IsEmpty(S)){		
		if(p&&p!=q){//如果当前节点不空并且没访问过,压入左孩子
			Push(S,p);
			p=p->lchild;
		} else{
			p = Pop(S);//出栈
			if(!IsEmpty(S)){//根节点没被取出
				if(p->rchild&&p->rchild!=q){//右孩子为真并且右孩子没被访问过,则重新压入父亲节点
					Push(S,p);
					p = p->rchild;//访问右孩子
				} else{
					printf("%c ",p->data);
					q = p;	//访问过之后标记				
				}				
			}			
		}
	}
}

完整代码

以下还包括了堆栈非递归前序实现,中序则只需调整printf("%c ",T->data); 位置即可,因为他们访问节点的顺序是一样的。如下图
访问顺序

#include <stdlib.h>
#include <stdio.h>
typedef struct node 
{ 
    char data; 
    struct node *lchild,*rchild; 
}BiNode,*BiTree; 

void CreatBiTree(BiTree *T) 
{ 
    char a;     
    scanf("%c",&a); 
    if(a=='#') 
     *T=NULL; 
    else 
     { 
       *T=(BiTree)malloc(sizeof(BiNode)); 
       (*T)->data=a; 
       CreatBiTree(&((*T)->lchild)); 
       CreatBiTree(&((*T)->rchild)); 
     } 
     
} 

//建立堆栈结构
typedef struct SNode{
	BiTree Data;
	struct SNode *next; 
}SNode,*Stack;

//初始化堆栈 
Stack CreateStack(){
	Stack S;
	S = (Stack)malloc(sizeof(struct SNode));
	S->next = NULL;
	return S;
} 

//判断堆栈是否为空
int IsEmpty(Stack S){
	return (S->next == NULL);
} 

//压栈
void Push(Stack S,BiTree T){
	Stack TmpCell;
	TmpCell = (Stack)malloc(sizeof(Stack));
	TmpCell->Data = T;
	TmpCell->next = S->next;
	S->next = TmpCell;
}

//出栈

BiTree Pop(Stack S){
	Stack FirstCell;
	BiTree TopElem;
	if(IsEmpty(S)){
		printf("堆栈空");
		return 0;
	} else {
		FirstCell = S->next;
		S->next = FirstCell->next;
		TopElem = FirstCell->Data;
		free(FirstCell);	
		return TopElem;	
	}
	
} 

/*非递归前序遍历*/
void InOrderTraverasl(BiTree BT){
	BiTree T = BT;
	Stack S = CreateStack();
	while(T||!IsEmpty(S)){
		while(T){
			Push(S,T);
			T = T->lchild;
		}
		T = Pop(S);
		printf("%c ",T->data);
		T = T->rchild;
	}
}
//非递归后序遍历
void HOrder(BiTree T){	
	BiTree p = T, q = NULL;//q指向上次访问的节点
	Stack S = CreateStack();
	Push(S,p);//压入根节点	
	while(!IsEmpty(S)){		
		if(p&&p!=q){//如果当前节点不空并且没访问过,压入左孩子
			Push(S,p);
			p=p->lchild;
		} else{
			p = Pop(S);//出栈
			if(!IsEmpty(S)){//根节点没被取出
				if(p->rchild&&p->rchild!=q){//右孩子为真并且右孩子没被访问过,则重新压入父亲节点
					Push(S,p);
					p = p->rchild;//访问右孩子
				} else{
					printf("%c ",p->data);
					q = p;	//访问过之后标记				
				}				
			}			
		}
	}
}
int main() { 
	BiTree T; 
	CreatBiTree(&T); 
	InOrderTraverasl(T);
	printf("\n");
	HOrder(T);

 
	return 0;
} 


 


### 回答1: 非递归后序遍历二叉树的核心代码如下: ``` void postorder_traverse(Node *root) { if (root == NULL) return; stack<Node*> s; Node *curr = root; Node *last_visited = NULL; while (curr != NULL || !s.empty()) { if (curr != NULL) { s.push(curr); curr = curr->left; } else { Node *peek_node = s.top(); // 如果右子树已经访问过了,则访问当前节点 if (peek_node->right != NULL && last_visited != peek_node->right) { curr = peek_node->right; } else { printf("%d ", peek_node->val); last_visited = peek_node; s.pop(); } } } } ``` 这段代码使用了一个栈来帮助遍历二叉树。首先将根节点压入栈中,然后遍历左子树,如果左子树遍历完了就弹出栈顶元素并访问。如果右子树还没有被访问过,就将右子树的根节点压入栈中,继续遍历左子树。如果右子树已经被访问过了,就直接访问栈顶元素。 这段代码的时间复杂度为 O(n),空间复杂度为 O(n)。 希望这能帮到你! ### 回答2: 下面是C语言实现非递归后序遍历的核心代码: ```c #include <stdio.h> #include <stdlib.h> // 定义二叉树的结构体 struct TreeNode { int val; struct TreeNode* left; struct TreeNode* right; }; // 定义栈的结构体 struct Stack { struct TreeNode* data[100]; int top; }; // 初始化栈 void initStack(struct Stack* stack) { stack->top = -1; } // 判断栈是否为空 int isEmpty(struct Stack* stack) { return stack->top == -1; } // 入栈 void push(struct Stack* stack, struct TreeNode* node) { stack->data[++(stack->top)] = node; } // 出栈 struct TreeNode* pop(struct Stack* stack) { return stack->data[(stack->top)--]; } // 获取栈顶元素 struct TreeNode* top(struct Stack* stack) { return stack->data[stack->top]; } // 非递归后序遍历函数 void postorderTraversal(struct TreeNode* root) { if (root == NULL) { return; } struct Stack stack; initStack(&stack); struct TreeNode* previsited = NULL; struct TreeNode* curr = root; while (curr != NULL || !isEmpty(&stack)) { while (curr != NULL) { push(&stack,curr); curr = curr->left; } curr = top(&stack); if (curr->right == NULL || curr->right == previsited) { printf("%d ",curr->val); // 输出节点的值 pop(&stack); previsited = curr; curr = NULL; } else { curr = curr->right; } } } int main() { // 构建二叉树 struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode)); struct TreeNode* node1 = (struct TreeNode*)malloc(sizeof(struct TreeNode)); struct TreeNode* node2 = (struct TreeNode*)malloc(sizeof(struct TreeNode)); struct TreeNode* node3 = (struct TreeNode*)malloc(sizeof(struct TreeNode)); struct TreeNode* node4 = (struct TreeNode*)malloc(sizeof(struct TreeNode)); root->val = 1; root->left = node1; root->right = node2; node1->val = 2; node1->left = node3; node1->right = NULL; node2->val = 3; node2->left = NULL; node2->right = node4; node3->val = 4; node3->left = NULL; node3->right = NULL; node4->val = 5; node4->left = NULL; node4->right = NULL; // 非递归后序遍历二叉树 postorderTraversal(root); // 释放内存 free(root); free(node1); free(node2); free(node3); free(node4); return 0; } ``` 上述代码中定义了一个`TreeNode`结构体表示二叉树节点,以及一个`Stack`结构体表示栈。其中`initStack()`函数用于初始化栈,`isEmpty()`函数用于判断栈是否为空,`push()`函数用于入栈,`pop()`函数用于出栈,`top()`函数用于获取栈顶元素。 主函数中通过手动构建一个二叉树,并调用`postorderTraversal()`函数进行非递归后序遍历,最后释放所分配的内存。 ### 回答3: 非递归后序遍历是指先遍历左子树,再遍历右子树,最后访问根节点。下面是C语言实现非递归后序遍历的核心代码: ```c // 定义树的节点结构 typedef struct TreeNode { int data; struct TreeNode* left; struct TreeNode* right; } TreeNode; // 定义栈的结构 typedef struct Stack { TreeNode* data[STACK_SIZE]; // 假设栈的最大容量为STACK_SIZE int top; } Stack; // 后序遍历函数 void postorderTraversal(TreeNode* root) { Stack stack; stack.top = -1; // 初始化栈为空 TreeNode* curr = root; // 当前节点指针 TreeNode* last = NULL; // 上一次访问的节点指针 while (curr != NULL || stack.top != -1) { // 遍历到最左子节点并将路径上的节点入栈 while (curr != NULL) { stack.data[++stack.top] = curr; curr = curr->left; } // 当前节点没有右子节点或者上一次访问的节点为其右子节点时,访问当前节点 curr = stack.data[stack.top]; if (curr->right == NULL || curr->right == last) { printf("%d ", curr->data); stack.top--; last = curr; curr = NULL; } else { curr = curr->right; } } } ``` 在这段代码中,使用了一个栈来帮助实现非递归后序遍历。首先遍历到最左子节点并将路径上的节点入栈,然后判断当前节点是否有右子节点。如果没有右子节点或者上一次访问的节点是其右子节点时,访问当前节点,并将其出栈,然后将上一次访问的节点设为当前节点,将当前节点指针置空。否则,将当前节点指针指向其右子节点。重复以上步骤,直到栈为空。最后就完成了非递归后序遍历
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值