- 我们先定确定需要用到的数据结构,其中有栈,队列,二叉树
//二叉树结构
typedef struct biNode {
int data;
struct biNode* lchild;
struct biNode* rchild;
}biNode,*biTree;
//队列结构,注意队列的data元素是一个指向二叉树节点的指针,即biTree类型的元素
typedef struct bfsQueue {
biTree data;
struct bfsQueue* next;
}qnode;
typedef struct bfsList {
qnode* head;//头节点
qnode *rear;//尾节点
}list,*qlist;
//栈结构
typedef struct snode {
biTree data;
struct snode* next;
}snode;
typedef struct stackNode {
snode* head;//栈顶节点
}stackNode, * Stack;
- 对于二叉树,用先序遍历创建
void preorderInsert(biTree* T) {
*T = new biNode;
int data;
cin >> data;
if (data!=0) //data为0,表示节点为空
{
(*T)->data = data;//先序遍历创建
preorderInsert(&(*T)->lchild);
preorderInsert(&(*T)->rchild);
}
else {
*T = NULL;
}
}
3.先来看广度优先遍历
最开始,我们让一棵二叉树即它的头节点进队列,然后我们从队列中取出一个元素并输出,如果它有左孩子和右孩子,则先让左孩子进队列,再让右孩子进队列。然后我们重复相同的步骤(即从队列取元素,让左孩子右孩子进队列,直到这个队列为空,就完成了广度优先遍历)
//广度优先遍历
void bfs(biTree T) {
qlist List = new list;
initQueue(List);//初始化队列
enter(List, T);//二叉树进队列
while (List->head) {
leaveQ(List);//重复相同步骤,直到队列为空
}
}
void initQueue(qlist Q) {
Q->head = NULL;
Q->rear = NULL;
}
void enter(qlist Q,biTree data) {
qnode* node = new qnode;
node->data = data;
node->next = NULL;
if (Q->head ==NULL)
Q->head = node;
if (Q->rear == NULL)
Q->rear = node;
else {
Q->rear->next = node;
Q->rear = node;
}
}
void leaveQ(qlist Q) {
cout << Q->head->data->data << endl;//输出要出队列的元素中的值
biTree L = Q->head->data->lchild;
biTree R = Q->head->data->rchild;
Q->head = Q->head->next;//出队列
if (Q->head == NULL)
Q->rear = NULL;
if (L)//如果左孩子不空,左孩子进队列
enter(Q, L);
if (R)//如果右孩子不空,右孩子进队列
enter(Q, R);
}
- 然后是深度优先遍历
和广度优先遍历类似,最开始,我们让一棵二叉树即它的头节点进栈,然后我们从栈中取出一个元素并输出,如果它有左孩子和右孩子,则先让右孩子(注意是先让右孩子,因为栈是先进后出)进栈,再让左孩子进栈。然后我们重复相同的步骤(即从栈取元素,让右孩子左孩子进栈,直到这个栈为空,就完成了深度优先遍历)
//深度优先遍历
void dfs(biTree T) {
Stack S=new stackNode;
initStack(S);
pushStack(S, T);
while (S->head->next) {
popStack(S);//重复相同步骤,直到栈为空
}
}
//初始化栈
void initStack(Stack S) {
snode* s = new snode;
S->head = s;
S->head->next = NULL;
}
进栈
void pushStack(Stack S, biTree data) {
snode* s = new snode;
s->data = data;
s->next = S->head->next;
S->head->next = s;
}
void popStack(Stack S) {
cout << S->head->next->data->data << endl;
biNode *L = S->head->next->data->lchild;
biNode* R = S->head->next->data->rchild;
S->head->next = S->head->next->next;
if (R)
pushStack(S, R);//右子树不空,右子树进栈
if (L)
pushStack(S, L);//左子树不空,左子树进栈
}
5.main函数
int main() {
biTree T;
preorderInsert(&T);//先序创建二叉树
bfs(T);//广度优先遍历
dfs(T);//深度优先遍历
return 0;
}
到此,我们已经完成了最简单的二叉树的遍历,在此基础上,我们将考虑图的广度优先与深度优先。不妨先来看看,它与二叉树遍历的不同之处,对于一棵二叉树,每个节点的左孩子右孩子只可能是它自己的左右孩子,所以我们不需要对已经遍历过的节点设置标记,但在图中就不一定,每个节点相邻的节点又可能和别的节点相邻,如果继续按照上述思路,我们就会重复遍历一些节点,所以,我们有必要对已经遍历过的节点设置一个标记,以避免它被重复遍历。