目录
以下代码均在内核链表(开源的代码)的基础上实现的。
一、二叉树的创建
1.1.完全二叉树的创建
TreeNode *CreateCompleteTree(int StartNo, int EndNo)
{
TreeNode *pTmpNode = NULL;
pTmpNode = malloc(sizeof(TreeNode));
if (NULL == pTmpNode)
{
return NULL;
}
memset(pTmpNode, 0, sizeof(TreeNode));
pTmpNode->No = StartNo;
pTmpNode->pLeftChild = pTmpNode->pRightChild = NULL;
if (2 * StartNo <= EndNo)
{
pTmpNode->pLeftChild = CreateCompleteTree(2 * StartNo, EndNo);
}
if (2 * StartNo + 1 <= EndNo)
{
pTmpNode->pRightChild = CreateCompleteTree(2 * StartNo + 1, EndNo);
}
return pTmpNode;
}
1.2.非完全二叉树的创建
TreeNode *CreateBTree(void)
{
char TmpData = 0;
TreeNode *pTmpNode = NULL;
scanf(" %c", &TmpData);
if ('#' == TmpData)
{
return NULL;
}
pTmpNode = malloc(sizeof(TreeNode));
if (NULL == pTmpNode)
{
return NULL;
}
memset(pTmpNode, 0, sizeof(TreeNode));
pTmpNode->Data = TmpData;
pTmpNode->pLeftChild = CreateBTree();
pTmpNode->pRightChild = CreateBTree();
return pTmpNode;
}
二、二叉树的递归遍历
2.1.前序遍历
int PreOrderBinTree(TreeNode *pRoot)
{
if (NULL == pRoot)
{
return 0;
}
printf("%d ", pRoot->No);
PreOrderBinTree(pRoot->pLeftChild);
PreOrderBinTree(pRoot->pRightChild);
return 0;
}
2.2.中序遍历
int InOrderBinTree(TreeNode *pRoot)
{
if (NULL == pRoot)
{
return 0;
}
InOrderBinTree(pRoot->pLeftChild);
printf("%d ", pRoot->No);
InOrderBinTree(pRoot->pRightChild);
return 0;
}
2.3.后序遍历
int PostOrderBinTree(TreeNode *pRoot)
{
if (NULL == pRoot)
{
return 0;
}
PostOrderBinTree(pRoot->pLeftChild);
printf("%d ", pRoot->No);
PostOrderBinTree(pRoot->pRightChild);
return 0;
}
三、二叉树的非递归遍历
3.1.前序遍历
先让根节点进栈,打印根节点,再让其左子树的所有左孩子依次进栈并打印,此时让栈顶元素出栈,判断下一个为栈顶元素的是否存在,如存在依次让他的所有左孩子再进栈并打印,依次类推,知道栈内无元素位置,就实现了二叉树的非递归前序遍历。
int PreOrderBinTreeByStack(TreeNode *pRoot)
{
//判断树是否为空
if (pRoot == NULL)
{
return -1;
}
//初始化栈
struct list_head head;
INIT_LIST_HEAD(&head);
//创建栈节点,方便后续树节点进栈
Stack_t *pnewnode = NULL;
Stack_t *pfreenode = NULL;
//创建树节点指针,指向根节点
TreeNode *ptmptreenode = NULL;
ptmptreenode = pRoot;
while (1)
{
while (ptmptreenode != NULL)
{
pnewnode = malloc(sizeof(Stack_t));
if (pnewnode == NULL)
{
return -1;
}
//根节点入栈
pnewnode->data = ptmptreenode;
//打印
printf("%c ", pnewnode->data->data);
//进栈
list_add(&pnewnode->node, &head);
//该左孩子,保存左孩子节点地址,让左孩子都进栈
ptmptreenode = ptmptreenode->pLeftChild;
}
//如果栈空,则结束
if (list_empty(&head))
{
break;
}
//获取栈顶节点的首地址
pfreenode = list_entry(head.next, Stack_t, node);
//让栈顶元素出栈
list_del(&pfreenode->node);
//获取出栈的树节点的右节点
ptmptreenode = pfreenode->data->pRightChild;
free(pfreenode);
}
return 0;
}
3.2.中序遍历
在前序遍历的过程中出栈一个元素打印一个元素就实现啦!
int InOrderBinTreeByStack(TreeNode *pRoot)
{
//判断树是否为空
if (pRoot == NULL)
{
return -1;
}
//初始化栈
struct list_head head;
INIT_LIST_HEAD(&head);
//创建栈节点,方便后续树节点进栈
Stack_t *pnewnode = NULL;
Stack_t *pfreenode = NULL;
//创建树节点指针,指向根节点
TreeNode *ptmptreenode = NULL;
ptmptreenode = pRoot;
while (1)
{
while (ptmptreenode != NULL)
{
pnewnode = malloc(sizeof(Stack_t));
if (pnewnode == NULL)
{
return -1;
}
//根节点入栈
pnewnode->data = ptmptreenode;
//进栈
list_add(&pnewnode->node, &head);
//该左孩子,保存左孩子节点地址,让左孩子都进栈
ptmptreenode = ptmptreenode->pLeftChild;
}
//如果栈空,则结束
if (list_empty(&head))
{
break;
}
//获取栈顶节点的首地址
pfreenode = list_entry(head.next, Stack_t, node);
//打印
printf("%c ", pfreenode->data->data);
//让栈顶元素出栈
list_del(&pfreenode->node);
//获取出栈的树节点的右节点
ptmptreenode = pfreenode->data->pRightChild;
free(pfreenode);
}
return 0;
}
3.3.后序遍历
先让根节点进栈,再让其左子树的所有左孩子依次进栈,此时让栈顶元素出栈,判断下一个为栈顶元素的是否存在,如存在依次让他的所有左孩子再进栈,然后出栈的元元素再次进栈,之后再次出栈,若出栈次数为2,则打印。依次类推,知道栈内无元素位置,就实现了二叉树的非递归后序遍历。
int PostOrderBinTreeByStack(TreeNode *pRoot)
{
SeqStack *pTmpStack = NULL;
TreeNode *pTmpNode = NULL;
TreeNode *pTopNode = NULL;
int k = 0;
k = GetTreeHeight(pRoot);
pTmpStack = CreateSeqStack(pow(2, k));
pTmpNode = pRoot;
while (1)
{
while (pTmpNode != NULL)
{
pTmpNode->flag = 1;
PushSeqStack(pTmpStack, pTmpNode);
pTmpNode = pTmpNode->pLeftChild;
}
if (IsEmptySeqStack(pTmpStack))
{
break;
}
pTopNode = PopSeqStack(pTmpStack);
if (2 == pTopNode->flag)
{
printf("%c ", pTopNode->Data);
continue;
}
else if (1 == pTopNode->flag)
{
pTopNode->flag = 2;
PushSeqStack(pTmpStack, pTopNode);
}
pTmpNode = pTopNode->pRightChild;
}
printf("\n");
DestroySeqStack(&pTmpStack);
return 0;
}
3.4.层次遍历
借助队列实现,先让根节点进队列打印根节点;根节点出队列,让根节点的左右孩子依次进队列并打印,依次类推,知道队列为空,则顺序遍历完成。
int LayerOrderBTree(TreeNode *pRoot)
{
SeqQueue *pTmpQueue = NULL;
int k = 0;
DataType Data;
k = GetTreeHeight(pRoot);
pTmpQueue = CreateSeqQueue(pow(2, k));
EnterSeqQueue(pTmpQueue, pRoot);
while (!IsEmptySeqQueue(pTmpQueue))
{
Data = QuitSeqQueue(pTmpQueue);
printf("%c ", Data->Data);
if (Data->pLeftChild != NULL)
{
EnterSeqQueue(pTmpQueue, Data->pLeftChild);
}
if (Data->pRightChild != NULL)
{
EnterSeqQueue(pTmpQueue, Data->pRightChild);
}
}
printf("\n");
DestroySeqQueue(&pTmpQueue);
return 0;
}
四、树的高度
递归实现,分别递归求左子树和右子树的高度,比较最大的就为树的高度
int BinTreeHight(TreeNode *pRoot)
{
int lefthight = 0;
int righthight = 0;
if (pRoot == NULL)
{
return 0;
}
lefthight = BinTreeHight(pRoot->pLeftChild);
righthight = BinTreeHight(pRoot->pRightChild);
return lefthight > righthight ? lefthight + 1 : righthight + 1;
}
五、总结
树的递归遍历很好理解,主要是非递归遍历,使用到了栈和队列,这块的综合能力要求比较高。