【编程】数据结构入门:二叉树前、中、后、层序遍历(迭代非递归方法)

前序遍历:

对于每一个节点,最先访问的是以此节点开始的最左路径。
对于每一个树,最先访问的右子树是在访问左路径是最后遇到的右子树。

左边的节点访问:自上而下
右边的节点访问:自下而上

利用“数据结构——栈”来实现迭代前序遍历

  1. 访问每一个节点开始的最左路径,访问到的每一个节点入栈
  2. 最左路径访问完成之后,获取栈顶元素,继续访问以栈顶元素的右子树为根的子结构,继续执行第一步
  3. 结束:栈为空 || 右子树为空
// C语言代码
// 力扣接口
typedef struct TreeNode* STDataType;
typedef struct Stack
{
    
    
	STDataType* _a;
	int _top;		// 栈顶
	int _capacity;  // 容量 
}Stack;

// 初始化栈 
void StackInit(Stack* ps)
{
    
    
	if (ps == NULL)
		return;
	ps->_top = 0;
	ps->_capacity = 0;
	ps->_a = NULL;
}

// 栈容量检测
void StackCheck(Stack* ps)
{
    
    
	if(ps->_top==ps->_capacity)
	{
    
    
		int newcapacity = (ps->_capacity == 0 ? 1 : 2 * ps->_capacity);
		ps->_a = (STDataType*)realloc(ps->_a, sizeof(STDataType) * newcapacity);
		ps->_capacity = newcapacity;
	}
}

// 入栈 
void StackPush(Stack* ps, STDataType data)
{
    
    
	StackCheck(ps);
	ps->_a[ps->_top++] = data;
}

// 出栈 
void StackPop(Stack* ps)
{
    
    
	if (ps == NULL || ps->_top == 0)
		return;
	ps->_top--;
}

// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{
    
    
	assert(ps);
	if (ps->_top == 0)
		return (STDataType)0;
	return ps->_a[ps->_top - 1];
}

// 获取栈中有效元素个数 
int StackSize(Stack* ps)
{
    
    
	assert(ps);
	return ps->_top;
}

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps)
{
    
    
	assert(ps);
	return ps->_top == 0;
}

// 销毁栈 
void StackDestroy(Stack* ps)
{
    
    
	if (ps == NULL)
		return;
	if (ps->_a)
	{
    
    
		free(ps->_a);
		ps->_a = NULL;
		ps->_capacity = 0;
		ps->_top = 0;
	}
}

int BinaryTreeSize(struct TreeNode* root)
{
    
    
	if (root == NULL)
		return 0;
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

// 迭代前序遍历
int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
    
    
    Stack st;
    StackInit(&st);
    int size=BinaryTreeSize(root);
    int* ans=(int*)malloc(sizeof(int)*size);
    int idx=0;
    while(root || !StackEmpty(&st))
    {
    
    
        while(root)
        {
    
    
            ans[idx++]=root->val;
            StackPush(&st, root);
            root=root->left;
        }
        root=StackTop(&st);
        StackPop(&st);
        root=root->right;
    }
    StackDestroy(&st);
    *returnSize=idx;
    return ans;
}

中序遍历:

利用“数据结构——栈”来实现迭代中序遍历

  1. 以根节点开始,走最左路径,此路径上遇到的每一个节点首先入栈,但不访问
  2. 获取栈顶元素,访问栈顶元素
  3. 获取栈顶元素的右子树,继续执行第1步
  4. 结束:栈为空 || 右子树为空
// 迭代中序遍历
// 栈的代码同上
// 力扣接口
int* inorderTraversal(struct TreeNode* root, int* returnSize)
{
    
    
    Stack st;
    StackInit(&st);
    int size=BinaryTreeSize(root);
    int* ans=(int*)malloc(sizeof(int)*size);
    int idx=0;
    while(root || !StackEmpty(&st))
    {
    
    
        while(root)
        {
    
    
            StackPush(&st,root);
            root=root->left;
        }
        root=StackTop(&st);
        ans[idx++]=root->val;
        StackPop(&st);
        root=root->right;
    }
    StackDestroy(&st);
    *returnSize=idx;
    return ans;
}

后序遍历:

利用“数据结构——栈”来实现迭代后序遍历

  1. 以根节点开始,遍历最左路径,遇到的每一个节点,入栈
  2. 获取栈顶元素:
    判断当前栈顶元素是否可以访问:
    a. 没有右子树 || 右子树访问完成:可以访问 执行第1步
    b. 有右子树但还没有访问完成:不能访问 首先访问右子树,再执行第1步
  3. 结束:栈为空 || 节点为空
    在这里插入图片描述
// 迭代后序遍历
// 栈的代码同上
// 力扣接口
int* postorderTraversal(struct TreeNode* root, int* returnSize)
{
    
    
    Stack st;
    StackInit(&st);
    int size=BinaryTreeSize(root);
    int* ans=(int*)malloc(sizeof(int)*size);
    int idx=0;
    struct TreeNode* prev=NULL;
    struct TreeNode* top=NULL;
    while(root || !StackEmpty(&st))
    {
    
    
        while(root)
        {
    
    
            StackPush(&st,root);
            root=root->left;
        }
        top=StackTop(&st);
        if(top->right==prev || top->right==NULL)
        {
    
    
            ans[idx++]=top->val;
            StackPop(&st);
            prev=top;
        }
        else
            root=top->right;
    }
    StackDestroy(&st);
    *returnSize=idx;
    return ans;
}

层序遍历:

利用“数据结构——队列”来实现迭代层序遍历
在这里插入图片描述

// 层序遍历
// 非力扣接口
void BinaryTreeLevelOrder(BTNode* root)
{
    
    
	// 借助队列保存节点
	Queue q;
	QueueInit(&q);
	// 根节点入队
	if (root)
		QueuePush(&q, root);
	// 遍历队列中的每一个节点
	while (!QueueEmpty(&q))
	{
    
    
		// 获取队头元素
		BTNode* node = QueueFront(&q);
		// 出队
		QueuePop(&q);

		printf("%c ", node->_data);
		// 保存队头元素的左右孩子节点
		if (node->_left)
			QueuePush(&q, node->_left);
		if (node->_right)
			QueuePush(&q, node->_right);
	}
	printf("\n");
}

猜你喜欢

转载自blog.csdn.net/m0_46613023/article/details/114295384