1. 程式人生 > >二叉樹(C語言)

二叉樹(C語言)

1、二叉樹的結構

        二叉樹是由一個儲存資料的變數和兩個指向子樹的指標構成的,定義在一個結構體中。其一般形式為:

typedef struct BiTree
{
	char data;
	struct BiTree *lchild;
	struct BiTree *rchild;
}BiTree,*BiNode;

        BiNode即結構體變數的指標,BiTree是結構體變數。在建立二叉樹時,為每個結點動態分配記憶體時要用到這兩個識別符號,例如: BiNode root=(BiNode)malloc(sizeof(BiTree))。

2、二叉樹的建立

        二叉樹一般使用遞迴的方式建立,遞迴呼叫函式來建立自己的左右子樹。

BiNode create()//先序建立二叉樹 
{
	BiNode T;
	char a;
	scanf("%c",&a);
	if(a=='.') return NULL;//當輸入.時表示這個結點為空,而且沒有左右子樹。
	else
	{
		T=(BiNode)malloc(sizeof(BiTree));//動態分配記憶體
		T->data=a;
		T->lchild=create();//建立左子樹 
		T->rchild=create();//建立右子樹 
	}
	return T;
}

          若想中序或後序建立,則只需改變函式中        T->data=a;        T->lchild=create();        T->rchild=create(); 這三條語句的順序,先給T->data=a在先的話是先序,在中間的話是中序,在最後的話是後序。

3、二叉樹的遍歷

        二叉樹一般有4種遍歷方法,即先序、中序、後序、層序。

        先序的遍歷順序是根節點->左子樹->右子樹。

        中序的遍歷順序是左子樹->根節點->右子樹。

        後序的遍歷順序是右子樹->根節點->左子樹。

        層序的遍歷順序是按層順次遍歷。

        先序、中序、後序的程式碼基本相同

void pre(BiNode root)//先序遍歷二叉樹 
{
	if(root)
	{
		printf("%c ",root->data);
		pre(root->lchild);
		pre(root->rchild);
	}
}

void mid(BiNode root)//中序遍歷二叉樹 
{
	if(root)
	{
		mid(root->lchild);
		printf("%c ",root->data);
		mid(root->rchild);
	}
}

void post(BiNode root)//後序遍歷二叉樹
{
	if(root)
	{
		post(root->lchild);
		post(root->rchild);
		printf("%c ",root->data);
	}
}

        例如這個簡單的二叉樹:

圖1

        當我們先序建立二叉樹時,應輸入:ABDF..GH..I..E..C..,這三種遍歷的結果為:

        而層序遍歷較為複雜,可以用佇列來實現,佇列的特點是先進先出。我們先構造一個佇列,先將根節點入佇列,之後每個出佇列的結點都要判斷其左右子樹是否存在,若存在則入佇列。程式碼如下:

void level(BiNode root)//二叉樹的層次遍歷,運用佇列,每層的結點挨個先進先出。 
{
	BiNode queue[20],pTemp;
	int cur=0,pre=0;//cur表示當前入佇列的結店,pre表示當前出佇列的結點
	queue[cur++]=root;
	while(cur!=pre)
	{
		pTemp=queue[pre++];
		printf("%c ",pTemp->data);
		if(pTemp->lchild!=NULL) queue[cur++]=pTemp->lchild;
		if(pTemp->rchild!=NULL) queue[cur++]=pTemp->rchild;
	}
}

        層序遍歷上面的二叉樹的執行結果為:

4、特殊二叉樹

  1、二叉排序樹

        二叉排序樹的特點是:若一個結點的左子樹非空,則左子樹的值一定小於結點的值;若一個節點的右子樹非空,則右子樹的值一定大於結點的值。

        例如這顆簡單二叉排序樹:

  

        其建立過程也不復雜,對於每個資料,都判斷它與根節點的大小關係,若大於根節點,則作為根節點的右子樹,若小於根節點,則作為根節點的左子樹。則二叉排序樹的中序遍歷一定是嚴格遞增的。程式碼如下:

BiNode BSTInsert(BiNode T,int key)
{
	if(!T)//若為空,則建立這個結點 
	{
		T=(BiNode)malloc(sizeof(BiTree));
		T->data=key;
		T->lchild=T->rchild=NULL;
	}
	else 
	{
		if(T->data<key)
			T->rchild=BSTInsert(T->rchild,key);
		else if(T->data>key)
			T->lchild=BSTInsert(T->lchild,key);
	}
	return T;
}

BiNode Insert(BiNode T,int data[],int n)
{
	int i;
	for(i=0;i<n;i++)
		T=BSTInsert(T,data[i]);
	return T;
}
int main()
{
	int num[9]={8,3,10,13,14,1,6,7,4};
	BiNode T=NULL;
	T=Insert(T,num,9);
	printf("\n中序遍歷:");
	mid(T);
	return 0;
}

        將一個數組{8,3,10,13,14,1,6,7,4}作為資料構造一棵二叉排序樹,可以得到上圖中的結果,對他進行中序遍歷的結果為:

        得到了正確的結果。