題目
假設二叉樹採用二叉鏈表存儲結構存儲,設計一個算法求出二叉樹的寬度(具有結點數最多的那一層上的結點個數)。
分析
要求含有最多結點數的層上的結點數,可以分別求出每層的結點數,然後從中選出最多的。 要達到這個目的,應該明白兩個事實。
第一,對於非空樹,樹根所在的層爲第一層,並且從層次遍歷算法的程序中可以發現,有-個由當前結點找到其左、右孩子結點的操作。這就提示我們,如果知道當前結點的層號,就可以推出其左、右孩子的層號,即爲當前結點層號加1,進而可以求出所有結點的層號。
第二,在層次遍歷中,用到了一個循環隊列(隊列用數組表示),其出隊和入隊操作爲front=(front+ 1)%maxSize;和rear=(rear+1)%maxSize;兩句。如果用來存儲隊列的數組足夠長,可以容納樹中所有結點,這時在整個遍歷操作中隊頭和隊尾指針不會出現折回數組起始位置的情況,那麼front=(front+ 1)%maxSize;可以用++front;代替,rear=(rear+1)%maxSize; 可以用++rear:代替。出隊操作只是隊頭指針front後移了一一位,但並沒有把隊頭元素刪除。在數組足夠長的情況下,隊頭元素也不會被新入隊的元素覆蓋。
代碼
核心代碼:
/* 求二叉樹的寬度 */
int maxNode(BTNode *b) {
St que[maxSize];
int front,rear;// 定義順序非循環隊列
int Lno=0,i,j,n,max=0;
front=rear=0;// 將隊列置空
BTNode *q;
if(b!=NULL) {
rear++;
que[rear].p=b;// 樹根入隊
que[rear].lno=1;// 樹根所在的層次號設置爲1,此爲已知條件
while(front!=rear) {
front++;
q=que[front].p;
Lno=que[front].lno;// 關鍵語句:Lno用來存取當前結點的層次號
if(q->lchild!=NULL) {
rear++;
que[rear].p=q->lchild;
que[rear].lno=Lno+1;// 關鍵語句:根據當前結點的層次號,推知其孩子結點的層次號
}
if(q->rchild!=NULL) {
rear++;
que[rear].p=q->rchild;
que[rear].lno=Lno+1;// 關鍵語句:根據當前結點的層次號推知其孩子結點的層次號
}
} // 注意:循環結束的時候,Lno中保存的是這顆二叉樹的最大層數
/* 以下代碼找出了含有結點最多的層中的結點數 */
max=0;
for(int i=1; i<=Lno; i++) {
n=0;
for(j=0; j<rear; j++) {
if(que[j].lno==i) {
n++;
}
if(max<n) {
max=n;
}
}
}
return max;
} else {
return 0;// 空樹直接返回0
}
}
完整代碼:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#define maxSize 30
/* 數結構體類型定義*/
typedef struct BTNode {
char data;// 這裏默認結點data域爲char類型
struct BTNode *lchild;// 左孩子指針域
struct BTNode *rchild;// 右孩子指針域
} BTNode,*BiTree;
/* 該結構體爲順序非循環隊列的隊列的隊列元素,可以存儲結點指針以及結點所在的層次號 */
typedef struct {
BTNode *p;// 結點指針
int lno;// 結點所在的層次號
} St;
/* 根據輸入創建二叉樹 */
/* 例:ABC##DE##F##GH### */
void CreatBiNode(BTNode **Node) { //此處應注意傳遞的參數(二重指針)
char data;
scanf("%c", &data);
*Node = (BiTree)malloc(sizeof(BTNode));
if (data == '#') {
*Node = NULL;
} else if ((data != '#') && (*Node)) {
(*Node)->data = data;
(*Node)->lchild = NULL;
(*Node)->rchild = NULL;
CreatBiNode(&(*Node)->lchild);
CreatBiNode(&(*Node)->rchild);
}
}
/* 求二叉樹的寬度 */
int maxNode(BTNode *b) {
St que[maxSize];
int front,rear;// 定義順序非循環隊列
int Lno=0,i,j,n,max=0;
front=rear=0;// 將隊列置空
BTNode *q;
if(b!=NULL) {
rear++;
que[rear].p=b;// 樹根入隊
que[rear].lno=1;// 樹根所在的層次號設置爲1,此爲已知條件
while(front!=rear) {
front++;
q=que[front].p;
Lno=que[front].lno;// 關鍵語句:Lno用來存取當前結點的層次號
if(q->lchild!=NULL) {
rear++;
que[rear].p=q->lchild;
que[rear].lno=Lno+1;// 關鍵語句:根據當前結點的層次號,推知其孩子結點的層次號
}
if(q->rchild!=NULL) {
rear++;
que[rear].p=q->rchild;
que[rear].lno=Lno+1;// 關鍵語句:根據當前結點的層次號推知其孩子結點的層次號
}
} // 注意:循環結束的時候,Lno中保存的是這顆二叉樹的最大層數
/* 以下代碼找出了含有結點最多的層中的結點數 */
max=0;
for(int i=1; i<=Lno; i++) {
n=0;
for(j=0; j<rear; j++) {
if(que[j].lno==i) {
n++;
}
if(max<n) {
max=n;
}
}
}
return max;
} else {
return 0;// 空樹直接返回0
}
}
int main() {
printf("先序輸入二叉樹(空結點用'#'表示):");
BiTree T=NULL;
CreatBiNode(&T);// 創建二叉樹
/* 求二叉樹的寬度 */
int r=maxNode(T);
printf("二叉樹的寬度:%d",r);
return 0;
}
以下圖爲例輸入(其中空結點用“#”表示),輸入的字符串如下:
運行結果: