二叉樹的概念遍地都是,就不詳說了。不管是順序的還是鏈式的二叉樹,實現的方法基本上都是遞歸的例子,我就自己看着遍歷的方法,寫出了這一個程序,程序中每個遍歷實現思想都有詳細描述,代碼略顯繁瑣,歡迎讀者批評指正。使用的例子看附圖,也算是自己的一個學習筆記。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#define Max_Size 100
#define null '#'//表示爲空
//可以當做一個數據類型
typedef char BinaryTree[Max_Size];
//初始化二叉樹中每個節點爲空
void InitTree(BinaryTree tree)
{
int i;
for(i=0;i<Max_Size-1;i++)
{
tree[i] = null;
}
tree[i] = '\0';
}
void CreateTree(BinaryTree tree,char *strtree)
{
int len = strlen(strtree);
if(strtree[0] == null)
{
printf("樹根節點不能爲空");
return ;
}
int i;
for(i=0;i<len;i++)
{
tree[i] = strtree[i];
//樹節點從0開始,若從1開始,則判斷條件改爲:tree[(i+1)/2]
if((tree[(i+1)/2 - 1] == null) &&(tree[i] != null))
{
printf("構造二叉樹錯誤,子節點沒有父節點.\n節點爲%d %c.\n",i+1,tree[i]);
exit(1);
return;
}
}
}
//使用完全二叉樹求深度的公式[log₂N]+1 [x]取不大於x的整數
int Length(char *strtree)
{
printf("二叉樹字符串:%s\n完全二叉樹的節點數::%d\n",strtree,strlen(strtree));
//c語言提供的函數log10
float a = log10((double)strlen(strtree)),b = log10(2.0);
//計算深度函數
int len = a/b + 1;
printf("二叉樹深度爲:%d\n",len);
return len;
}
int Is_Empty(BinaryTree tree)
{
if(tree[0] == '#' || tree[0] == '\0')
{
printf("二叉樹爲空!\n");
return 1;
}
return 0;
}
//有效節點個數
int Count(BinaryTree tree)
{
int count=0;
int len = strlen(tree);
int i=0;
while(i < len)
{
if(tree[i] != '#')
{
count++;
}
i++;
}
return count;
}
//先序遍歷實現思想:(根據輸出的有效節點個數來作爲循環的終止條件)
//一:從根節點出發,先打印根節點,
//二:尋找下一個左節點,
//三:若節點不爲空,打印該節點並重復步驟二
//四:若節點爲空,判斷該節點的兄弟右節點
//五: 若不爲空,從該節點開始,重複步驟二
//六: 若爲空,回退至上一個節點,重複步驟四
//注:(回退時注意從左節點開始回退,避免兩個不同子樹的右孩子與左孩子有聯繫)
void PreOrderTraverse(BinaryTree tree)
{
char Strtree[Max_Size];
strcpy(Strtree,tree);
if((Is_Empty(Strtree) == 1))
{
return;
}
int len = Count(Strtree);
int k=0,i=0;//i表示節點在完全二叉樹中的位置
//根據輸出的有效節點個數來作爲循環的終止條件
while(k < len)
{
while(Strtree[i] != '#')
{
//打印有效節點
printf("%c ",Strtree[i]);
Strtree[i] = '#';//標誌節點已被打印爲空
k++;
//繼續尋找左節點
i = (i+1)*2 - 1;
if(Strtree[i] == '#')
{
break;
}
}
//遍歷右節點
if(Strtree[i+1] != '#')
{
i = i + 1;
}
else
{
//回退過程
i = (i+1)/2 - 1;
if(i%2 == 0 )
{
i = i - 1;
}
}
}
}
//中序遍歷實現思想:(根據輸出的有效節點個數來作爲循環的終止條件)
//一:對於任意一個節點,先找到它的最左節點,最左節點的下一個左節點一定是空的
//二:回退至上一個節點,判斷該節點是否爲空(左子樹打印過程中會置空,回退時避免打印無效節點):
//三: 若不爲空,打印該節點,繼續判斷該節點的右孩子,若不爲空,重複步驟一;
//四: 若爲空,重複步驟二。
void MidOrderTraverse(BinaryTree tree)
{
char Strtree[Max_Size];
strcpy(Strtree,tree);
if((Is_Empty(Strtree) == 1))
{
return;
}
int len = Count(Strtree);
int i=0,k=0;//i表示節點在完全二叉樹中的位置
while(k<len)
{
//新一個右節點就尋找該子樹的最左節點
while((Strtree[i] != '#'))
{
i = 2*(i+1)-1;
}
//回退至父節點
i = (i+1)/2 - 1;
if(Strtree[i] != '#')
{
printf("%c ",Strtree[i]);
Strtree[i] = '#';//標誌節點已被打印爲空
k++;
}
if(Strtree[(i+1)*2] != '#')
{
i= (i+1)*2;
}
}
}
//後序遍歷實現思想:
//一:對於任意一個節點,先找到它的最左節點,最左節點的下一個左節點一定是空的,判斷該兄弟(右)節點:
//二:若爲空,回退至父節點,打印並輸出該節點,判斷該節點的兄弟(右)節點
//三: 若不爲空,重複步驟一
//四: 若爲空,重複步驟二
//注:判斷右節點是否爲空之前,先要判斷該節點是否爲右節點,如果是就要跳過該判斷。
//數組的方式存儲完全二叉樹,除開根節點,右節點所在位置都是偶數,故用:i%2判斷
void PostOrderTraverse(BinaryTree tree)
{
char Strtree[Max_Size];
strcpy(Strtree,tree);
if((Is_Empty(Strtree) == 1))
{
return;
}
int len = Count(Strtree);
int i=0,k=0;//i表示節點在完全二叉樹中的位置
while(k<len)
{
//新一個右節點就尋找該子樹的最左節點
while((Strtree[i] != '#'))
{
i = 2*(i+1)-1;
}
//如果最左節點的兄弟(右)節點不爲空,繼續下一輪循環
if(Strtree[i+1] != '#' && (i%2 !=0) )
{
i = i + 1;
continue;
}
//回退至父節點
i = (i+1)/2 - 1;
if(Strtree[i] != '#')
{
//printf("i = %d\n",i);
printf("%c ",Strtree[i]);
Strtree[i] = '#';//標誌節點已被打印爲空
k++;
}
//判斷兄弟(右)節點(在完全二叉樹中,右節點一定爲偶數(除開根節點))
if(Strtree[i+1] != '#')
{
if(i%2 != 0)
{
i= i+1;
}
}
}
}
int main()
{
BinaryTree tree;
char BinaryTree[Max_Size] = "-+/a*ef##b-##########cd";//第一個圖
//char BinaryTree[Max_Size] = "fdgbe#iac####hj";//第二個圖
//char BinaryTree[Max_Size] = "AB#CD####EF#########G";
InitTree(tree);
CreateTree(tree,BinaryTree);
Length(BinaryTree);
printf("有效節點個數:%d\n",Count(tree));
printf("先序遍歷如下:\n");
PreOrderTraverse(tree);
printf("\n中序遍歷如下:\n");
MidOrderTraverse(tree);
printf("\n後序遍歷如下:\n");
PostOrderTraverse(tree);
return 0;
}
運行結果示例: