数据结构--4.1 二叉树的创建与遍历

本文详细介绍了二叉树的创建,包括结构体定义、初始化和子树构造,并展示了如何将字符串转化为二叉树。此外,还探讨了二叉树的层次遍历、前序遍历、中序遍历和后序遍历的实现,以及相应的测试代码和运行结果。这些遍历方法利用了栈和队列的数据结构,体现了递归和队列的思想。
摘要由CSDN通过智能技术生成

二叉树的创建

结构体定义

#include <stdio.h>
#include <malloc.h>

#define QUEUE_SIZE 5

typedef struct BTNode{
	char element;
	BTNode* left;//左儿子 
	BTNode* right;//右儿子 
}BTNode,*BTNODE;

typedef struct BTNodePtrQueue{
	BTNODE* nodePtr;
	int front;
	int rear;
}BTNodePtrQueue,*QUEUE;

初始化

QUEUE initQueue() 
{
	QUEUE resultPtr = (QUEUE)malloc(sizeof(BTNodePtrQueue));
	resultPtr->nodePtr = (BTNODE*)malloc(QUEUE_SIZE*sizeof(BTNODE));
	resultPtr->front = 0;
	resultPtr->rear = 1;
	return resultPtr;
}//初始化二叉树 

创建子树

BTNODE constructBTNode(char paraChar)
{
	BTNODE resultPtr = (BTNODE)malloc(sizeof(BTNode));
	resultPtr->element = paraChar;
	resultPtr->left = NULL;
	resultPtr->right = NULL;
	return resultPtr;
} //创建子树

字符串转化为二叉树``

这里使用的是顺序结构存储,就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储,二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。
从字符串转化为二叉树,就是先询问用户根节点是谁,然后每次都询问某个节点的左孩子是谁,右孩子是谁。如图:
在这里插入图片描述
在这里插入图片描述
代码如下:

BTNODE stringToBTree(char* paraString)
{
	int i;
	char ch;
	
	QUEUE tempQueue = initQueue();
	
	BTNODE resultHead;
	BTNODE tempPa,tempLc,tempRc;
	i = 0;
	ch = paraString[i];
	resultHead = constructBTNode(ch);
	enQueue(tempQueue,resultHead);
	
	while(!is_empty(tempQueue))
	{
		tempPa = deQueue(tempQueue);
		
		i++;
		ch = paraString[i];
		if(ch == '#')
		{
			tempPa->left = NULL;
		}else
		{
			tempLc = constructBTNode(ch);
			enQueue(tempQueue,tempLc);
			tempPa->left = tempLc;
		}
		
		i++;
		ch = paraString[i];
		if(ch == '#')
		{
			tempPa->right = NULL;
		}else
		{
			tempRc = constructBTNode(ch);
			enQueue(tempQueue,tempRc);
			tempPa->right = tempRc;
		}
	}
	
	return resultHead;
}//字符串转化为二叉树

二叉树的遍历

层次遍历

层次遍历从根节点出发,依次访问左右孩子结点,再从左右孩子出发,依次它们的孩子结点,直到节点访问完毕
让我们先看图:
在这里插入图片描述
层次遍历得到的结果是 ABCDEFGHI。
层次遍历和前中后序遍历不同。前中后序遍历利用了递归的思想,而层次遍历体现了队列的思想。
在这里插入图片描述
如上图。层序遍历的思路是,创建一个队列,先将根节点(A)入队,然后再将根节点出队,接下来看刚才的根节有没有左孩子或右孩子,如果有,先左(B)后右(C)入队,最后输出根节点的值,只要队列还不为空,就说明还没有遍历完,就进行下一次循环,这时的队头元素则为刚才入队的左孩子(B),然后出队,再把它的左右孩子拉进来(如果有),因为队列的先进先出性质,B的左右孩子D是排在C后面的,然后输出B,下一次循环将会拉人C的左右孩子EF,一直循环直到没有入队元素,队列变为空,当队列为空时,整颗树就层序遍历完成了,结束循环。
代码如下:

入队:

void enQueue(QUEUE paraQueue,BTNODE paraBTNode)
{
	printf("front = %d,rear = %d\r\n",paraQueue->front,paraQueue->rear);
	if((paraQueue->rear+1)%QUEUE_SIZE == paraQueue->front )
	{
		printf("the queue is full.\r\n");
		return;
	}
	paraQueue->nodePtr[paraQueue->rear] = paraBTNode;
	paraQueue->rear = (paraQueue->rear+1)%QUEUE_SIZE;
	printf("enqueue %c ends.\r\n",paraBTNode->element);
}//添加子节点

出队

BTNODE deQueue(QUEUE paraQueue)
{
	if(is_empty(paraQueue))
	{
		printf("can not delete,the queue is empty.\r\n");
		return NULL;
	}
	
	paraQueue->front = (paraQueue->front+1)%QUEUE_SIZE;
	
	printf("dequeue %c end.\r\n",paraQueue->nodePtr[paraQueue->front]->element);
	
	return paraQueue->nodePtr[paraQueue->front];
} //删除子节点

