二叉树的遍历(递归以及非递归)

递归

1.先序遍历(根左右)

void BinaryTreePrevOrder(BTNode* root) //先序遍历 根左右 (递归)
{
	if (root)
	{
		putchar(root->data);//打印根节点
		BinaryTreePrevOrder(root->lchild);
		BinaryTreePrevOrder(root->rchild);
	}	
}

2.中序遍历 (左根右)

void BinaryTreeInOrder(BTNode* root) //中序遍历 左根右 (递归)
{
	if (root)
	{
		BinaryTreeInOrder(root->lchild);
		putchar(root->data);
		BinaryTreeInOrder(root->rchild);
	}
	
}

3.后序遍历(左右根)

void BinaryTreePostOrder(BTNode* root)//后序遍历  左右根 (递归)
{
	if (root)
	{
		BinaryTreePostOrder(root->lchild);
		BinaryTreePostOrder(root->rchild);
		putchar(root->data);
		
	}
}

非递归(需要用到栈来实现)

需要用到的栈的代码

void StackInit(Stack* psl, size_t capicity)
{
	assert(psl);
	psl->capicity = capicity;
	psl->array = (SLDataType *)malloc(capicity * sizeof(SLDataType));
	assert(psl->array);

	psl->size = 0;
}
void StackDestory(Stack* psl)
{
	assert(psl);
	if (psl->array)
	{
		free(psl->array);
		psl->array = NULL;
		psl->size = 0;
		psl->capicity = 0;
	}
}
void CheckCapacity(Stack* psl)
{
	assert(psl);
	if (psl->size == psl->capicity)
	{
		psl->capicity *= 2;
		psl->array = (SLDataType *)realloc(psl->array, psl->capicity * sizeof(SLDataType));

	}
}
void StackPush(Stack* psl, SLDataType x)
{
	assert(psl);
	CheckCapacity(psl);

	psl->array[psl->size] = x;
	psl->size++;
}
void StackPop(Stack* psl)
{
	assert(psl || psl->size);
	psl->size--;

}
SLDataType StackTop(Stack* psl)
{
	if (StackIsEmpty(psl))
	{
		return (SLDataType)0;
	}
	return psl->array[psl->size - 1];
}
int StackIsEmpty(Stack * psl)
{
	return psl->size == 0;
}


1.先序遍历 

(1)、打印当前节点

(2)、如果它有右孩子就将齐入栈

(3)、如果它有左孩子就访问左孩子,如果没有,就访问栈顶。

void BinaryTreePrevOrderNonR(BTNode* root) // 先序遍历   (非递归)
{
	Stack st;
	BTNode * cur = root;
	StackInit(&st, 100); //初始化栈
	while (cur) 
	{
		putchar(cur->data); //打印当前根节点的值
		if (cur->rchild) //右孩子存在
		{
			StackPush(&st, cur->rchild); //右孩子入栈
		}
		if (cur->lchild) //左孩子存在
		{
			cur = cur->lchild; //根节点为左孩子
		}
		else//没有左孩子取栈顶
		{
			cur = StackTop(&st); //取到空时,遍历结束
			StackPop(&st); //出栈
		}
	}
	StackDestory(&st);
}

2.中序遍历

(1)、从当前节点开始遍历左子树,将所有的节点入栈,直到左子树为空

(2)、取出并打印栈顶,访问它的右孩子,如果右孩子,重复过程1,如果没有右孩子,重复过程2

void BinaryTreeInOrderNonR(BTNode* root) //中序遍历  (非递归)
{
	Stack st;
	BTNode* cur = root;
	StackInit(&st,100);
	while (cur || !StackIsEmpty(&st))//(1)
	{
		for (; cur; cur = cur->lchild)//将当前节点及左孩子入栈 (链表遍历)
		{
			StackPush(&st, cur);
		}
		    cur = StackTop(&st);//取出栈顶 (1、右孩子为空,for循环不进直接取栈顶。
			//2、如果右孩子不为空,那么这是一个没有左孩子的节点。
			//第一种情况是左子树访问完毕,第二种情况是右子树为空。
			//无论哪种,当前节点都要打印。)
			/*if (!cur )
			{
			break;
			}*/
			putchar(cur->data);
			StackPop(&st);
			cur = cur->rchild;
		
	}
	StackDestory(&st);
}

3.后序遍历

LT = 左子树访问标记,即代码中tag数组

(1)、从当前节点开始遍历左子树,将所有节点入栈,且清空LT标记,直到左子树为空,然后就进入过程2

(2)、访问栈顶,置位它的LT标记,访问它的右子树,如果右子树存在,重复过程1,如果右子树不存在,进入过程3

(3)、取出栈顶,打印,然后检测它的父节点的LT是否也被置位,如果是,则一并打印,直到找到第一个LT标记为清空状态的节点位置,然后返回到过程2

