1.简介
对于二叉树的遍历,有四种方式:层序输出,前序输出,中序输出,后序输出。但不论利用何种输出方式对二叉树进行遍历,其前提为必须提前已知一颗树。那么什么叫做已知一颗树呢?
所谓已知一棵树的意思即为:已经用数据结构定义好的树,通过该树可以知道哪个节点是根;哪个节点是左儿子,右儿子;哪个节点是左儿子的左右儿子等等这样的信息。在本文中,我们把得到这个已知树的过程称之为创建一颗树。
2.四种遍历方式示意图
3.如何构建一颗已知二叉树
利用层序输入的策略构建二叉树相对比较方便。当然也可以通过其他手段构建二叉树,但相对会比较麻烦,该种策略是最容易理解的。后续的实例中会介绍另外一种构建策略。
4.创建二叉树并遍历输出实例
比如我们在笔试的过程中会遇到的题目:已知一颗树的前序遍历和中序遍历,输出二叉树的层序遍历。该类题目的策略就是通过树的前序遍历和中序遍历来创建一颗已知树,并通过创建得到的树进行层序的遍历输出。
解题思路:利用递归的手段通过前序和中序的结果来构建已知树。并利用广度优先的手段遍历输出(就是层序遍历)。之所以可以利用递归,因为当根据前序遍历结果可知,第一位是整颗树的根节点,而根据中序遍历中找到当前这个第一位的index,在中序遍历序列中该index之前和之后的两段被切分成了两颗子树,并且根据这两颗子树的长度可以从前序的列表中切除这两颗子树的前序遍历列表,因此我们发现对于每一个节点的操作一致,且最终的终止条件为最原始的前序为空时递归结束。
5.二叉树的性质
在二叉树的第i层上最多有2 i-1 个节点 。(i>=1)
二叉树中如果深度为k,那么最多有2k-1个节点。(k>=1)
.n0=n2+1 n0表示度数为0的节点 n2表示度数为2的节点。
完全二叉树中,具有n个节点的完全二叉树的深度为[log2n]+1,其中[log2n]+1是向下取整。
若对含 n 个结点的完全二叉树从上到下且从左至右进行 1 至 n 的编号,则对完全二叉树中任意一个编号为 i 的结点:
(1) 若 i=1,则该结点是二叉树的根,无双亲, 否则,编号为 [i/2] 的结点为其双亲结点;
(2) 若 2i>n,则该结点无左孩子, 否则,编号为 2i 的结点为其左孩子结点;
(3) 若 2i+1>n,则该结点无右孩子结点, 否则,编号为2i+1 的结点为其右孩子结点。
6.
二叉树的遍历
3.1 前序遍历
1.首先访问根节点。
2.其次前序访问左子树。
3.最后前序访问右子树。
3.2 中序遍历
1.先中序遍历左子树。
2.然后是根结点。
3.然后中序遍历右子树。
3.3 后序遍历
1.后序遍历左子树。
2.后序遍历右子树。
3.然后访问根节点。
3.4 层次遍历
逐层从左到右访问二叉树结点。
代码
#include <stdio.h>
#include <malloc.h>
#define QUEUE_SIZE 5
typedef struct BTNode{
char element;
BTNode* left;
BTNode* right;
}BTNode, *BTNodePtr;
typedef struct BTNodePtrQueue{
BTNodePtr* nodePtrs;
int front;
int rear;
}BTNodePtrQueue, *QueuePtr;
QueuePtr initQueue(){
QueuePtr resultQueuePtr = (QueuePtr)malloc(sizeof(struct BTNodePtrQueue));
resultQueuePtr->nodePtrs = (BTNodePtr*)malloc(QUEUE_SIZE * sizeof(BTNodePtr));
resultQueuePtr->front = 0;
resultQueuePtr->rear = 1;
return resultQueuePtr;
}
bool isQueueEmpty(QueuePtr paraQueuePtr){
if ((paraQueuePtr->front + 1) % QUEUE_SIZE == paraQueuePtr->rear) {
return true;
}
return false;
}
void enqueue(QueuePtr paraQueuePtr, BTNodePtr paraBTNodePtr){
printf("front = %d, rear = %d.\r\n", paraQueuePtr->front, paraQueuePtr->rear);
if ((paraQueuePtr->rear + 1) % QUEUE_SIZE == paraQueuePtr->front % QUEUE_SIZE) {
printf("Error, trying to enqueue %c. queue full.\r\n", paraBTNodePtr->element);
return;
}
paraQueuePtr->nodePtrs[paraQueuePtr->rear] = paraBTNodePtr;
paraQueuePtr->rear = (paraQueuePtr->rear + 1) % QUEUE_SIZE;
printf("enqueue %c ends.\r\n", paraBTNodePtr->element);
}
BTNodePtr dequeue(QueuePtr paraQueuePtr){
if (isQueueEmpty(paraQueuePtr)) {
printf("Error, empty queue\r\n");
return NULL;
}
paraQueuePtr->front = (paraQueuePtr->front + 1) % QUEUE_SIZE;
printf("dequeue %c ends.\r\n", paraQueuePtr->nodePtrs[paraQueuePtr->front]->element);
return paraQueuePtr->nodePtrs[paraQueuePtr->front];
}
BTNodePtr constructBTNode(char paraChar){
BTNodePtr resultPtr = (BTNodePtr)malloc(sizeof(BTNode));
resultPtr->element = paraChar;
resultPtr->left = NULL;
resultPtr->right = NULL;
return resultPtr;
}
BTNodePtr stringToBTree(char* paraString){
int i;
char ch;
QueuePtr tempQueuePtr = initQueue();
BTNodePtr resultHeader;
BTNodePtr tempParent, tempLeftChild, tempRightChild;
i = 0;
ch = paraString[i];
resultHeader = constructBTNode(ch);
enqueue(tempQueuePtr, resultHeader);
while(!isQueueEmpty(tempQueuePtr)) {
tempParent = dequeue(tempQueuePtr);
i ++;
ch = paraString[i];
if (ch == '#') {
tempParent->left = NULL;
} else {
tempLeftChild = constructBTNode(ch);
enqueue(tempQueuePtr, tempLeftChild);
tempParent->left = tempLeftChild;
}
i ++;
ch = paraString[i];
if (ch == '#') {
tempParent->right = NULL;
} else {
tempRightChild = constructBTNode(ch);
enqueue(tempQueuePtr, tempRightChild);
tempParent->right = tempRightChild;
}
}
return resultHeader;
}
void levelwise(BTNodePtr paraTreePtr){
//Use a queue to manage the pointers
char tempString[100];
int i = 0;
QueuePtr tempQueuePtr = initQueue();
BTNodePtr tempNodePtr;
enqueue(tempQueuePtr, paraTreePtr);
while(!isQueueEmpty(tempQueuePtr)) {
tempNodePtr = dequeue(tempQueuePtr);
//For output.
tempString[i] = tempNodePtr->element;
i ++;
if (tempNodePtr->left != NULL){
enqueue(tempQueuePtr, tempNodePtr->left);
}//Of if
if (tempNodePtr->right != NULL){
enqueue(tempQueuePtr, tempNodePtr->right);
}//Of if
}//Of while
tempString[i] = '\0';
printf("Levelwise: %s\r\n", tempString);
}//Of levelwise
void preorder(BTNodePtr tempPtr){
if (tempPtr == NULL){
return;
}//Of if
printf("%c", tempPtr->element);
preorder(tempPtr->left);
preorder(tempPtr->right);
}//Of preorder
void inorder(BTNodePtr tempPtr){
if (tempPtr == NULL) {
return;
}//Of if
inorder(tempPtr->left);
printf("%c", tempPtr->element);
inorder(tempPtr->right);
}//Of inorder
void postorder(BTNodePtr tempPtr){
if (tempPtr == NULL) {
return;
}//Of if
postorder(tempPtr->left);
postorder(tempPtr->right);
printf("%c", tempPtr->element);
}//Of postorder
int main(){
BTNodePtr 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;
}//Of main
结果
There is only one node. Preorder visit: c
front = 0, rear = 1.
enqueue a ends.
dequeue a ends.
front = 1, rear = 2.
enqueue c ends.
front = 1, rear = 3.
enqueue d ends.
dequeue c ends.
front = 2, rear = 4.
enqueue e ends.
dequeue d ends.
front = 3, rear = 0.
enqueue b ends.
front = 3, rear = 1.
enqueue f ends.
dequeue e ends.
dequeue b ends.
dequeue f ends.
Preorder: acedbf
Inorder: ecabdf
Postorder: ecbfda
Levelwise: front = 0, rear = 1.
enqueue a ends.
dequeue a ends.
front = 1, rear = 2.
enqueue c ends.
front = 1, rear = 3.
enqueue d ends.
dequeue c ends.
front = 2, rear = 4.
enqueue e ends.
dequeue d ends.
front = 3, rear = 0.
enqueue b ends.
front = 3, rear = 1.
enqueue f ends.
dequeue e ends.
dequeue b ends.
dequeue f ends.
Levelwise: acdebf
Press any key to continue