学习 严蔚敏讲数据结构笔记18

来源:互联网 发布:做淘宝仓库打包员累吗 编辑:程序博客网 时间:2024/05/25 12:21

遍历是所有非线性结构(包括二叉树,树,图和广义表)的操作基础

不同的应用需要应用不同的搜索路径

1.      深度优先搜索遍历 2广度优先搜索遍历

深度优先搜索遍历:

二叉树先序,中序,后序

     先根,后根

     先访问顶点,后访问顶点

广义表先遍历表头,先遍历表尾

深度优先搜索遍历算法的两种形式:递归,非递归

6.12已知L[i]R[i](i=1,2,…n-1)分别指示二叉树中第i个结点的左孩子和右孩子结点,0表示空。试写判别结点u是否是结点v的子孙的算法。

分析:

1.      u是否是结点v的子孙===从结点v出发遍历能否到达结点u;“访问”===判结点u是否是结点v的孩子

2.      给出的存储结构实质上是一个二叉链表

32_002

Status descendent(int L[], int R[], int  u,int v)

{

         if(u  && v)

         {

                   if(L[v]  == u || R[v] == u)

                            return  TRUE;

                   else  if(descendent(L, R, u, L[v]))

                            return  TRUE;

                   else 

                            return  descendent(L, R, u, R[v]);

         }

         else  return FALSE;

}

 

6.19 编写递归算法:对于二叉树中每一个元素值为x的结点,删去以它为根的子树,并释放相应的空间。

分析:

1.      先序遍历二叉树的过程中查找每一个元素值为x的结点;

2.      修改其双亲结点的相应指针;

3.      释放以它为艮的子树上的所有结点,则应该后序遍历以它为根的子树

32_003

void Delete-X(BiTree &BT, ElemType x)

{

         if(BT)

         {

                   if(BT->data  == x)

                   {

                            disp(BT);

                            BT  = NULL;

                   }

                   else

                   {

                            Delete-X(BT->Lchild,  x);

                            Delete-X(BT->Rchild,  x);

                   }

         }

}

6.22 编写一个算法:输出以二叉树表示的算数表达式,若该表达式中含有括号,则输出时应添上

分析:

1.      原表达式即为带括弧的中缀表达式,则此题应该进行中序遍历

2.      表达式求值应该进行后序遍历,则表明左、右子树的运算应该先于根结点的运算进行;因此,若左、右子树根的运算符的优先数低于根节点运算符的优先数,则应对左子树和右子树应加上括弧;

32_004

void Expression(BiTree T)