void BinaryTreePostOrderNonR(BTNode* root)//后序遍历  (非递归)
{
	char tag[64];
	Stack st;
	BTNode* cur = root;
	StackInit(&st, 100);

	do
	{
		for (; cur; cur = cur->lchild)//将当前节点及左孩子入栈 (链表遍历)
		{
			StackPush(&st, cur);//左孩子入栈
			tag[st.size - 1] = 0;//重置左子树访问标记(LT)
		}
		while (!StackIsEmpty(&st)&&tag[st.size - 1])//栈不为空并且标记为1 
			//前面的条件只在最后一次循环跳出时生效
			//后面的条件分两种情况
			//1、当cur为空时,上面的for不进,此条件成立。
			//2、当cur不为空,上面的for进,此条件不成立。
			//如果检测到当前的LT被置位,那么在打印完当前节点后,再去直接检查上一个节点(父节点)也要被打印了
		{
			cur = StackTop(&st); //取栈顶
			putchar(cur->data);//打印
			StackPop(&st);//出栈
		}
		if (!StackIsEmpty(&st))//栈不为空 //此条件只在最后一次循环跳出时生效
		{
			cur = StackTop(&st);//取栈顶
			//1、如果上面的while进了,那么证明左子树访问完毕,给LT置位
			//2、如果上面的while没进,那么证明左子树不存在,给LT置位
			tag[st.size - 1] = 1;//标记改为1
			cur = cur->rchild; //取右孩子
			//左子树访问完毕后,访问右子树
		}
			//
	} while (!StackIsEmpty(&st));//由于后序遍历中根节点最后出栈前,栈不可能为空,所以以根节点是否为空判断
	StackDestory(&st);
}

4.层序遍历 (需要队列的辅助来实现)

有关队列的代码

void QueueInit(Queue* plist)
{
	assert(plist);
	plist->_head = NULL;
	plist->_rear = NULL;

}
void QueueDestory(Queue* plist)
{
	QueueNode * tmp;
	while (plist->_head)
	{
		tmp = plist->_head;
		plist->_head = plist->_head->_next;
		free(tmp);
	}
}

void QueuePop(Queue* plist)
{
	assert(plist);
	QueueNode * tmp;
	if (plist->_head)
	{
		tmp = plist->_head;
		plist->_head = plist->_head->_next;
		free(tmp);
	}
}
void QueuePush(Queue* plist, QuDataType x)
{
	QueueNode * cur = (QueueNode *)malloc(sizeof(QueueNode));
	cur->_data = x;
	cur->_next = NULL;
	if (QueueIsEmpty(plist))
	{
		plist->_head = plist->_rear = cur;
		return;
	}
	plist->_rear->_next = cur;
	plist->_rear = cur;
}

int QueueIsEmpty(Queue * plist)
{
	return plist->_head == NULL;
}
QuDataType QueueTop(Queue *plist)
{
	if (QueueIsEmpty(plist))
	{
		return (QuDataType)0;
	}
	return plist->_head->_data;
}

层序遍历的实现

先将根入列

(1)、取队顶打印

(2)、如果它有左孩子就入队左孩子,如果它有右孩子就入队右孩子

(3)、队顶出队

void BinaryTreeLeveorder(BTNode* root)//层序遍历
{
	Queue qu;
	BTNode * cur;
	QueueInit(&qu);//初始化队列
	QueuePush(&qu, root);//入队列
	while (!QueueIsEmpty(&qu))//队列不为空
	{
		cur = QueueTop(&qu); //cur 等于队列头
		putchar(cur->data); //输出cur
		if (cur->lchild) // 左孩子存在
		{
			QueuePush(&qu, cur->lchild);//左孩子入队列
		}
		if (cur->rchild)//右孩子存在
		{
			QueuePush(&qu, cur->rchild); //右孩子入队列
		}
		QueuePop(&qu);//队头元素出队列
	}
	QueueDestory(&qu);//销毁
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
叉树归算法是指在不使用归的情况下,实现对二叉树的遍。常用的归算法有三种:归前序遍归中序遍归后序遍。 以下是三种归遍叉树的算法: 1. 归前序遍叉树 ```c void preOrderNRec(Tree root){ Tree stack[MAXSIZE], node; int k = -1; if (root == NULL){ printf("tree is empty-- \n"); return; } else{ k++; // 仿照一个栈 stack[k] = root; // 将根节点入栈 while (k > -1){ //出栈 node = stack[k--]; printf(" %c - ", node->data); // 先把右子树放进去,栈是先进去后出,所以下面的左子树先出 if (node->right != NULL){ stack[++k] = node->right; } if (node->left != NULL){ stack[++k] = node->left; } } } } ``` 2. 归中序遍叉树 ```c void inOrderNRec(Tree root){ Tree stack[MAXSIZE], node; int k = -1; if (root == NULL){ printf("tree is empty-- \n"); return; } else{ node = root; while (k > -1 || node != NULL){ while (node != NULL){ stack[++k] = node; node = node->left; } if (k > -1){ node = stack[k--]; printf(" %c - ", node->data); node = node->right; } } } } ``` 3. 归后序遍叉树 ```c void postOrderNRec(Tree root){ Tree stack[MAXSIZE], node, lastVisit; int k = -1; if (root == NULL){ printf("tree is empty-- \n"); return; } else{ node = root; while (k > -1 || node != NULL){ while (node != NULL){ stack[++k] = node; node = node->left; } node = stack[k]; if (node->right == NULL || node->right == lastVisit){ printf(" %c - ", node->data); lastVisit = node; k--; node = NULL; } else{ node = node->right; } } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值