树的定义
由N(N>=0)个结点构成的集合。
有一个特殊的结点,称为根节点,根节点没有前驱结点。
结点:包括一个数据元素及若干指向其他子树的分支(指针(索引))
结点的度:结点所拥有子树的个数
分支结点:度不为0的结点,分支结点也称为非终端结点。一棵树中除叶结点外的所有结点都是分支结点。
祖先结点:从根节点到该结点所经分支上的所有节点。
子孙结点:以某结点为根节点的子树中所有结点
树的度:树中所有结点的度的最大值。
结点的层次:从根节点到树中某节点所经路径上的分支数称为该节点的层次,根节点的层次为1,其他结点层次是其双亲结点层次加1
树的深度:树中所有结点的层次的最大值
二叉树
特点:
- 每个结点最多有两棵子树,即二叉树不存在度大于2的结点
- 二叉树的子树有左右之分,其子树的次序不能颠倒
满二叉树和完全二叉树
满二叉树:在一棵二叉树中,如果所有分支结点都存在左右子树,并且所有叶子结点在同一层上
完全二叉树:如果一棵具有N个结点的二叉树的结构与满二叉树的前N个结点的结构相同,称为完全二叉树
- 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^i-1(i>0)个结点
- 若规定只有根节点的二叉树的深度为1,则深度为K的二叉树的最大的节点数是最大节点数为(2^k)-1
- 对于任何一棵二叉树,如果其叶结点个数为n0,度为2的非叶结点个数为n2,则有n0=n2+1
- 具有n个结点的完全二叉树的深度为log2(n+1)上取整
- 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有结点从0开始编号,则对于序号为i的结点有:
1.若i>0,双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲结点
2.若2i+1<n,左孩子序号:2i+1,否则无左孩子
3.若2i+2<n,右孩子序号:2i+2,否则无右孩子
二叉树链式存储结构
typedef struct Node {
int value;
struct Node *left;
struct Node *right;
}Node;
二叉树的遍历
前序遍历:(1)访问根节点(2)前序遍历根节点的左子树(3)前序遍历根节点的右子树
void preorderTraversal(Node *root) {
//空树
if (root == NULL) {
return;
}
printf("%d", root->value);
preorderTraversal(root->left);
preorderTraversal(root->right);
}
前序遍历结果: A B D C E F
中序遍历:(1)中序遍历根节点的左子树(2)访问根节点(3)中序遍历访问根节点的右子树
void inorderTraversal(Node *root) {
//空树
if (root == NULL) {
return;
}
inorderTraversal(root->left);
printf("%d", root->value);
inorderTraversal(root->right);
}
中序遍历结果:D B A E C F
后序遍历:(1)后序遍历根节点的左子树(2)后序遍历根节点的右子树(3)访问根节点
void postorderTraversal(Node *root) {
//空树
if (root == NULL) {
return;
}
postorderTraversal(root->left);
postorderTraversal(root->right);
printf("%d", root->value);
}
后序遍历结果: D B E F C A
层序遍历:
(1)初始化一个队列
(2)将根节点的指针入队列
(3)当队列非空时,循环执行以下步骤:
>取队头元素并访问
>若该结点的左子树非空,将该结点的左子树入队列
>若该结点的右子树非空,将该结点的右子树入队列
(4)结束
void Levelorder(Node *root) {
if (root == NULL) { printf("\n"); }
std::queue<Node *> q;
q.push(root);
while (!q.empty()) {
Node *front = q.front();
q.pop();
printf("%c",front->value);
if (front->left != NULL) {
q.push(front->left);
}
if (front->right != NULL) {
q.push(front->right);
}
}
}
层序遍历结果:A B C D E F