1、樹的基本定義
1、樹的定義:n個結點的有限集合(n>=0)。
2、樹的結點:包含1個數據元素及若干指向其子樹的分支。
3、結點的度:結點所擁有的子樹數量。
4、樹的度:樹中所有結點的度的最大值。
5、結點的層次:從根節點開始爲第一層
6、樹的深度:最大的層次數。
/2、二叉樹(Binary Tree)
1、二叉樹:n個結點的有限集合(n>=0)。特殊在於:n>1時,1個根節點和兩棵互不相交的二叉樹。
2、滿二叉樹:①所有的分支結點都有左子樹和右子樹;②所有的葉子結點都在同一層。
3、完全二叉樹:對有n個結點的二叉樹按照層序編號,若編號i(1<=i<=n)與同樣深度的滿二叉樹的位置完全相同,則該二叉樹爲完全二叉樹。
4、二叉樹的一些性質:
/2.1 二叉樹的順序結構
注意:邏輯結構和物理結構的差異。
邏輯結構:分爲線性和非線性。(樹是非線性結構)
物理結構(存儲結構):分爲順序、鏈式、索引、哈希等,表徵數據是如何存儲的。(因此樹結構也可以有順序或鏈式存儲結構)
二叉樹的順序存儲結構如下:
//二叉樹的順序結構中:一個數組和一個表示位置的結構體。數組存放數據,下標從0開始;位置表徵結點的層數和本層序號數。
typedef TElemType SqBiTree[MAX_TREE_SIZE]; //0號單元存儲根節點,使用一個數組存放數據
typedef struct
{
int level, order; //結點的層,本層序號(按照滿二叉樹計算)
}Position;
二叉樹的順序存儲,元素是放在數組中,注意點要在根節點與孩子結點的2倍關係、以及結點所在層數和序號之間的計算上。
/************************************************************************/
/* 1.二叉樹的順序結構 */
/************************************************************************/
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 //存儲空間初始分配量
#define MAX_TREE_SIZE 100 //二叉樹的最大結點數
typedef int Status;
typedef int TElemType;
typedef TElemType SqBiTree[MAX_TREE_SIZE]; //0號單元存儲根節點,使用一個數組存放數據
typedef struct
{
int level, order; //結點的層,本層序號(按照滿二叉樹計算)
}Position;
TElemType Nil=0; //設整型以0爲空
Status visit_SqBiTree(TElemType c)
{
printf("%d ",c);
return OK;
}
//構造空二叉樹T。因爲T是固定數組,不會改變,因此不需要&
Status InitBiTree(SqBiTree T)
{
int i;
for (i=0;i<MAX_TREE_SIZE;i++)
T[i]=Nil; //初值爲空
return OK;
}
//按層序的次序輸入二叉樹中結點的值,構造順序存儲的二叉樹T
Status CreateBiTree(SqBiTree T)
{
int i=0;
printf("請按照層序輸入結點的值,0表示空節點,輸入999表示結束,結點數<=%d\n",MAX_TREE_SIZE);
while(i<10)
{
T[i]=i+1;
if (i !=0 && T[(i+1)/2-1]==Nil && T[i]!=Nil) //此結點不空,無雙親且不是根
{
printf("出現無雙親的非根結點%d\n",T[i]);
exit(ERROR);
}
i++;
}
while(i<MAX_TREE_SIZE)
{
T[i]=Nil; //將空值賦給T後面的結點
i++;
}
return OK;
}
#define ClearBiTree InitBiTree //在二叉樹的順序存儲結構中,清除和初始化函數一樣
/* 初始條件:二叉樹T存在*/
/*操作結果:若T爲空二叉樹,則返回TRUE;否則返回FALSE*/
Status isBiTreeEmpty(SqBiTree T)
{
if (T[0]==Nil) //若根節點爲空,則樹空
return TRUE;
else
return FALSE;
}
/*初始條件:二叉樹T存在。操作結果:返回T的深度*/
int BiTreeDepth(SqBiTree T)
{
int i,j=-1;
for (i=MAX_TREE_SIZE-1; i>=0;i--) //找到最後一個結點
{
if (T[i]!=Nil)
break;
}
i++;
do
{
j++;
} while (i>=powl(2,j)); //計算2的j次冪.pow(x,y):計算x的y次方
return j;
}
/* 初始條件:二叉樹T存在*/
/* 操作結果:當T不爲空,用e返回T的根,返回OK;否則返回ERROR*/
Status Root(SqBiTree T, TElemType *e)
{
if (isBiTreeEmpty(T)) //先判斷是否爲空
return ERROR;
else
{
*e =T[0];
return OK;
}
}
/* 初始條件:二叉樹T存在,e是T中某個結點*/
/*操作結果:返回處於位置e(層,本層序號)的結點的值*/
TElemType Value(SqBiTree T, Position e)
{
//2的k-1次方是當前層的第一個元素下標,再加上元素在當前層的序列,-1是得到在該層的準確位置,再進行-1是因爲數組下標從0開始存數據(T[0]存放根節點數據)
return T[(int)powl(2,e.level-1)+e.order-2];//將層序號轉換爲在數組中存放的下標
}
/* 初始條件:二叉樹T存在,e是T中某個結點的位置*/
/* 操作結果:給處於位置e(層)的結點賦予新值value*/
Status Assign(SqBiTree T, Position e, TElemType value)
{
int i=(int)powl(2,e.level-1)+e.order-2; //將層號轉換爲矩陣(一位數組)序號
if (value!=Nil && T[(i+1)/2-1]==Nil) //value非空;若雙親爲空
return ERROR;
else if (value==Nil && (T[i*2+1]!=Nil || T[i*2+2]!=Nil)) //給存在孩子的雙親賦空
return ERROR;
T[i]=value; //以上兩種情況都不是,即給T[i]賦值
return OK;
}
/*初始條件:二叉樹T存在,e是T中的某個結點*/
/*操作結果:若e是T的非根節點,則返回它的雙親,否則返回空*/
TElemType Parent(SqBiTree T, TElemType e)
{
//判斷是否爲空樹
if (T[0]==Nil)
return Nil;
for (int i=1; i<=MAX_TREE_SIZE-1; i++)
{
if (T[i]==e) //先找到結點e
{
return T[(i+1)/2-1];
}
}
return Nil; //沒找到e
}
/*初始條件:二叉樹T存在,e是T中的某個結點*/
/*操作結果:返回e的左孩子。若e無左孩子,返回空*/
TElemType LeftChild(SqBiTree T, TElemType e)
{
//判斷是否爲空樹
if (T[0]==Nil)
return Nil;
for(int i=0;i<=MAX_TREE_SIZE-1;i++)
{
if (T[i]==e)
{
return T[i*2+1];
}
}
return Nil;//沒找到e
}
/*操作結果,返回右孩子;若無右孩子,返回空*/
TElemType RightChild(SqBiTree T, TElemType e)
{
if (T[0]==Nil)
return Nil;
for (int i=0; i<=MAX_TREE_SIZE-1; i++)
{
if (T[i]==e)
{
return T[(i+1)*2];
}
}
return Nil;//沒找到e,返回空
}
/*初始條件:二叉樹T存在,e是T中的某個結點*/
/*操作結果:返回e的做兄弟。若e是左孩子或無左兄弟,返回空*/
TElemType LeftBrother(SqBiTree T, TElemType e)
{
if (T[0]==Nil)
return Nil;
for (int i=1; i<=MAX_TREE_SIZE-1;i++)
{
if (T[i]==e && i%2==0)
{
return T[i-1];
}
}
return Nil;//沒找到e,或者e就是左孩子
}
//返回e的右兄弟
TElemType RightBrother(SqBiTree T, TElemType e)
{
if (T[0]==Nil)
return Nil;
for(int i=1; i<MAX_TREE_SIZE;i++)
{
if (T[i]==e && i%2==1 /*&&T[i+1]!=Nil*/)
{
return T[i+1];
}
}
return Nil;//沒找到e
}
/*PreOrderTraverse()調用*/
void PreTraverse(SqBiTree T, int e)
{
visit_SqBiTree(T[e]);
if (T[2*e+1]!=Nil) //左子樹不爲空
{
PreTraverse(T,2*e+1);
}
if (T[2*e+2]!=Nil) //右子樹不爲空
{
PreTraverse(T,2*e+2);
}
}
/*初始條件:二叉樹存在*/
/*操作結果:先序遍歷T(先序是指根節點先)*/
Status PreOrderTraverse(SqBiTree T)
{
if (isBiTreeEmpty(T))
return ERROR;
PreTraverse(T,0);
printf("\n");
return OK;
}
//中序遍歷InOrderTraverse()調用
void InTraverse(SqBiTree T,TElemType e)
{
if (T[2*e+1]!=Nil) //左子樹不爲空,先左子樹
{
InTraverse(T,2*e+1);
}
visit_SqBiTree(T[e]); //第二纔是對應根節點
if (T[2*e+2]!=Nil) //第三是右子樹
{
InTraverse(T,2*e+2);
}
}
/*初始條件:二叉樹T存在*/
/*操作結果:中序遍歷*/
Status InOrderTraverse(SqBiTree T)
{
if (!isBiTreeEmpty(T))
{
InTraverse(T,0);
}
printf("\n");
return OK;
}
//後續遍歷PostOrderTraverse()的調用函數
void PostTraverse(SqBiTree T, TElemType e)
{
if (T[2*e+1]!=Nil)
{
PostTraverse(T,2*e+1);
}
if (T[2*e+2]!=Nil)
{
PostTraverse(T,2*e+2);
}
visit_SqBiTree(T[e]);
}
//後序遍歷
Status PostOrderTraverse(SqBiTree T)
{
if (!isBiTreeEmpty(T))
{
PostTraverse(T,0);
}
printf("\n");
return OK;
}
/*層序遍歷二叉樹*/
void LevelOrderTraverse(SqBiTree T)
{
//注意:要先找到最後一個非空節點的序號,然後再依次遍歷
int i=MAX_TREE_SIZE-1;
while(T[i]==Nil)
i--;
for (int j=0;j<=i;j++)
{
if (T[j]!=Nil) //只遍歷非空結點
visit_SqBiTree(T[j]);
}
printf("\n");
}
/*逐層、按照本層序號輸出二叉樹*/
void Print(SqBiTree T)
{
Position p;
TElemType e;
for(int j=1;j<=BiTreeDepth(T);j++)
{
printf("第%d層:",j);
for(int i=1;i<=powl(2,j-1);i++)
{
p.level=j;
p.order=i;
e=Value(T,p);
if (e!=Nil)
{
printf("第%d個:%d",i,e);
}
}
printf("\n");
}
}
int main()
{
Status i;
Position p;
TElemType e;
SqBiTree T;
InitBiTree(T);
CreateBiTree(T);
printf("建立二叉樹之後,樹是否爲空?%d(1:是;0:否)\n",isBiTreeEmpty(T));
printf("樹的深度爲%d\n",BiTreeDepth(T));
i=Root(T,&e);
if (i)
{
printf("二叉樹的根節點爲%d\n",i);
}
else
printf("二叉樹爲空");
printf("先序遍歷二叉樹:\n");
PreOrderTraverse(T);
printf("中序遍歷二叉樹:\n");
InOrderTraverse(T);
printf("後序遍歷二叉樹:\n");
PostOrderTraverse(T);
printf("層序遍歷二叉樹:\n");
LevelOrderTraverse(T);
printf("修改結點的層號3本層序號2.(第三層的第二個結點)");
p.level=3;
p.order=2;
e=Value(T,p);
printf(" %d",e);
e=50;
Assign(T,p,e);
printf("修改後,前序遍歷二叉樹:\n");
PreOrderTraverse(T);
printf("結點%d的雙親爲%d,左右孩子分別爲%d和%d",e,Parent(T,e),LeftChild(T,e),RightChild(T,e));
getchar();
}
2.2 二叉樹的鏈式結構:二叉鏈表
首先要構造鏈式表的結構體,如下:
//和單鏈表類似。區別在於多了一個指針
typedef struct BiTNode
{
TelemType data;//存放數據
struct BiTNode *lchild,*rchild;//構造兩個指針分別指向左子樹和右子樹
}BitNode,*BiTree;
其次,二叉鏈表在使用的時候,注意力在於根節點與左孩子和右孩子之間的關係。
/************************************************************************/
/* 樹的鏈式存儲結構 :二叉鏈表 */
/************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <math.h>
#include <time.h>
#include <string.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100
typedef int Status;
typedef char TElemType;
TElemType Nil2 =' '; //字符型以空格爲空,(整型Nil=0)
/******用於構造二叉樹*******/
int index=1;
typedef char String[24];//定義一個字符型數組String,其中0號單元存放串的長度
String str; //main()函數中用到
Status StrAssignBiTree(String T, char *chars) //生成一個字符串T,其值等於chars
{
int i;
if (strlen(chars) > MAXSIZE)
return ERROR;
else
{
T[0]=strlen(chars);
for (i=1; i<=T[0]; i++)
{
T[i]=*(chars+i-1);
}
return OK;
}
}
/**************************************/
Status visitBiTree(TElemType e)
{
printf("%c",e);
return OK;
}
typedef struct BiTNode /*定義結點結構*/
{
TElemType data; //結點數據,TElemTypeChar型
struct BiTNode *lchild, *rchild; //定義左右孩子指針
}BiTNode, *BiTree;
//構造空的二叉樹T
Status InitBiTree(BiTree *T)
{
*T =NULL;
return OK;
}
/*初始條件:二叉樹T存在。操作結果:銷燬二叉樹*/
void DestroyBiTree(BiTree *T)
{
if (*T)
{
if ((*T)->lchild) //有左孩子
{
DestroyBiTree(&(*T)->lchild); //銷燬左孩子樹
}
if ((*T)->rchild)
{
DestroyBiTree(&(*T)->rchild);
}
free(*T); //釋放根節點
*T=NULL; //空指針賦0
}
}
#define ClearBiTree DestroyBiTree
/* 按前序輸入二叉樹中結點的值(這裏設置的是一個字符)*/
/* #表示空樹,構造二叉鏈表表示二叉樹T */
void CreateBiTree(BiTree *T)
{
TElemType ch;
ch=str[index++];
if (ch=='#') //空樹
{
*T=NULL;
}
else
{
*T=(BiTree)malloc(sizeof(BiTNode));
if (!*T)
exit(OVERFLOW); //表示未分配到合適大小的空間
(*T)->data=ch;
CreateBiTree(&(*T)->lchild); //構造左子樹
CreateBiTree(&(*T)->rchild); //構造右子樹
}
}
/* 初始條件:二叉樹T存在 */
/* 操作結果:若T爲空二叉樹,返回TRUE;否則返回FALSE */
Status isBiTreeEmpty(BiTree T)
{
if(T)
return FALSE;
else
return TRUE;
}
/* 初始條件:二叉樹T存在。 操作結果:返回T的深度 */
int BiTreeDepth(BiTree T)
{
int i,j;
if(!T)
return ERROR;
if (T->lchild)
i=BiTreeDepth(T->lchild);
else
i=0;
if (T->rchild)
j=BiTreeDepth(T->rchild); //因爲不一定是完全二叉樹,所以有可能是各種奇怪的二叉樹。因此既要判斷左子樹,也要判斷右子樹
else
j=0;
return i>j?i+1:j+1;
}
/* 初始條件:二叉樹T存在。 操作結果:返回T的根 */
TElemType Root(BiTree T)
{
if (!T)
return Nil2;
else
return T->data;
}
/* 初始條件:二叉樹T存在,p指向T中的某個結點 */
/* 操作結果:返回p所指向結點的值 */
TElemType Value(BiTree p)
{
return p->data; //
}
//給p所指向的結點賦值爲value
void Assign(BiTree p, TElemType value)
{
p->data =value;
}
/*初始條件:二叉樹T存在。操作結果:前序遍歷T*/
void PreOrder(BiTree T)
{
if (!T)
return;
printf("%c ",T->data); //顯示結點數據
PreOrder(T->lchild);
PreOrder(T->rchild);
}
/* 初始條件:二叉樹T存在。操作結果:中序遍歷T*/
void InOrder(BiTree T)
{
if (!T)
return;
InOrder(T->lchild);
printf("%c ",T->data);
InOrder(T->rchild);
}
/* 後序遍歷*/
void PostOrder(BiTree T)
{
if(!T)
return;
PostOrder(T->lchild);
PostOrder(T->rchild);
printf("%c ",T->data);
}
int main()
{
int i;
BiTree T;
TElemType e1;
InitBiTree(&T);
StrAssignBiTree(str,"ABDH#K###E##CFI###G#J##");
CreateBiTree(&T);
printf("構造空二叉樹後,樹是否爲空?%d(1:空;0:否),樹的深度爲%d\n",isBiTreeEmpty(T),BiTreeDepth(T));
e1=Root(T);
printf("樹的根爲%c\n",e1);
printf("\n前序遍歷結果:");
PreOrder(T);
printf("\n中序遍歷結果:");
InOrder(T);
printf("\n後序遍歷結果:");
PostOrder(T);
ClearBiTree(&T);
printf("\n清除二叉樹後,樹是否爲空?%d(1:空;0:否),樹的深度爲%d\n",isBiTreeEmpty(T),BiTreeDepth(T));
i=Root(T);
if (!i)
printf("樹空,無根\n");
getchar();
return 0;
}