首先我們來了解一下什麼是二叉樹
二叉樹是每個節點最多有兩個子樹的樹結構。通常子樹被稱作“左子樹”(left subtree)和“右子樹”(right subtree)。二叉樹的特點:
1.每個節點最多有兩棵子樹,即二叉樹不存在度大於2的節點
2.二叉樹的子樹有左右之分,其子樹的順序不能顛倒
3.滿二叉樹: 在一棵二叉樹中,如果所有分支節點都存在左子樹和右子樹,並且所有葉子節點都在同一層上
4.完全二叉樹:如果一棵具有N個節點的二叉樹的結構與滿二叉樹的前N個節點的結構相同,稱爲完全二叉樹
5.滿二叉樹與完全二叉樹之間的關係:滿二叉樹是一個特殊的完全二叉樹
二叉樹的性質:
1.若規定根節點的層數爲1,則一棵非空二叉樹的第i層上最多有2^(i-1)(i > 0)個節點;
3.對任何一棵二叉樹,如果其葉子節點個數爲n0,度爲2的非葉子節點個數爲n2,則有n0 = n2 +1;
4.具有n個節點的完全二叉樹的深度爲k爲log2(n+1)上取整;
5.對於具有n個節點的完全二叉樹,如果按照從上至下從左至右的順序對所有節點從0開始編號,則對於序號爲i的節點有:
(1)若 i>0,雙親序號:(i-1)/2 i=0,
i爲根節點編號,無雙親節點
(2)若 n>2i+1,左孩子序號爲2i+1,否則無左孩子
(3)若 n>2i+1,右孩子序號爲2i+1,否則無右孩子
二叉樹的存儲結構:
二叉樹主要有順序存儲結構和鏈式存儲結構
順序存儲結構:對於一棵完全二叉樹所有節點按照層序自頂向下,同一層自左向右順序編號,就得到一個節點的順序序列
優點:存儲完全二叉樹,簡單省空間
缺點:存儲一般二叉樹尤其單支樹,存儲空間利用不高
鏈式存儲結構:
二叉樹的遍歷:
1.先序遍歷:
(1)訪問根節點
(2)遍歷左子樹
(3)遍歷右子樹
2.中序遍歷:
(1)遍歷左子樹
(2)訪問根節點
(3)遍歷右子樹
3.後續遍歷:
(1)遍歷左子樹
(2)遍歷右子樹
(3)訪問根節點
4.層序遍歷:
按照二叉樹的層序次序,同一層中按先左子樹再右子樹的次序遍歷二叉樹下面就是對二叉樹的四種遍歷代碼的實現:
首先是 .h 文件
#pragma once
#include<stdio.h>
typedef char TreeNodeType;
//使用孩子表示法來表示一個樹
typedef struct TreeNode
{
TreeNodeType data;
struct TreeNode* lchild;
struct TreeNode* rchild;
}TreeNode;
//對於鏈表來說,使用鏈表的頭節點的指針表示一個鏈表
//對於一個樹來書,使用根節點的指針來表示一個樹
void TreeInit(TreeNode** pRoot);
void TreePreOrder(TreeNode* root);//先序
void TreeInOrder(TreeNode* root);//中序
void TreePostOrder(TreeNode* root);//後序
void TreeLevelOrder(TreeNode* root);//層序
#include <stdio.h>
#include"bin_tree.h"
#include"seqqueue.h"//因爲層序用到了隊列,所以將前面的隊列代碼引用進來
#include<stdlib.h>
#include<stddef.h>
TreeNode* CreateTreeNode(TreeNodeType value)//創建一個新的節點
{
TreeNode* new_node = (TreeNode*)malloc(sizeof(TreeNode));
new_node->data = value;
new_node->lchild = NULL;
new_node->rchild = NULL;
return new_node;
}
void DestroyTreeNode(TreeNode* node)
{
free(node);
}
void TreeInit(TreeNode** pRoot)//初始化
{
if(pRoot == NULL)
{
//非法輸入
return;
}
if(*pRoot == NULL)
{
//空樹
return;
}
*pRoot = NULL;
return;
}
- 先序遍歷的實現:
void TreePreOrder(TreeNode* root)
{
if(root == NULL)
{
printf("#");
return;
}
//先訪問根結點,再左子樹,再右子樹
printf("%c",root->data);
TreePreOrder(root->lchild);
TreePreOrder(root->rchild);
return;
}
void TestPreOrder()
{
TEST_HEADER;
TreeNode* a = CreateTreeNode('a');
TreeNode* b = CreateTreeNode('b');
TreeNode* c = CreateTreeNode('c');
TreeNode* d = CreateTreeNode('d');
TreeNode* e = CreateTreeNode('e');
TreeNode* f = CreateTreeNode('f');
TreeNode* g = CreateTreeNode('g');
a->lchild = b;
a->rchild = c;
b->lchild = d;
b->rchild = e;
e->lchild = g;
c->lchild = f;
TreePreOrder(a);
return;
}
- 中序遍歷的實現:
void TreeInOrder(TreeNode* root)
{
if(root == NULL)
{
return;
}
//先遍歷左子樹,再遍歷根節點,最後遍歷右子樹
TreeInOrder(root->lchild);
printf("%c",root->data);
TreeInOrder(root->rchild);
return;
}
void TestInOrder()
{
TEST_HEADER;
TreeNode* a = CreateTreeNode('a');
TreeNode* b = CreateTreeNode('b');
TreeNode* c = CreateTreeNode('c');
TreeNode* d = CreateTreeNode('d');
TreeNode* e = CreateTreeNode('e');
TreeNode* f = CreateTreeNode('f');
TreeNode* g = CreateTreeNode('g');
a->lchild = b;
a->rchild = c;
b->lchild = d;
b->rchild = e;
e->lchild = g;
c->lchild = f;
TreeInOrder(a);
return;
}
- 後序遍歷的實現:
void TreePostOrder(TreeNode* root)
{
if(root == NULL)
{
return;
}
//先遍歷左子樹,再遍歷右子樹,最後訪問根結點
TreePostOrder(root->lchild);
TreePostOrder(root->rchild);
printf("%c",root->data);
return;
}
void TestPostOrder()
{
TEST_HEADER;
TreeNode* a = CreateTreeNode('a');
TreeNode* b = CreateTreeNode('b');
TreeNode* c = CreateTreeNode('c');
TreeNode* d = CreateTreeNode('d');
TreeNode* e = CreateTreeNode('e');
TreeNode* f = CreateTreeNode('f');
TreeNode* g = CreateTreeNode('g');
a->lchild = b;
a->rchild = c;
b->lchild = d;
b->rchild = e;
e->lchild = g;
c->lchild = f;
TreePostOrder(a);
printf("\n");
return;
}
- 層序遍歷的實現:
void TestLevelOrder()
{
TEST_HEADER;
TreeNode* a = CreateTreeNode('a');
TreeNode* b = CreateTreeNode('b');
TreeNode* c = CreateTreeNode('c');
TreeNode* d = CreateTreeNode('d');
TreeNode* e = CreateTreeNode('e');
TreeNode* f = CreateTreeNode('f');
TreeNode* g = CreateTreeNode('g');
a->lchild = b;
a->rchild = c;
b->lchild = d;
b->rchild = e;
e->lchild = g;
c->lchild = f;
TreeLevelOrder(a);
printf("\n");
return;
}
void TreeLevelOrder(TreeNode* root)
{
if(root == NULL)
{
return;
}
SeqQueue queue;
SeqQueueInit(&queue);
SeqQueuePush(&queue,root);
while(1)
{
SeqQueueType front;
int ret = SeqQueueFront(&queue,&front);
if(ret == 0)
{
//如果取隊列首元素失敗,說明隊列爲空
//如果隊列爲空,說明遍歷已經結束
break;
}
printf("%c",front->data);
SeqQueuePop(&queue);
if(front->lchild != NULL)
{
SeqQueuePush(&queue,front->lchild);
}
if(front->rchild != NULL)
{
SeqQueuePush(&queue,front->rchild);
}
}
printf("\n");
return;
}