1. 程式人生 > >C語言實現的求二叉樹的最大寬度(遞迴與非遞迴版本)

C語言實現的求二叉樹的最大寬度(遞迴與非遞迴版本)

一、遞迴

這裡說的遞迴,並非是指整個函式遞迴,而是說其中一個子函式使用了遞迴。整個思路可以如下:要求取最大寬度,可以迴圈求取每一層的寬度,存入一個數組,然後在這個數組裡求最大值即可,陣列下標即層數(或高度)。對於求某一層的寬度,考慮把它寫成一個子函式,引數考慮起始結點以及對應的層數,舉例:對於根節點來說,其第三層的寬度,就是其左孩子的第二層的寬度與其右孩子的第二層的寬度之和。

這樣,我們可以寫出兩個函式,我的如下:子函式LevelWidth函式返回特定起點開始的某個層的寬度,採用遞迴。

int LevelWidth(BT root,int level)//find the width of a level(amounts of nodes in the level).
{
	if(!root)return 0;
	else
	{
		if(level==1)return 1;
		level=LevelWidth(root->lchild,level-1)+LevelWidth(root->rchild,level-1);
	}
	return level;
}

主函式Width返回某起點開始的樹的最大寬度,使用迴圈。

int Width(BT root)//find the maximum width of the btree.
{
	int width,i;
	int w[20];
	for(i=0;i<20;i++)w[i]=0;
	if(!root)width=0;
	else
	{
		for(i=0;i<=Depth(root);i++)w[i]=LevelWidth(root,i+1);
	}
	i=0;
	while(w[i])
	{
		if(w[i]>width)width=w[i];
		i++;
	}
	return width;
}

那麼能不能合二為一寫成一個遞迴函式呢?我覺得不可以。因為最大寬度分成左右子樹最大寬度之和,是不對的,因為未必在同一個層次。當然也許有其它分法,但我未知。

二、非遞迴

非遞迴需要採用佇列,是在層次遍歷一棵樹的基礎上做些改進。我看過C++使用vector寫的,使用swap交換,可以獲得每個層次的結點數目,非常妙。若借鑑這個思路則需要寫可以交換兩個陣列的c子函式,並不難,但我想盡可能在一個函式內完成。和層次遍歷比起來,需要多記錄一個資訊,就是每一層的結點數目,因此在遍歷的程式碼基礎上增加了一個數組,用來記錄每一層的數目(或者每一層以及之前的層的所有結點數之和,我這裡是採用這個的),這樣就可以在掃描佇列頭的時候,根據隊頭的結點序號來判斷該結點處於哪一層,也判斷出了它的孩子處於哪一層(下一層)。此時在對它的每個孩子結點的入隊同時,即每增加一個入隊結點之時,下一層的結點數目也相應增加一個。我的具體實現如下,WidthNR用以表明width not recursive。

int WidthNR(BT root)//find the maximum width without recursive function.
{
	int i,j,w,index;
	int count[20],width[20];//count array stores the total amounts of nodes before a level(including itself);width array stores every level's amount of nodes.
	BT queue[20];//queue array stores the nodes' pointers.
	for(i=0;i<20;i++)
	{
		count[i]=0;
		width[i]=0;
		queue[i]=NULL;
	}
	i=0;
	j=0;
	if(!root)w=0;
	else
	{
		queue[0]=root;
		count[0]=1;
		count[1]=1;
		index=1;
		while(queue[i])
		{
			if(queue[i]->lchild)
			{
				j++;
				queue[j]=queue[i]->lchild;
				count[index]++;
			}
			if(queue[i]->rchild)
			{
				j++;
				queue[j]=queue[i]->rchild;
				count[index]++;
			}
			i++;
			if(i>=count[index-1])index++;//if the head of queue exeeds the level's total amount then it indictates it's a node in next level.
			if(count[index]==0)count[index]+=count[index-1];//the next level's amount of nodes is the sum of itself's and the amount of nodes whose level are before it.

		}
	}
	width[0]=1;
	w=width[0];
	i=1;
	while(count[i])
	{
		width[i]=count[i]-count[i-1];
		if(width[i]>w)w=width[i];
		i++;
	}
	return w;
}