一、二叉樹的遍歷
二叉樹遍歷的概念: 二叉樹的遍歷是指按照一定次序訪問樹中所有節點,並且每個節點僅被訪問一次的過程。它是最基本的運算,是二叉樹中所有其他運算的基礎。
1. 先序遍歷過程
先序遍歷二叉樹的過程是:① 訪問根節點;②先序遍歷左子樹;③先序遍歷右子樹。
2. 中序遍歷過程
中序遍歷二叉樹的過程是:① 中序遍歷左子樹;② 訪問根節點;③中序遍歷右子樹。
3. 後序遍歷過程
後序遍歷二叉樹的過程是: ①後序遍歷左子樹;②後序遍歷右子樹;③訪問根節點。
4. 層次遍歷過程
層次遍歷二叉樹的過程是: ①訪問根節點(第1層)②按照從上到下、從左往右訪問第2到第h層所有節點
二、二叉樹遍歷遞歸算法
1. 先序遍歷的遞歸算法:
void PreOrder(BTNode *b){ if (b!=NULL)
{ printf("%c ",b->data); //訪問根節點
PreOrder(b->lchild);
PreOrder(b->rchild);
}
}
2. 中序遍歷的遞歸算法:
void InOrder(BTNode *b){ if (b!=NULL)
{ InOrder(b->lchild);
printf("%c ",b->data); //訪問根節點
InOrder(b->rchild);
}
}
3. 後序遍歷遞歸算法:
void PostOrder(BTNode *b){ if (b!=NULL)
{ PostOrder(b->lchild);
PostOrder(b->rchild);
printf("%c ",b->data); //訪問根節點
}
}
三、二叉樹遍歷非遞歸算法
1. 先序遍歷非遞歸算法
void PreOrder(BTNode *b)
{ BTNode *St[MaxSize],*p; int top=-1;
top++; St[top]=b; //根節點入棧
while (top>-1) //棧不爲空時循環
{ p=St[top]; top--; //退棧並訪問該節點
printf("%c ",p->data);
if (p->rchild!=NULL) //右孩子節點入棧
{ top++; St[top]=p->rchild; }
if (p->lchild!=NULL) //左孩子節點入棧
{ top++; St[top]=p->lchild; }
}
}
2. 中序遍歷非遞歸算法
void InOrder(BTNode *b)
{ BTNode *St[MaxSize],*p; int top=-1;
p=b;
while (top>-1 || p!=NULL)
{ while (p!=NULL) //掃描*p的所有左節點並進棧
{ top++; St[top]=p;
p=p->lchild;
}
if (top>-1)
{ p=St[top];top--; //出棧*p節點
printf("%c ",p->data); //訪問之
p=p->rchild; //處理右子樹
}
}
}
3. 後序遍歷非遞歸算法
void PostOrder(BTNode *b)
{ BTNode *St[MaxSize];BTNode *p;
int flag,top=-1; //棧指針置初值
do
{ while (b!=NULL) //將*b的所有左節點進棧
{ top++; St[top]=b;
b=b->lchild;
}
p=NULL; //p指向棧頂節點的前一個已訪問的節點
flag=1; //表示*b的左子樹已訪問或爲空
while (top!=-1 && flag==1)
{ b=St[top]; //取出當前的棧頂元素if (b->rchild==p)
{ printf("%c ",b->data);//訪問*b節點
top--;p=b; //p指向則被訪問的節點
}
else
{ b=b->rchild; //b指向右孩子節點
flag=0; ///b的左子樹未訪問
}
}
} while (top!=-1);
}
例如,求一個節點的所有祖先節點。假設二叉樹採用二叉鏈存儲結構,設計一個算法輸出從根節點到每個葉子節點的路徑之逆(因爲樹中路徑是從根節點到其他節點的節點序列,這裏就是求從葉子節點及其雙親節點、該雙親節點的雙親節點,直到根節點的序列,或者說求葉子節點及其所有祖先節點的序列)。
解:本例採用後序遍歷非遞歸算法。
void AllPath(BTNode *b)
{ BTNode *St[MaxSize];
BTNode *p;
int flag,i,top=-1; //棧指針置初值
if (b!=NULL)
{ do
{ while (b!=NULL)//將*b的所有左節點進棧
{ top++;
St[top]=b;
b=b->lchild;
}
p=NULL;
flag=1;
while (top!=-1 && flag)
{ b=St[top]; //取出當前的棧頂元素
if (b->rchild==p)
{ if (b->lchild==NULL && b->rchild==NULL)
{ //若爲葉子節點,輸出棧中所有節點值
for (i=top;i>0;i--)
printf("%c->",St[i]->data);
printf("%c\n",St[0]->data);
}
top--;
p=b; //p指向剛訪問過的節點
}
else
{ b=b->rchild; //b指向右孩子節點
flag=0;
}
}
} while (top!=-1);
printf("\n");
}
}
四、層次遍歷算法
層次遍歷算法採用一個環形隊列qu來實現。
層次遍歷過程是:
先將根節點進隊,在隊不空時循環;
從隊列中出列一個節點*p,訪問它;
若它有左孩子節點,將左孩子節點進隊;若它有左孩子節點,將左孩子節點進隊。
如此操作直到隊空爲止。對應的算法如下:
void LevelOrder(BTNode *b)
{ BTNode *p;
BTNode *qu[MaxSize]; //定義環形隊列,存放節點指針
int front,rear; //定義隊頭和隊尾指針
front=rear=-1; //置隊列爲空隊列
rear++;
qu[rear]=b; //根節點指針進入隊列
while (front!=rear) //隊列不爲空
{ front=(front+1)%MaxSize;
p=qu[front]; //隊頭出隊列
printf("%c ",p->data); //訪問節點
if (p->lchild!=NULL) //有左孩子時將其進隊
{ rear=(rear+1)%MaxSize;
qu[rear]=p->lchild;
}
if (p->rchild!=NULL) //有右孩子時將其進隊
{ rear=(rear+1)%MaxSize;
qu[rear]=p->rchild;
}
}
}