二叉树是什么
概念
在计算机科学中,二叉树是每个节点最多有两个子树的树结构。
组成
有两个子树,左子树(left subtree)和右子树(right subtree)。
用途
二叉树常被用于实现二叉查找树和二叉堆。
特点
- 度:
- 每个节点至多只有二棵子树(不存在度大于2的节点)
- 第N层最多的度:2 ^ (N - 1)
- 前N-1层的度:2 ^ (N - 1) - 1
- 次序:二叉树的子树有左右之分, 次序不能颠倒。
类型
- 满二叉树:一棵深度为k,且有2^k-1个节点称之为满二叉树;节点的度要么是0,要么是2
- 完全二叉树:深度为k,有n个节点的二叉树,前k-1层是满二叉树;度为1的节点,最多有1个
存储
- 可以顺序存储
- 可以链式存储
二叉树的建树
头文件 BinaryTree.h
#ifndef __BINARYTREE_H__
#define __BINARYTREE_H__
#define TYPENAME char
//二叉树节点
typedef struct TreeNode {
//数据域
TYPENAME _data;
//指针域
struct TreeNode *_pLeft;
struct TreeNode *_pRight;
}TreeNode_t, *pTreeNode_t;
//静态建树,已知树节点个数
void build_binaryTree(pTreeNode_t *ppRoot, TYPENAME *begin, TYPENAME *end);
//队列节点
typedef struct QueueNode {
pTreeNode_t _data; //树节点地址
struct QueueNode *_pNext;
}QueueNode_t, *pQueueNode_t;
//队列
typedef struct Queue {
pQueueNode_t _pHead; //队头
pQueueNode_t _pTail; //队尾
}Queue_t, *pQueue_t;
//动态建树,不清楚节点个数,通过辅助队列
//辅助队列中,是所有没放完指针域的树节点
void insertTree_queue(pTreeNode_t *ppRoot, pQueue_t pQue, TYPENAME val);
//遍历
void preOrder(pTreeNode_t pRoot); //先序遍历
void midOrder(pTreeNode_t pRoot); //中序遍历
void postOrder(pTreeNode_t pRoot); //后序遍历
#endif
实现文件 BinaryTree.c
#include "BinaryTree.h"
#include <stdio.h>
#include <stdlib.h>
void build_binaryTree(pTreeNode_t *ppRoot, TYPENAME *begin, TYPENAME *end)
{
//求出二叉树的节点个数
TYPENAME *start = begin;
int len = 0;
while (start != end) {
++start;
++len;
}
//申请所有树节点所需空间
pTreeNode_t pArr = (pTreeNode_t)calloc(len, sizeof(TreeNode_t));
//根据传入的数据,给所有树节点赋值
start = begin;
for (int i = 0; i < len; ++i, ++start) {
pArr[i]._data = *start;
}
//建树
//i 用来遍历树节点
//j 表示要修改指针域的树节点
*ppRoot = pArr;
for (int i = 1, j = 0; i < len; ++i) {
if (NULL == pArr[j]._pLeft) {
pArr[j]._pLeft = &pArr[i]; //放左孩子
}
else {
pArr[j]._pRight = &pArr[i]; //放右孩子
++j; //当前节点指针域已全部放完,换下一个节点
}
}
return;
}
void insertTree_queue(pTreeNode_t *ppRoot, pQueue_t pQue, TYPENAME val)
{
//新建树节点,新建队列节点然后将其加入辅助队列
pTreeNode_t pT = (pTreeNode_t)calloc(1, sizeof(TreeNode_t));
pT->_data = val;
pQueueNode_t pQ = (pQueueNode_t)calloc(1, sizeof(QueueNode_t));
pQ->_data = pT;
//如果树为空,给根节点赋值, 队列节点入队
if (NULL == *ppRoot) {
*ppRoot = pT;
pQue->_pHead = pQ;
pQue->_pTail = pQ;
return;
}
//树不为空
//队列节点入队
pQue->_pTail->_pNext = pQ;
pQue->_pTail = pQ;
//将新树节点地址,赋给队首指向的树节点的指针域
pQueueNode_t pCur = pQue->_pHead;
if (NULL == pCur->_data->_pLeft) {
//放左孩子
pCur->_data->_pLeft = pT;
}
else {
//放右孩子
pCur->_data->_pRight = pT;
//队首指向的树节点的指针域全部放完,出队
pQue->_pHead = pQue->_pHead->_pNext;
//释放队首
free(pCur);
pCur = NULL;
}
}
void preOrder(pTreeNode_t pRoot)
{
if (pRoot) {
printf("%c ", pRoot->_data);
preOrder(pRoot->_pLeft);
preOrder(pRoot->_pRight);
}
}
void midOrder(pTreeNode_t pRoot)
{
if (pRoot) {
midOrder(pRoot->_pLeft);
printf("%c ", pRoot->_data);
midOrder(pRoot->_pRight);
}
}
void postOrder(pTreeNode_t pRoot)
{
if (pRoot) {
postOrder(pRoot->_pLeft);
postOrder(pRoot->_pRight);
printf("%c ", pRoot->_data);
}
}
测试文件 test_tree.c
#include "BinaryTree.h"
#include <stdio.h>
#include <string.h>
void test0()
{
pTreeNode_t pRoot = NULL;
char arr[] = "abcdefghi";
TYPENAME *begin = arr; //第一个元素的地址
TYPENAME *end = arr + strlen(arr) - 1; //最后一个元素的地址
build_binaryTree(&pRoot, begin, end);
printf("--------------test print_tree--------------\n");
preOrder(pRoot);
printf("\n");
midOrder(pRoot);
printf("\n");
postOrder(pRoot);
printf("\n");
}
void test1()
{
pTreeNode_t pRoot = NULL;
Queue_t que;
char val;
while (scanf("%c", &val)) {
if ('\n' == val) {
break;
}
insertTree_queue(&pRoot, &que, val);
}
printf("--------------test print_tree--------------\n");
preOrder(pRoot);
printf("\n");
midOrder(pRoot);
printf("\n");
postOrder(pRoot);
printf("\n");
}
int main()
{
/* test0(); */
test1();
return 0;
}