二叉树----遍历(先序、中序、后序遍历的递归、非递归+层次遍历)

所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问 题。 遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。

一、先序遍历

递归方式实现:

  • 访问根结点(此处的根结点并非特指整棵树的根结点,泛着所有子树的根节点 );
  • 递归访问左孩子;
  • 递归访问右孩子;
void PreOrder(BtNode *p)//前序遍历
{
	if (p != NULL)
	{
		cout << p->data << " ";//此处相当于每颗子树的根结点; 
		PreOrder(p->leftchild);
		PreOrder(p->rightchild);
	}
}

非递归方式实现:通过压栈和出栈的方式;

方法一:从右到左入栈(可以联想两个点:栈的性质是先进后出+先序遍历的递归顺序)

  • 将根结点入栈;
  • 获取栈顶元素并打印;
  • 栈顶元素出栈;
  • 判断获取到的栈顶元素右子树是否为空,不为空则入栈右节点;
  • 判断获取到的栈顶元素左子树是否为空,不为空则入栈左节点;
void Nice_PreOrder1(BtNode* tree)//非递归先序遍历,从右到左入栈法则。
{
	stack<BtNode*>st;
	st.push(tree);
	while (!st.empty())
	{
		BtNode* p = st.top();
		cout << p->data << " ";
		st.pop();

		if (p->rightchild != NULL)
		{
			st.push(p->rightchild);
		}
		if (p->leftchild != NULL)
		{
			st.push(p->leftchild);
		}
	}
}

方法二:从左至右入栈

  • 利用一个栈,首先从根节点一直入栈左子树,并不断打印遇到的节点,直到左子树为NULL
  • 获取并出栈栈顶元素,对获取到的栈顶元素的右子树做如上操作
  • 直到将栈为空,遍历结束
void Nice_PreOrder2(BtNode *tree)//非递归先序遍历,从左到右栈法则
{
	if (tree == NULL)
	{
		cout << "This is empty tree";
	}
	stack<BtNode *>sta;
	while (tree || !sta.empty())
	{
		while (tree)
		{
			sta.push(tree);
			cout << tree->data<<" ";
			tree = tree->leftchild;
		}
		tree = sta.top();
		sta.pop();
		tree = tree->rightchild;
	}
}

二、中序遍历

递归方式实现:

  • 递归遍历左子树;
  • 访问根结点;
  • 递归遍历右子树;
void InOrder(BtNode *p)//中序遍历
{
	if (p != NULL)
	{
		InOrder(p->leftchild);
		cout << p->data << " ";
		InOrder(p->rightchild);
	}
}

非递归方式实现:

方法一:

很显然中序遍历是当第二次访问到某个节点时打印(或其他操作),因此可以利用出栈的次数来进行打印。

首先定义一个存储节点访问次数的结构体,此时栈里存储的不光是节点,还有节点对应的出栈次数。

typedef struct stkNode
{
	BtNode* node;//节点
	int num;//节点对应的出栈次数
public:
	stkNode(BtNode* n)
	{
		node = n;
		num = 0;
	}
}stkNode;
  • 首先入栈根节点。
  • 获取栈顶元素,判断如果该节点出栈次数,如果为2则打印,然后判断右子树是否为NULL,不为空入栈右子树
  • 如果该节点出栈次数不为2则继续将该节点入栈,然后判断该节点左子树是否为NULL,不为空则入栈左子树
  • 直到栈空,否则重复上述操作
void Nice_InOrder2(BtNode* tree)
{
	if (tree == NULL)
	{
		return;
	}
	stack<stkNode> st;
	st.push(tree);
	while (!st.empty())
	{
		stkNode stk = st.top();
		st.pop();
		if (++stk.num == 2)
		{
			cout << stk.node->data << " ";
			if (stk.node->rightchild != NULL)
			{
				st.push(stkNode(stk.node->rightchild));
			}
		}
		else
		{
			st.push(stk);
			if (stk.num == 1 && stk.node->leftchild != NULL)
			{
				st.push(stkNode(stk.node->leftchild));
			}
		}
	}
	cout << endl;
}

方式二:该方法和从左到右入栈先序非递归遍历相似,只是在入栈左子树的过程中不打印所遇到的节点,而是等到出栈的时候再打印。思路如下

  • 利用一个栈,首先从根节点一直入栈左子树,直到左子树为NULL;
  • 获取并出栈栈顶元素并打印,对获取到的栈顶元素的右子树做如上操作;
  • 直到将栈为空,遍历结束
void Nice_InOrder1(BtNode* tree)//非递归中序遍历,一直入左,左空打印,入当前右。
{
	if (tree == NULL)
	{
		cout << "This is empty tree";
	}
	stack<BtNode *>sta;
	while (tree || !sta.empty())
	{
		while (tree)
		{
			sta.push(tree);
			tree = tree->leftchild;
		}
		tree = sta.top();
		cout << tree->data << " ";
		sta.pop();
		tree = tree->rightchild;
	}
}

 

三、后序遍历

递归方式实现:

  • 先递归遍历左子树
  • 再递归遍历右子树
  • 最后打印当前节点
void PastOrder(BtNode *p)//后序遍历
{
	if (p != NULL)
	{
		PastOrder(p->leftchild);
		PastOrder(p->rightchild);
		cout << p->data << " ";
	}
}

非递归方式实现:利用出栈次数的方式来做,只不过后序遍历是第三次出栈进行打印。

void Nice_PastOrder(BtNode* tree)//非递归后续遍历。
{
	if (tree == NULL)
	{
		return;
	}
	stack<stkNode> st;
	st.push(tree);
	while (!st.empty())
	{
		stkNode stk = st.top();
		st.pop();
		if (++stk.num == 3)
		{
			cout << stk.node->data << " ";
		}
		else
		{
			st.push(stk);
			if (stk.num == 1 && stk.node->leftchild != NULL)
			{
				st.push(stk.node->leftchild);
			}
			else if (stk.num == 2 && stk.node->rightchild != NULL)
			{
				st.push(stk.node->rightchild);
			}
		}
	}
	cout << endl;
}

四、层次遍历

所谓层次遍历就是按照每一层依次取打印;

第一步:先利用递归的思想打印第k层;

第二步:求树的深度;

第三步:循环打印每一层;

int GetDepth(BtNode *tree)//层次遍历中--获得深度
{
	if (tree == NULL)
	{
		return 0;
	}
	else
	{
		return max(GetDepth(tree->leftchild), GetDepth(tree->rightchild)) + 1;
	}

}

void Level_Order_K(BtNode *tree, int k)//第k层的遍历
{
	if (!tree||k<0) return ;
	if (k == 0)
	{
		cout << tree->data<<" ";
	}
	if (k>0)
	{
		Level_Order_K(tree->leftchild, k - 1);
		Level_Order_K(tree->rightchild, k - 1);
	}
}


void Level_Print(BtNode* tree)//所有层的打印
{
	int depth = GetDepth(tree);
	for (int i = 0; i < depth; i++)
	{
		Level_Order_K(tree, i);
		cout << endl;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值