您的位置:首页 > 理论基础 > 数据结构算法

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

2013-05-28 06:53 363 查看
6.3 二叉树的存储结构

一、二叉树的顺序存储表示

#define MAX_TREE_SIZE 100 //二叉树的最大结点数

typedef TElemType SqBiTree[MAX_TREE_SIZE];//0号单元存储根结点

SqBiTree bt;

二、二叉树的链式存储表示

1.二叉链表

2.三叉树

3.双亲链表

4.线索链表

 

1.      二叉链表

typedef struct BiTNode

{

         TElemType  data;

         struct  BiTNode *lchild, *rchild; //左右孩子指针

}BiTNode, *BiTree;

2.三叉链表

typedef struct TriTNode

{

         TElemType  data;

         struct TriTNode *lchild, *rchild; //左右孩子指针

         struct  TriTNode *parent;

}TriTNode, *TriTree;

3双亲链表

typedef struct BPTNode

{

         TElemType  data;

         int  *parent; //指向双亲的指针

         char  LRTag; //左右孩子标识域

}BPTNode;

 

typedef struct BPTree

{

         BPTNode  nodes[MAX_TREE_SIZE];

         int  num_node; //结点数目

         int  root; //根结点的位置

}BPTree;

4.线索链表

 

6.4 二叉树的遍历

一、问题的提出

顺着某一条搜索路径巡访二叉树中的结点,使得每个结点均被访问一次,而且仅被访问一次

“访问”的含义可以很广、如:输出结点的信息等。

“遍历”是任何类型均有的操作,对线性结构而言,只有一条搜索路径(因为每个结点均只有一个后继),故不需要另加讨论。而二叉树是非线性结构,每个结点有两个后继,则存在如何遍历即按什么样的搜索路径遍历的问题。

对“二叉树”而言,可以有三条搜索路径:

1.      先上后下的按层次遍历

2.      先左(子树)后右(子树)的遍历

3.      先右(子树)后左(子树)的遍历

二、先左(子树)后右(子树)的遍历

先(根)序的遍历算法:若二叉树为空树,则空操作;否则,1)访问根结点;2)先序遍历左子树;3)后序遍历右子树

中(根)序的遍历算法:若二叉树为空树,则空操作;否则,1)中序遍历左子树;2)访问根结点;3)后序遍历右子树

后(跟)序的变量算法:若二叉树为空树,则空操作;否则,1)后序遍历左子树;2)后续遍历右子树;3)访问根结点

三、算法的递归描述

19_001

void Preorder(BiTree T, void(*  visit)(TElemType &c))

{

         //先序遍历二叉树

         if(T)

         {

                   visit(T->data);  //访问结点

                   Preorder(T->lchild,  visit); //遍历左子树

                   Preorder(T->rchild,  visit); //遍历右子树

         }

}

四、中序遍历算法的非递归描述

19_002

BiTNode *GoFarLeft(BiTree T, Stack *S)

{

         if(!  T)

                   return  NULL;

         while(T->lchild)

         {

                   Push(S,  T);

                   T  = T->lchild;

         }

         return  T;

}

 

19_003

//非递归中序遍历的算法

void Inorder_l(BiTree T, void(*  visit)(TelemType &e))

{

         Stack  *S;

         t  = GoFarLeft(T, S); //找到最左下的结点

         while(t)

         {

                   visit(t->data);

                   if(t->rchild)

                            t  = GoFarLeft(t->rchild, S);

                   else  if(! StackEmpty(S)) //栈不空时退栈

                            t  = Pop(S);

                   else

                            t  = NULL; //栈空表明遍历结束

         }

}

 

一、遍历算法的应用

1.统计二叉树中叶子结点的个数(先序遍历)

020_001

void CountLeaf(BiTree T, int &count)

{

         if(T)

         {

                   if((!  T->lchild) && (!T->rchild))

                            count  ++;

                   CountLeaf(T->lchild);

                   CountLeaf(T->rchild);

         }

}

2.      求二叉树的深度(后序遍历)

020_002

int Depth(BiTree T)

{

         if(!  T)

                   depthval  = 0;

         else

         {

                   depthLeft  = Depth(T->lchild);

                   depthRight  = Depth(T->rchild);

                   depthval  = 1+(depthLeft > depthRight ? depthLeft : depthRight);

         }

         return  depthval;

}

3.      复制二叉树(后序遍历)

020_003

//生成一个二叉树

BiTNode *GetTreeNode(TElemType item,  BiTNode *lptr, BiTNode *rptr)

{

         if(!  (T = (BiTNode *) malloc(sizeof(BiTNode))))

                   exit(1);

         T->data  = item;

         //T->lchild  = T->rchild = NULL; //存在问题应该改为下面2行

T->lchild  = lptr;

T->rchild  = rptr;

         return  T;

}

020_004

BiTNode *CopyTree(BiTNode *T)

{

         if(!  T)

                   return  NULL;

         if(T->lchild)

                   newlptr  = CopyTree(T->lchild);

         else

                   newlptr  = NULL;

         if(T->rchild)

                   newrptr  = CopyTree(T->rchild);

         else

                   newrptr  = NULL;

         newnode  = GetTreeNode(T->data, newlptr, newrptr);

         return  newnode;

}

 

4.      建立二叉树的存储结构

按给定的先序序列建立二叉树链表

20_005

Status CreateBiTree(BiTree &T)