{

         if(T)

         {

                   if(precede(T->data,  T->Lchild->data)

                   {

                            printf("(");

                            Expression(T->Lchild);

                            printf(")");

                   }

                   else

                            Expression(T->Lchild);

                   printf(T->data);

                   if(precede(T->data,  T->Lchild->data))

         }

}

6.24 编写算法完成下列操作:无重复地输出以孩子兄弟链表存储的树T中所有的边。输出的形式为(k1,k2),…,(ki,kj),..,其中,kikj为树结点中的结点标识。

分析:

在孩子兄弟链表中,哪一些结点是根的孩子?

33_001

void OutEdge(CStree T)

{

         if(T)

         {

                   p  = T->firstchild;

                   while(p)

                   {

                            prntf(T->data,  p->data);

                            OutEdge(p);

                            p  = p->nextsibling;

                   }

         }

}//先根遍历输出树中各条边

7.7 已知有向图和图中两个顶点uv,试编写算法求有向图从uv的所有简单路径。

33_002

void DFSearch(Graph G, int v, int s)

{

         visited[v]  = TRUE; //访问第v个顶点

         Append(PATH,  getVertex(v));

         for(w  = FirstAdjVex(v); w != 0; w = NextAdjVex(v))

                   OutPath(PATH);

         if(!  visited[w])

                   DFSearch(G,  w, s);

         visited[v]  = FLASE;

}

深度优先搜索遍历的非递归形式的算法:一般情况下,需要一个“栈”保留一些信息

例如:遍历二叉树时,需要利用栈保留曾经路过的根结点(中序);或者保留尚未遍历的右子树的根结点(先序)以便从左子树返回时继续遍历右子树。

后序遍历二叉树的情况要复杂一些,由于根结点的访问在左、右子树的遍历之后,则不仅要保存结点的信息,还应保存“标志”。

反之,如果在存储结构中加上适当的信息,

 

6.15假设在二叉链表的结点中增设两个域;双亲域(parent)以指示其双亲结点;标识域(mark012)以区分在遍历过程中到达该节点时应继续向左或向右访问该结点,试以此存储结构编写不用栈进行后序遍历的递归形式的算法。

Mark域的作用在于识别当前的状态:

Mark=0表示当前状态是对结点第一次访问

Mark=1表示当前状态是对结点第二次访问

Mark=2表示当前状态是对结点第三次访问

33_003

void postorder(BiTree T)

{

         p  = T;

         while(p)

         {

                   switch(p->mark)

                   {

                   case  0:

                            p->mark  = 1;

                            if(p->Lchild)

                            {

                                     p  = p->Lchild;

                            }

                            break;

                   case  1:

                            p->mark  = 2;

                            if(p->Rchild)

                            {

                                     p  = p->Rchild;

                            }

                            break;

                   case  2:

                            p->mark  = 0;

                            //...

                   }

         }

}

深度优先遍历图的非递归形式的算法

33_004

void DFS(Graph G, int v)

{

         visited[v]  = TRUE;

         VisitFunc(v);

         for(w  = FirstAdjVex(G, v); w != 0; w = NextAdjVex(G, v, w))

                   if(!  visited[w])

                            DFS(G,  w);

}

可见,栈中保留的信息应该是:当前访问的顶点和它当前的邻接点

33_005

void DFS(Graph g, int v)

{

         Visit(v);

         visited[v]  = TRUE;

         ...

         while(!  StackEmpty(S))

         {

                   v  = GetTop(S).vp;

                   w  = GetTop(S),wp;

                   if(w)

                   {

                            if(!  visited[w])

                            {

                                     Visit(w);

                                     visited[w]  = TRUE;

                                     ...

                            }

                            else

                            {

                                     w  = NextAdj(G, v, w);

                                     ...

                            }

                            Pop(S);

                   }

 

         }

}

广度优先搜索遍历的算法

33_006

void BFSTraverse(Graph G, Status(*  Visit)(int v))

{

         for(v  = 0; v < G.vexnum; ++ v)

                   visited[v]  = FALSE;

         InitQueue(Q);  //置空的辅助队列Q

         for(v  = 0; v < G.vexnum; ++v)

         {

                   if(!  visited[v])

                   {

                            //v尚未访问

                            visited[v]  = TRUE;

                            Visit(v);  //访问v

                            EnQueue(Q,  v); //v入队列

                            while(!  QueueEmpty(Q))

                            {

                                     DeQueue(Q,  u); //队列元素出队并置为u

                                     for(w  = FirstAdjVex(G, u); w != 0; w = NextAdjVex(G, u, w))

                                               if(!  visited[w])

                                               {

                                                        visited[w]  = TRUE;

                                                        Visit(w);

                                                        Enqueue(Q,  w); //

                                               }

                            }

                   }

         }

}

6.20编写按层次顺序(同一层自左至右)遍历二叉树的算法

33_007

void BFSTraverse(BiTree T)

{

         InitQueue(Q);  //置空的辅助队列Q

         if(T)

                   EnQueue(Q,  T); //根结点入队列

         while(!  QueueEmpty(Q))

         {

                   DeQueue(Q,  p); //队头元素出队并置为p

                   Visit(p);

                   if(p->Lchild)

                            EnQueue(Q,  p->Lchild); //左子树根入队列

                   if(p->Rchild)

                            EnQueue(Q,  p->Rchild); //右子树根入队列

         }

}

33_008

void BFSTraverse(CSTree T)

{

         InitQueue(Q);  //置空的辅助队列Q

         if(T)

                   EnQueue(Q,  T); //根结点入队列

         while(!  QueueEmpty(Q))

         {

                   DeQueue(Q,  p); //队头元素出队并置为p

                   Visit(p);

                   for(q  = p->firstchild; !q; q = q->nextsibling)

                            EnQueue(Q,  q); //子树根入队列

         }

}