主要循环过程:

void levelwise(BTNODE paraTree)
{
	char tempString[100];
	int i = 0;
	QUEUE tempQueue = initQueue();
	BTNODE tempNode;
	enQueue(tempQueue,paraTree);
	
	while(!is_empty(tempQueue))
	{
		tempNode = deQueue(tempQueue);
		
		tempString[i] = tempNode->element;
		i++;
		
		if(tempNode->left!= NULL)
		{
			enQueue(tempQueue,tempNode->left);
		}
		if(tempNode->right != NULL)
		{
			enQueue(tempQueue,tempNode->right);
		}
	}
	tempString[i] = '\0';
	
	printf("Levelwise: %s\r\n",tempString);
}//层次遍历

前中后序遍历

在一颗二叉树中,我们将树根作为中间,然后分别是左子树和右子树。前,中,后序遍历也就是依次将根放到最开始,中间和最后进行的遍历方式。
前序遍历就是按照中左右的顺序遍历整个二叉树。例如下图中的二叉树

在这里插入图片描述
从前序遍历的话,我们从根出发,也就是A,接着到左子树B,然后把B当作新的根,接下来就是D,完了是E,E结束之后轮到以D为根的右子树H,这样B这整个左子树就遍历完了,然后我们再从C开始遍历右子树,依旧是中左右的顺序。
这样下来我们得到的结果就是: ABDGHCEIF。

那中序遍历是按照左中右的顺序遍历整个二叉树,道理和前序遍历一样,我们直接看图吧:
在这里插入图片描述
我们可以看到,中序遍历的时候我们从最左边接着是最下面作为起点开始遍历,得到的结果也就是: CDHBAEICF。

那同理我们也可以得到后序遍历:也就是以左右中的方式,将根放到最后来进行遍历。如图:
在这里插入图片描述
得到的结果是:GHDBIEFCA。

代码如下:

void preorder(BTNODE tempPtr)
{
	if(tempPtr == NULL)
	{
		return;
	}

	printf("%c",tempPtr->element);
	preorder(tempPtr->left);
	preorder(tempPtr->right);
}//前序遍历 

void inorder(BTNODE tempPtr)
{
	if(tempPtr == NULL)
	{
		return;
	}

	inorder(tempPtr->left);
	printf("%c",tempPtr->element);
	inorder(tempPtr->right);
}//中序遍历

void postorder(BTNODE tempPtr)
{
	if(tempPtr == NULL)
	{
		return;
	}

	postorder(tempPtr->left);
	postorder(tempPtr->right);
	printf("%c",tempPtr->element);
}//后序遍历

测试代码

int main(){
	BTNODE tempHeader;
	tempHeader = constructBTNode('c');
	printf("There is only one node. Preorder visit: ");
	preorder(tempHeader);
	printf("\r\n");

	char* tempString = "acde#bf######";

	tempHeader = stringToBTree(tempString);
	printf("Preorder: ");
	preorder(tempHeader);
	printf("\r\n");
	printf("Inorder: ");
	inorder(tempHeader);
	printf("\r\n");
	printf("Postorder: ");
	postorder(tempHeader);
	printf("\r\n");
	printf("Levelwise: ");
	levelwise(tempHeader);
	printf("\r\n");

	return 1;
} 

运行结果

There is only one node. Preorder visit: c
front = 0,rear = 1
enqueue a ends.
dequeue a end.
front = 1,rear = 2
enqueue c ends.
front = 1,rear = 3
enqueue d ends.
dequeue c end.
front = 2,rear = 4
enqueue e ends.
dequeue d end.
front = 3,rear = 0
enqueue b ends.
front = 3,rear = 1
enqueue f ends.
dequeue e end.
dequeue b end.
dequeue f end.
Preorder: acedbf
Inorder: ecabdf
Postorder: ecbfda
Levelwise: front = 0,rear = 1
enqueue a ends.
dequeue a end.
front = 1,rear = 2
enqueue c ends.
front = 1,rear = 3
enqueue d ends.
dequeue c end.
front = 2,rear = 4
enqueue e ends.
dequeue d end.
front = 3,rear = 0
enqueue b ends.
front = 3,rear = 1
enqueue f ends.
dequeue e end.
dequeue b end.
dequeue f end.
Levelwise: acdebf

总结

在二叉树的创建与遍历的时候,我们都用到了之前学过的栈和队列那一部分的知识。
在二叉树的遍历中,用到了递归算法的思想,递归实现的本质也是系统帮我们建立了栈结构,而系统栈需要记住每个节点的值,所以空间复杂度仍为O(N),时间复杂度也为O(N)。

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值