{

         scanf(&  ch);

         if(ch  == '')

                   T  = NULL;

         else

         {

                   if(!  (T = (BiTNode *) malloc(sizeof(BiTNode)))

                            exit(OVERFLOW);

                   T->data  = ch; //生成根结点

                   CreateBiTree(T->lchild);  //构造左子树

                   CreateBiTree(T->rchild);  //构造右子树

         }

         return  OK;

}// CreateBiTree

按给定的表达式建相应二叉树

由先缀表示建树

20_006

vodi CrtExptree(BiTree &T,  char exp[])

{

         InitStack(S);

         Push(S,  '#');

         InitStack(PTR);

         p  = exp;

         ch  = *p;

         while(!  GetTop(S) == '#' && ch == '#'))

         {

                   if(!  IN(ch, OP))

                            CrtNode(t,  ch); //建立叶子结点并入栈

                   else

                   {

                            switch(ch)

                            {

                            case  '(':

                                     Push(S,  ch);

                                     break;

                            case  ')':

                                     //...

                            default:  //default

                            }//switch

                   }//else

                   if(ch  != '#')

                   {

                            p ++;

                            ch  = *p;

                   }

         }//  while

         Pop(PTR,  t);

}//CrtExptree

20_007

Pop(S, c);

while(c != '(')

{

         CrtSubtree(t,  c); //创建二叉树并入栈

         Pop(S,  c);

}

break;

 

while(! Gettop(S, c) &&  (precede(c, ch)))

{

         CrtSubtree(t,  c);

         Pop(S,  c);

}

if(ch != '#')

         Push(S,  ch);

break;

建叶子结点的算法为:

20_008

void CrtNode(BiTree &T, char ch)

{

         T  = (BiTNode *) malloc(sizeof(BiTNode));

         T->data  = char;

         T->lchild  = T->rchild = NULL;

         Push(PTR,  T);

}

建子树的算法为:

20_009

void CrtSubtree(BiTree &T, char c)

{

         T  = (BiTNode *) malloc(sizeof(BiTNode));

         T->data  = c;

         Pop(PTR,  rc);

         T->rchild  = rc;

         Pop(PTR,  lc);

         T->lchild  = lc;

         Push(PTR,  T);

}

由二叉树的先序和中序序列建树

例如:已知二叉树

先序序列:abcdefg

中序序列:cdbaegf

分析可得:根结点是a
左子树是bcd 右子树是egf

 

6.5 线索二叉树

何谓线索二叉树

线索链表的遍历算法

如何建立线索表?

 

遍历二叉树的结果是,求得结点的一个线性序列

指向该线性序列中的“前驱”和“后继”的指针,称作“线索”

包含“线索”的存储结构,称作“线索链表”

与其相应的二叉树,“线索二叉树”

对线索链表中结点的约定:

在二叉链表的结点中增加两个标识域,并作如下规定:

若该结点的左子树不空

则lchild域的指针指向其左子树,且左标志域的值为0

否则,lchild域的指针指向其“前驱”,且左标志的值为1

若该节点的右子树不空

则rchild域的指针指向其右子树,且右标志域的值为0,“指针Link”

否则,rchild域的指针指向其“后继”,且右标志的值为1“指针Thread”。

线索链表的结构描述:

21_001

typedef enum(Link, Thread) PointerThr;

//Link == 0;指针,Thread==1;
线索

typedef struct BiThrNode

{

         TElemType  data;

         struct  BiThrNode *lchild, *rchild; //左右指针

         PointerThr  LTag, RTag; //左右标志

}BiThrNode, *BiThrTree;

二、线索链表的遍历算法

21_002

for(p = firstNode(T); p; p = Succ(p))

         Visit(p);

中序线索化链表的遍历算法:

中序遍历的第一个结点?

在中序线索化链表中结点的后继?

21_003

Status InOrderTraverse_Thr(BiTree T,  Status(*Visit)(TElemType e))

{

         p  = T->child; //p指向根结点

         while(p  != T) //空树或遍历结束时 p==T

         {

                   while(p->LTag  == Link)

                            p  = p->lchild;

                   if(!  Visit(p->data))

                            return  ERROR;

                   while(p->RTag  == Thread && p->rchild != t)

                   {

                            p  = p->rchild;

                            Visit(p->data);  //访问后继结点

                   }

                   p  = p->rchild; //p进其右子树跟

         }

         return  OK;

}// InOrderTraverse_Thr

三、如何建立线索链表

在中序遍历过程中修改结点的左、又指针域,以保存当前访问结点的“前驱”和“后继”信息。遍历过程中,附设指针pre,并始终保持指针pre指向当前访问的,指针p所指结点的前驱。

21_004

void InThreading(BiThrTree p)

{

         if(p)

         {

                   InThrcading(p->lchild);  //左子树线索化

                   if(!  p->lchild)

                   {

                            p->LTag  = Thread;

                            p->lchild  - pre; //建前驱线索

                   }

                   if(!  pre->rchild)

                   {

                            Pre->RTag  = Thread;

                            pre->rchild  = p; //建后继限速

                   }

                   pre  = p;

                   InThreading(p->rchild);  //右子树线索化

         }

}//InThreading

 

21_005

Status InOrderThreading(BiThrTree  &Thrt, BiThrTree T)

{

         if(!  Thrt = (BiThrTree) malloc(sizeof(BiThrNode))))

                   exit(OVERFLOW);

         Thrt->LTag  = Link;

         Thrt->RTag  = Thread;

         Thrt->rchild  = Thrt;

         if(!  T)

                   Thrt->lchild  = Thrt; //添加头结点

         else

         {

                   Thrt->lchild  = T;

                   pre  = Thrt;

                   InThreading(T);

                   pre->rchild  = Thrt;

                   pre->RTag  = Thread;

                  Thrt->rchild = pre; //处理最后一个结点

         }

         return  OK;

}//InOrderThreading

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: