赞
踩
树是一种非线性的数据结构,它是由n(n >= 0)
个有限结点组成一个具有层次关系的集合T
。如果n = 0
,称为空树。如果n > 0
,则T
满足以下两个条件:①有且仅有一个根结点;②其他结点划分为m(m >= 0)
个互不相交的有限集合T1 ,T2 ,…… ,Tm,其中每个集合又是一棵树,并且称之为根的子树。
0
个或多个直接后继(其每棵子树的根结点),但没有直接前驱。0
个或多个直接后继。结点的度:
结点拥有的子树数目称为结点的度
结点的关系:
结点子树的根结点为该结点的孩子结点。相应该结点称为孩子结点的双亲结点。
下图中,A为B的双亲结点,B为A的孩子结点。
同一个双亲结点的孩子结点之间互称兄弟结点。
下图中,结点B与结点C互为兄弟结点。
结点层次:
从根开始定义,根为第一层,根的孩子为第二层,以此类推,如下图。
森林:
互不相交的树的集合称为森林。森林和树间的联系:一棵树去掉根,其子树构成一片森林;一片森林增加一个根结点就成了一棵树。
二叉树(Binary Tree)是n(n >= 0)
个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。
1. 斜树
所有结点都只有左子树的二叉树叫左斜树。所有结点都只有右子树的二叉树叫右斜树发,两者统称为斜树。
2. 满二叉树
在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。
3. 完全二叉树
对一棵具有n
个结点的二叉树按层序编号,如果编号为i(1 <= i <= n)
的结点与同样深度的满二叉树中编号为i
的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树。
1. 在二叉树的第i
层至多有2i-1个结点(i >= 1)
。
2. 深度为k
的二叉树至多有2k-1个结点(k >= 1)
。
3. 对任何一棵二叉树T
,如果其终端结点数为n0,度为2
的结点数为n2,则n0 = n2 + 1。
4. 具有n
个结点的完全二叉树的深度为 ⌊ l o g2 n ⌋ + 1 。
5. 如果对一棵 有n
个结点的完全二叉树(其深度为⌊ l o g2 n ⌋ + 1)的结点按层序编号(从第1
层到第⌊ l o g2 n ⌋ + 1层,每层从左到右),对任一结点i(1 <= i <= n)
有:
( 1 )如果i = 1
,则结点i
是二叉树的根,无双亲;如果i > 1
,则其双亲是结点 ⌊i / 2⌋
。
( 2 )如果2i > n
,则结点i
无左孩子(结点i
为叶子结点);否则其左孩子是结点2i
。
( 3 )如果2i + 1 > n
,则结点i
无右孩子;否则其右孩子是结点2i + 1
。
二叉树结构体定义
/* 二叉树结点 */ typedef char ElemType; typedef struct BTNode { ElemType 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(BTNodePtrQueue));
resultQueuePtr->nodePtrs = (BTNodePtr*)malloc(sizeof(BTNodePtr) * QUEUE_SIZE);
resultQueuePtr->front = 0;
resultQueuePtr->rear = 1;
return resultQueuePtr;
}
判断队列是否为空
/* 判断队列是否为空 */
bool isQueueEmpty(QueuePtr tempQueuePtr)
{
if((tempQueuePtr->front + 1) % QUEUE_SIZE == tempQueuePtr->rear)
{
return true;
}
return false;
}
结点入队
/* 结点入队 */
void Enqueue(QueuePtr tempQueuePtr, BTNodePtr tempBTNodePtr)
{
printf("front = %d, rear = %d.\n",tempQueuePtr->front,tempQueuePtr->rear);
if((tempQueuePtr->rear + 1) % QUEUE_SIZE == tempQueuePtr->front % QUEUE_SIZE)
{
printf("错误,%c入队失败:队列已满\n",tempBTNodePtr->element);
return ;
}
tempQueuePtr->nodePtrs[tempQueuePtr->rear] = tempBTNodePtr;
tempQueuePtr->rear = (tempQueuePtr->rear + 1) % QUEUE_SIZE;
printf("%c入队结束\n",tempBTNodePtr->element);
}
结点出队
/* 结点出队 */
BTNodePtr Dequeue(QueuePtr tempQueuePtr)
{
if(isQueueEmpty(tempQueuePtr))
{
printf("错误:队列为空\n");
return NULL;
}
tempQueuePtr->front = (tempQueuePtr->front + 1) % QUEUE_SIZE;
printf("%c出队结束\n",tempQueuePtr->nodePtrs[tempQueuePtr->front]->element);
return tempQueuePtr->nodePtrs[tempQueuePtr->front];
}
构造二叉树结点
/* 构造二叉树结点 */
BTNodePtr constructBTNode(ElemType tempElement)
{
BTNodePtr resultPtr = (BTNodePtr)malloc(sizeof(BTNode));
resultPtr->element = tempElement;
resultPtr->left = NULL;
resultPtr->right = NULL;
return resultPtr;
}
将字符串转换为二叉树
/* 将字符串转换为二叉树 */ BTNodePtr stringToBTree(char* tempString) { QueuePtr tempQueuePtr = initQueue(); BTNodePtr resultHeader; BTNodePtr tempParent, tempLeftChild, tempRightChild; int i = 0; char ch = tempString[i]; resultHeader = constructBTNode(ch); Enqueue(tempQueuePtr, resultHeader); while (!isQueueEmpty(tempQueuePtr)) { tempParent = Dequeue(tempQueuePtr); ++i; ch = tempString[i]; if(ch == '#') { tempParent->left = NULL; }else{ tempLeftChild = constructBTNode(ch); Enqueue(tempQueuePtr, tempLeftChild); tempParent->left = tempLeftChild; } ++i; ch = tempString[i]; if(ch == '#') { tempParent->right = NULL; }else{ tempRightChild = constructBTNode(ch); Enqueue(tempQueuePtr, tempRightChild); tempParent->right = tempRightChild; } } return resultHeader; }
二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次。
1. 前序遍历
若二叉树为空,则空操作返回;否则先访问根结点,然后前序遍历左子树,再前序遍历右子树。如下图所示,遍历顺序为ABDGHCEIF
。
前序遍历算法
/* 前序遍历 */
void preorder(BTNodePtr tempPtr)
{
if(tempPtr == NULL)
{
return ;
}
printf("%c",tempPtr->element);
preorder(tempPtr->left);
preorder(tempPtr->right);
}
2. 中序遍历
若二叉树为空,则空操作返回;否则从根结点开始(注意并不是先访问根结点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树。如下图所示,遍历顺序为GDHBAEICF
。
中序遍历算法
/* 中序遍历 */
void inorder(BTNodePtr tempPtr)
{
if(tempPtr == NULL)
{
return ;
}
inorder(tempPtr->left);
printf("%c",tempPtr->element);
inorder(tempPtr->right);
}
3. 后序遍历
若二叉树为空,则空操作返回;否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根结点。如下图所示,遍历顺序为GHDBIEFCA
。
后序遍历算法
/* 后序遍历 */
void postorder(BTNodePtr tempPtr)
{
if(tempPtr == NULL)
{
return ;
}
postorder(tempPtr->left);
postorder(tempPtr->right);
printf("%c",tempPtr->element);
}
4. 层序遍历
若二叉树为空,则空操作返回;否则从树的第一层,也就是根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问。如下图所示,遍历顺序为ABCDEFGHI
。
层序遍历算法
/* 层序遍历 */ void levelWise(BTNodePtr tempTreePtr) { char tempString[100]; int i = 0; QueuePtr tempQueuePtr = initQueue(); BTNodePtr tempNodePtr; Enqueue(tempQueuePtr, tempTreePtr); while(!isQueueEmpty(tempQueuePtr)) { tempNodePtr = Dequeue(tempQueuePtr); tempString[i] = tempNodePtr->element; ++i; if(tempNodePtr->left != NULL) { Enqueue(tempQueuePtr, tempNodePtr->left); } if(tempNodePtr->right != NULL) { Enqueue(tempQueuePtr, tempNodePtr->right); } } tempString[i] = '\0'; printf("层序遍历:%s\n",tempString); }
完整代码
#include <stdio.h> #include <malloc.h> #define QUEUE_SIZE 5 /* 二叉树结点 */ typedef char ElemType; typedef struct BTNode { ElemType 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(BTNodePtrQueue)); resultQueuePtr->nodePtrs = (BTNodePtr*)malloc(sizeof(BTNodePtr) * QUEUE_SIZE); resultQueuePtr->front = 0; resultQueuePtr->rear = 1; return resultQueuePtr; } /* 判断队列是否为空 */ bool isQueueEmpty(QueuePtr tempQueuePtr) { if((tempQueuePtr->front + 1) % QUEUE_SIZE == tempQueuePtr->rear) { return true; } return false; } /* 结点入队 */ void Enqueue(QueuePtr tempQueuePtr, BTNodePtr tempBTNodePtr) { printf("front = %d, rear = %d.\n",tempQueuePtr->front,tempQueuePtr->rear); if((tempQueuePtr->rear + 1) % QUEUE_SIZE == tempQueuePtr->front % QUEUE_SIZE) { printf("错误,%c入队失败:队列已满\n",tempBTNodePtr->element); return ; } tempQueuePtr->nodePtrs[tempQueuePtr->rear] = tempBTNodePtr; tempQueuePtr->rear = (tempQueuePtr->rear + 1) % QUEUE_SIZE; printf("%c入队结束\n",tempBTNodePtr->element); } /* 结点出队 */ BTNodePtr Dequeue(QueuePtr tempQueuePtr) { if(isQueueEmpty(tempQueuePtr)) { printf("错误:队列为空\n"); return NULL; } tempQueuePtr->front = (tempQueuePtr->front + 1) % QUEUE_SIZE; printf("%c出队结束\n",tempQueuePtr->nodePtrs[tempQueuePtr->front]->element); return tempQueuePtr->nodePtrs[tempQueuePtr->front]; } /* 构造二叉树结点 */ BTNodePtr constructBTNode(ElemType tempElement) { BTNodePtr resultPtr = (BTNodePtr)malloc(sizeof(BTNode)); resultPtr->element = tempElement; resultPtr->left = NULL; resultPtr->right = NULL; return resultPtr; } /* 将字符串转换为二叉树 */ BTNodePtr stringToBTree(char* tempString) { QueuePtr tempQueuePtr = initQueue(); BTNodePtr resultHeader; BTNodePtr tempParent, tempLeftChild, tempRightChild; int i = 0; char ch = tempString[i]; resultHeader = constructBTNode(ch); Enqueue(tempQueuePtr, resultHeader); while (!isQueueEmpty(tempQueuePtr)) { tempParent = Dequeue(tempQueuePtr); ++i; ch = tempString[i]; if(ch == '#') { tempParent->left = NULL; }else{ tempLeftChild = constructBTNode(ch); Enqueue(tempQueuePtr, tempLeftChild); tempParent->left = tempLeftChild; } ++i; ch = tempString[i]; if(ch == '#') { tempParent->right = NULL; }else{ tempRightChild = constructBTNode(ch); Enqueue(tempQueuePtr, tempRightChild); tempParent->right = tempRightChild; } } return resultHeader; } /* 层序遍历 */ void levelWise(BTNodePtr tempTreePtr) { char tempString[100]; int i = 0; QueuePtr tempQueuePtr = initQueue(); BTNodePtr tempNodePtr; Enqueue(tempQueuePtr, tempTreePtr); while(!isQueueEmpty(tempQueuePtr)) { tempNodePtr = Dequeue(tempQueuePtr); tempString[i] = tempNodePtr->element; ++i; if(tempNodePtr->left != NULL) { Enqueue(tempQueuePtr, tempNodePtr->left); } if(tempNodePtr->right != NULL) { Enqueue(tempQueuePtr, tempNodePtr->right); } } tempString[i] = '\0'; printf("层序遍历:%s\n",tempString); } /* 前序遍历 */ void preorder(BTNodePtr tempPtr) { if(tempPtr == NULL) { return ; } printf("%c",tempPtr->element); preorder(tempPtr->left); preorder(tempPtr->right); } /* 中序遍历 */ void inorder(BTNodePtr tempPtr) { if(tempPtr == NULL) { return ; } inorder(tempPtr->left); printf("%c",tempPtr->element); inorder(tempPtr->right); } /* 后序遍历 */ void postorder(BTNodePtr tempPtr) { if(tempPtr == NULL) { return ; } postorder(tempPtr->left); postorder(tempPtr->right); printf("%c",tempPtr->element); } void test() { BTNodePtr tempHeader; tempHeader = constructBTNode('c'); printf("只有一个结点.前序遍历:\n"); preorder(tempHeader); printf("\n"); char* tempString = "acde#bf######"; tempHeader = stringToBTree(tempString); printf("前序遍历:"); preorder(tempHeader); printf("\n"); printf("中序遍历:"); inorder(tempHeader); printf("\n"); printf("后序遍历:"); postorder(tempHeader); printf("\n"); printf("层序遍历:"); levelWise(tempHeader); printf("\n"); return ; } int main(){ test(); return 0; }
测试结果
只有一个结点.前序遍历: c front = 0, rear = 1. a入队结束 a出队结束 front = 1, rear = 2. c入队结束 front = 1, rear = 3. d入队结束 c出队结束 front = 2, rear = 4. e入队结束 d出队结束 front = 3, rear = 0. b入队结束 front = 3, rear = 1. f入队结束 e出队结束 b出队结束 f出队结束 前序遍历:acedbf 中序遍历:ecabdf 后序遍历:ecbfda 层序遍历:front = 0, rear = 1. a入队结束 a出队结束 front = 1, rear = 2. c入队结束 front = 1, rear = 3. d入队结束 c出队结束 front = 2, rear = 4. e入队结束 d出队结束 front = 3, rear = 0. b入队结束 front = 3, rear = 1. f入队结束 e出队结束 b出队结束 f出队结束 层序遍历:acdebf
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。