数据结构-树1

树的基本定义

 D:D是具有相同特性的数据元素的集合, hi是di上的二元关系(说明了谁是谁的孩子,谁是谁的父母)

(di,{hi})就是一颗子树;

基本操作

 

 二叉树

 

 

基本操作 

 

 二叉树的性质

 

 

几种特殊的树

 二叉树的存储结构

二叉树的顺序存储

  

 

 缺点就是浪费空间

 

 

代码实现

 // c6-1.h 二叉树的顺序存储表示
 #define MAX_TREE_SIZE 100 // 二叉树的最大结点数
 typedef TElemType SqBiTree[MAX_TREE_SIZE]; // 0号单元存储根结点

 struct position
 {
   int level,order; // 结点的层,本层序号(按满二叉树计算)
 };
 // bo6-1.cpp 二叉树的顺序存储(存储结构由c6-1.h定义)的基本操作(23个)
//以数组的形式存储数据,但进行数据的读取操作却是树
 Status InitBiTree(SqBiTree T)
 { // 构造空二叉树T。因为T是固定数组,不会改变,故不需要&
   int i;
   for(i=0;i<MAX_TREE_SIZE;i++)
     T[i]=Nil; // 初值为空
   return OK;
 }

 void DestroyBiTree()
 { // 由于SqBiTree是定长类型,无法销毁
 }

 Status CreateBiTree(SqBiTree T)
 { // 按层序次序输入二叉树中结点的值(字符型或整型), 构造顺序存储的二叉树T
   int i=0;
 #if CHAR
   int l;
   char s[MAX_TREE_SIZE];
   cout<<"请按层序输入结点的值(字符),空格表示空结点,结点数≤"<<MAX_TREE_SIZE<<':'<<endl;
   gets(s); // 输入字符串
   l=strlen(s); // 求字符串的长度
   for(;i<l;i++) // 将字符串赋值给T
   {
     T[i]=s[i];
     if(i!=0&&T[(i+1)/2-1]==Nil&&T[i]!=Nil) // 此结点(不空)无双亲且不是根
     {
       cout<<"出现无双亲的非根结点"<<T[i]<<endl;
       exit(ERROR);
     }
   }
   for(i=l;i<MAX_TREE_SIZE;i++) // 将空赋值给T的后面的结点
     T[i]=Nil;
 #else
   cout<<"请按层序输入结点的值(整型),0表示空结点,输999结束。结点数≤"<<MAX_TREE_SIZE<<':'<<endl;
   while(1)
   {
     cin>>T[i];
     if(T[i]==999)
       break;
     if(i!=0&&T[(i+1)/2-1]==Nil&&T[i]!=Nil) // 此结点(不空)无双亲且不是根
     {
       cout<<"出现无双亲的非根结点"<<T[i]<<endl;
       exit(ERROR);
     }
     i++;
   }
   while(i<MAX_TREE_SIZE)
   {
     T[i]=Nil; // 将空赋值给T的后面的结点
     i++;
   }
 #endif
   return OK;
 }

 #define ClearBiTree InitBiTree // 在顺序存储结构中,两函数完全一样

 Status BiTreeEmpty(SqBiTree T)
 { // 初始条件: 二叉树T存在
   // 操作结果: 若T为空二叉树,则返回TRUE,否则FALSE
   if(T[0]==Nil) // 根结点为空,则树空
     return TRUE;
   else
     return FALSE;
 }

 int BiTreeDepth(SqBiTree T)
 { // 初始条件: 二叉树T存在。操作结果: 返回T的深度
   int i,j=-1;
   for(i=MAX_TREE_SIZE-1;i>=0;i--) // 找到最后一个结点
     if(T[i]!=Nil)
       break;
   i++; // 为了便于计算
   do
     j++;
   while(i>=pow(2,j));
   return j;
 }

 Status Root(SqBiTree T,TElemType &e)
 { // 初始条件: 二叉树T存在
   // 操作结果:  当T不空,用e返回T的根,返回OK;否则返回ERROR,e无定义
   if(BiTreeEmpty(T)) // T空
     return ERROR;
   else
   {
     e=T[0];
     return OK;
   }
 }

 TElemType Value(SqBiTree T,position e)
 { // 初始条件: 二叉树T存在,e是T中某个结点(的位置)
   // 操作结果: 返回处于位置e(层,本层序号)的结点的值
   return T[int(pow(2,e.level-1)+e.order-2)];
 }

 Status Assign(SqBiTree T,position e,TElemType value)
 { // 初始条件: 二叉树T存在,e是T中某个结点(的位置)
   // 操作结果: 给处于位置e(层,本层序号)的结点赋新值value
   int i=int(pow(2,e.level-1)+e.order-2); // 将层、本层序号转为矩阵的序号
   if(value!=Nil&&T[(i+1)/2-1]==Nil) // 给叶子赋非空值但双亲为空
     return ERROR;
   else if(value==Nil&&(T[i*2+1]!=Nil||T[i*2+2]!=Nil)) //  给双亲赋空值但有叶子(不空)
     return ERROR;
   T[i]=value;
   return OK;
 }

 TElemType Parent(SqBiTree T,TElemType e)
 { // 初始条件: 二叉树T存在,e是T中某个结点
   // 操作结果: 若e是T的非根结点,则返回它的双亲,否则返回"空"
   int i;
   if(T[0]==Nil) // 空树
     return Nil;
   for(i=1;i<=MAX_TREE_SIZE-1;i++)
     if(T[i]==e) // 找到e
       return T[(i+1)/2-1];
   return Nil; // 没找到e
 }

 TElemType LeftChild(SqBiTree T,TElemType e)
 { // 初始条件: 二叉树T存在,e是T中某个结点
   // 操作结果: 返回e的左孩子。若e无左孩子,则返回"空"
   int i;
   if(T[0]==Nil) // 空树
     return Nil;
   for(i=0;i<=MAX_TREE_SIZE-1;i++)
     if(T[i]==e) // 找到e
       return T[i*2+1];
   return Nil; // 没找到e
 }

 TElemType RightChild(SqBiTree T,TElemType e)
 { // 初始条件: 二叉树T存在,e是T中某个结点
   // 操作结果: 返回e的右孩子。若e无右孩子,则返回"空"
   int i;
   if(T[0]==Nil) // 空树
     return Nil;
   for(i=0;i<=MAX_TREE_SIZE-1;i++)
     if(T[i]==e) // 找到e
       return T[i*2+2];
   return Nil; // 没找到e
 }

 TElemType LeftSibling(SqBiTree T,TElemType e)
 { // 初始条件: 二叉树T存在,e是T中某个结点
   // 操作结果: 返回e的左兄弟。若e是T的左孩子或无左兄弟,则返回"空"
   int i;
   if(T[0]==Nil) // 空树
     return Nil;
   for(i=1;i<=MAX_TREE_SIZE-1;i++)
     if(T[i]==e&&i%2==0) // 找到e且其序号为偶数(是右孩子)
       return T[i-1];
   return Nil; // 没找到e
 }

 TElemType RightSibling(SqBiTree T,TElemType e)
 { // 初始条件: 二叉树T存在,e是T中某个结点
   // 操作结果: 返回e的右兄弟。若e是T的右孩子或无右兄弟,则返回"空"
   int i;
   if(T[0]==Nil) // 空树
     return Nil;
   for(i=1;i<=MAX_TREE_SIZE-1;i++)
     if(T[i]==e&&i%2) // 找到e且其序号为奇数(是左孩子)
       return T[i+1];
   return Nil; // 没找到e
 }

 void Move(SqBiTree q,int j,SqBiTree T,int i) // InsertChild()用到。加
 { // 把从q的j结点开始的子树移为从T的i结点开始的子树
   if(q[2*j+1]!=Nil) // q的左子树不空
     Move(q,(2*j+1),T,(2*i+1)); // 把q的j结点的左子树移为T的i结点的左子树
   if(q[2*j+2]!=Nil) // q的右子树不空
     Move(q,(2*j+2),T,(2*i+2)); // 把q的j结点的右子树移为T的i结点的右子树
   T[i]=q[j]; // 把q的j结点移为T的i结点
   q[j]=Nil; // 把q的j结点置空
 }

 Status InsertChild(SqBiTree T,TElemType p,Status LR,SqBiTree c)
 { // 初始条件: 二叉树T存在,p是T中某个结点的值,LR为0或1,非空二叉树c与T
   //           不相交且右子树为空
   // 操作结果: 根据LR为0或1,插入c为T中p结点的左或右子树。p结点的原有左或
   //           右子树则成为c的右子树
   int j,k,i=0;
   for(j=0;j<int(pow(2,BiTreeDepth(T)))-1;j++) // 查找p的序号
     if(T[j]==p) // j为p的序号
       break;
   k=2*j+1+LR; // k为p的左或右孩子的序号
   if(T[k]!=Nil) // p原来的左或右孩子不空
     Move(T,k,T,2*k+2); // 把从T的k结点开始的子树移为从k结点的右子树开始的子树
   Move(c,i,T,k); // 把从c的i结点开始的子树移为从T的k结点开始的子树
   return OK;
 }

 typedef int QElemType; // 设队列元素类型为整型(序号)
 #include "c3-3.h" // 顺序非循环队列
 #include "bo3-4.cpp" // 顺序非循环队列的基本操作
 Status DeleteChild(SqBiTree T,position p,int LR)
 { // 初始条件: 二叉树T存在,p指向T中某个结点,LR为1或0
   // 操作结果: 根据LR为1或0,删除T中p所指结点的左或右子树
   int i;
   Status k=OK; // 队列不空的标志
   SqQueue q;
   InitQueue(q); // 初始化队列,用于存放待删除的结点
   i=(int)pow(2,p.level-1)+p.order-2; // 将层、本层序号转为矩阵的序号
   if(T[i]==Nil) // 此结点空
     return ERROR;
   i=i*2+1+LR; // 待删除子树的根结点在矩阵中的序号
   while(k)
   {
     if(T[2*i+1]!=Nil) // 左结点不空
       EnQueue(q,2*i+1); // 入队左结点的序号
     if(T[2*i+2]!=Nil) // 右结点不空
       EnQueue(q,2*i+2); // 入队右结点的序号
     T[i]=Nil; // 删除此结点
     k=DeQueue(q,i); // 队列不空
   }
   return OK;
 }

 Status(*VisitFunc)(TElemType); // 函数变量
 void PreTraverse(SqBiTree T,int e)
 { // PreOrderTraverse()调用
   VisitFunc(T[e]);
   if(T[2*e+1]!=Nil) // 左子树不空
     PreTraverse(T,2*e+1);
   if(T[2*e+2]!=Nil) // 右子树不空
     PreTraverse(T,2*e+2);
 }

 Status PreOrderTraverse(SqBiTree T,Status(*Visit)(TElemType))
 { // 初始条件: 二叉树存在,Visit是对结点操作的应用函数
   // 操作结果: 先序遍历T,对每个结点调用函数Visit一次且仅一次。
   //           一旦Visit()失败,则操作失败
   VisitFunc=Visit;
   if(!BiTreeEmpty(T)) // 树不空
     PreTraverse(T,0);
   cout<<endl;
   return OK;
 }

 void InTraverse(SqBiTree T,int e)
 { // InOrderTraverse()调用
   if(T[2*e+1]!=Nil) // 左子树不空
     InTraverse(T,2*e+1);
   VisitFunc(T[e]);
   if(T[2*e+2]!=Nil) // 右子树不空
     InTraverse(T,2*e+2);
 }

 Status InOrderTraverse(SqBiTree T,Status(*Visit)(TElemType))
 { // 初始条件: 二叉树存在,Visit是对结点操作的应用函数
   // 操作结果: 中序遍历T,对每个结点调用函数Visit一次且仅一次。
   //           一旦Visit()失败,则操作失败
   VisitFunc=Visit;
   if(!BiTreeEmpty(T)) // 树不空
     InTraverse(T,0);
   cout<<endl;
   return OK;
 }

 void PostTraverse(SqBiTree T,int e)
 { // PostOrderTraverse()调用
   if(T[2*e+1]!=Nil) // 左子树不空
     PostTraverse(T,2*e+1);
   if(T[2*e+2]!=Nil) // 右子树不空
     PostTraverse(T,2*e+2);
   VisitFunc(T[e]);
 }

 Status PostOrderTraverse(SqBiTree T,Status(*Visit)(TElemType))
 { // 初始条件: 二叉树T存在,Visit是对结点操作的应用函数
   // 操作结果: 后序遍历T,对每个结点调用函数Visit一次且仅一次。
   //           一旦Visit()失败,则操作失败
   VisitFunc=Visit;
   if(!BiTreeEmpty(T)) // 树不空
     PostTraverse(T,0);
   cout<<endl;
   return OK;
 }

 void LevelOrderTraverse(SqBiTree T,Status(*Visit)(TElemType))
 { // 层序遍历二叉树
   int i=MAX_TREE_SIZE-1,j;
   while(T[i]==Nil)
     i--; // 找到最后一个非空结点的序号
   for(j=0;j<=i;j++)  // 从根结点起,按层序遍历二叉树
     if(T[j]!=Nil)
       Visit(T[j]); // 只遍历非空的结点
   cout<<endl;
 }

 void Print(SqBiTree T)
 { // 逐层、按本层序号输出二叉树
   int j,k;
   position p;
   TElemType e;
   for(j=1;j<=BiTreeDepth(T);j++)
   {
     cout<<"第"<<j<<"层: ";
     for(k=1;k<=pow(2,j-1);k++)
     {
       p.level=j;
       p.order=k;
       e=Value(T,p);
       if(e!=Nil)
         cout<<k<<':'<<e<<' ';
     }
     cout<<endl;
   }
 }

检测代码

 // main6-1.cpp 检验bo6-1.cpp的主程序,利用条件编译选择数据类型为char或int
 //#define CHAR 1 // 字符型
 #define CHAR 0 // 整型(二者选一)
 #include"c1.h"
 #if CHAR
   typedef char TElemType;
   TElemType Nil=' '; // 设字符型以空格符为空
 #else
   typedef int TElemType;
   TElemType Nil=0; // 设整型以0为空
 #endif
 #include"c6-1.h"
 #include"bo6-1.cpp"

 Status visit(TElemType e)
 {
   cout<<e<<' ';
   return OK;
 }

 void main()
 {
   Status i;
   int j;
   position p;
   TElemType e;
   SqBiTree T,s;
   InitBiTree(T);
   CreateBiTree(T);
   cout<<"建立二叉树后,树空否?"<<BiTreeEmpty(T)<<"(1:是 0:否) 树的深度="<<BiTreeDepth(T)<<endl;
   i=Root(T,e);
   if(i)
     cout<<"二叉树的根为:"<<e<<endl;
   else
     cout<<"树空,无根"<<endl;
   cout<<"层序遍历二叉树:"<<endl;
   LevelOrderTraverse(T,visit);
   cout<<"中序遍历二叉树:"<<endl;
   InOrderTraverse(T,visit);
   cout<<"后序遍历二叉树:"<<endl;
   PostOrderTraverse(T,visit);
   cout<<"请输入待修改结点的层号 本层序号: ";
   cin>>p.level>>p.order;
   e=Value(T,p);
   cout<<"待修改结点的原值为"<<e<<"请输入新值: ";
   cin>>e;
   Assign(T,p,e);
   cout<<"先序遍历二叉树:"<<endl;
   PreOrderTraverse(T,visit);
   cout<<"结点"<<e<<"的双亲为"<<Parent(T,e)<<",左右孩子分别为";
   cout<<LeftChild(T,e)<<","<<RightChild(T,e)<<",左右兄弟分别为";
   cout<<LeftSibling(T,e)<<","<<RightSibling(T,e)<<endl;
   InitBiTree(s);
   cout<<"建立右子树为空的树s:"<<endl;
   CreateBiTree(s);
   cout<<"树s插到树T中,请输入树T中树s的双亲结点 s为左(0)或右(1)子树: ";
   cin>>e>>j;
   InsertChild(T,e,j,s);
   Print(T);
   cout<<"删除子树,请输入待删除子树根结点的层号 本层序号 左(0)或右(1)子树: ";
   cin>>p.level>>p.order>>j;
   DeleteChild(T,p,j);
   Print(T);
   ClearBiTree(T);
   cout<<"清除二叉树后,树空否?"<<BiTreeEmpty(T)<<"(1:是 0:否) 树的深度="<<BiTreeDepth(T)<<endl;
   i=Root(T,e);
   if(i)
     cout<<"二叉树的根为:"<<e<<endl;
   else
     cout<<"树空,无根"<<endl;
 }

二叉树的链式存储 

基本操作的代码

 // c6-2.h 二叉树的二叉链表存储表示
 typedef struct BiTNode
 {
   TElemType data;
   BiTNode *lchild,*rchild; // 左右孩子指针
 }BiTNode,*BiTree;
 // bo6-2.cpp 二叉树的二叉链表存储(存储结构由c6-2.h定义)的基本操作(22个)
 Status InitBiTree(BiTree &T)
 { // 操作结果: 构造空二叉树T
   T=NULL;
   return OK;
 }

 void DestroyBiTree(BiTree &T)
 { // 初始条件: 二叉树T存在。操作结果: 销毁二叉树T
   if(T) // 非空树
   {
     if(T->lchild) // 有左孩子
       DestroyBiTree(T->lchild); // 销毁左孩子子树
     if(T->rchild) // 有右孩子
       DestroyBiTree(T->rchild); // 销毁右孩子子树
     free(T); // 释放根结点
     T=NULL; // 空指针赋0
   }
 }

 void CreateBiTree(BiTree &T)
 { // 算法6.4:按先序次序输入二叉树中结点的值(可为字符型或整型,在主程中
   // 定义),构造二叉链表表示的二叉树T。变量Nil表示空(子)树。有改动
   TElemType ch;
 #ifdef CHAR
   scanf("%c",&ch);
 #endif
 #ifdef INT
   scanf("%d",&ch);
 #endif
   if(ch==Nil) // 空
     T=NULL;
   else
   {
     T=(BiTree)malloc(sizeof(BiTNode));
     if(!T)
       exit(OVERFLOW);
     T->data=ch; // 生成根结点
     CreateBiTree(T->lchild); // 构造左子树
     CreateBiTree(T->rchild); // 构造右子树
   }
 }

 Status BiTreeEmpty(BiTree T)
 { // 初始条件: 二叉树T存在
   // 操作结果: 若T为空二叉树,则返回TRUE,否则FALSE
   if(T)
     return FALSE;
   else
     return TRUE;
 }

 #define ClearBiTree DestroyBiTree

 int BiTreeDepth(BiTree T)
 { // 初始条件: 二叉树T存在。操作结果: 返回T的深度
   int i,j;
   if(!T)
     return 0;
   if(T->lchild)
     i=BiTreeDepth(T->lchild);
   else
     i=0;
   if(T->rchild)
     j=BiTreeDepth(T->rchild);
   else
     j=0;
   return i>j?i+1:j+1;
 }

 TElemType Root(BiTree T)
 { // 初始条件: 二叉树T存在。操作结果: 返回T的根
   if(BiTreeEmpty(T))
     return Nil;
   else
     return T->data;
 }

 TElemType Value(BiTree p)
 { // 初始条件: 二叉树T存在,p指向T中某个结点
   // 操作结果: 返回p所指结点的值
   return p->data;
 }

 void Assign(BiTree p,TElemType value)
 { // 给p所指结点赋值为value
   p->data=value;
 }

 typedef BiTree QElemType; // 设队列元素为二叉树的指针类型
 #include"c3-2.h"
 #include"bo3-2.cpp"
 TElemType Parent(BiTree T,TElemType e)
 { // 初始条件: 二叉树T存在,e是T中某个结点
   // 操作结果: 若e是T的非根结点,则返回它的双亲,否则返回"空"
   LinkQueue q;
   QElemType a;
   if(T) // 非空树
   {
     InitQueue(q); // 初始化队列
     EnQueue(q,T); // 树根入队
     while(!QueueEmpty(q)) // 队不空
     {
       DeQueue(q,a); // 出队,队列元素赋给a
       if(a->lchild&&a->lchild->data==e||a->rchild&&a->rchild->data==e) // 找到e(是其左或右孩子)
         return a->data; // 返回e的双亲的值
       else // 没找到e,则入队其左右孩子指针(如果非空)
       {
         if(a->lchild)
           EnQueue(q,a->lchild);
         if(a->rchild)
           EnQueue(q,a->rchild);
       }
     }
   }
   return Nil; // 树空或没找到e
 }

 BiTree Point(BiTree T,TElemType s)
 { // 返回二叉树T中指向元素值为s的结点的指针。另加
   LinkQueue q;
   QElemType a;
   if(T) // 非空树
   {
     InitQueue(q); // 初始化队列
     EnQueue(q,T); // 根结点入队
     while(!QueueEmpty(q)) // 队不空
     {
       DeQueue(q,a); // 出队,队列元素赋给a
       if(a->data==s)
         return a;
       if(a->lchild) // 有左孩子
         EnQueue(q,a->lchild); // 入队左孩子
       if(a->rchild) // 有右孩子
         EnQueue(q,a->rchild); // 入队右孩子
     }
   }
   return NULL;
 }

 TElemType LeftChild(BiTree T,TElemType e)
 { // 初始条件: 二叉树T存在,e是T中某个结点
   // 操作结果: 返回e的左孩子。若e无左孩子,则返回"空"
   BiTree a;
   if(T) // 非空树
   {
     a=Point(T,e); // a是结点e的指针
     if(a&&a->lchild) // T中存在结点e且e存在左孩子
       return a->lchild->data; // 返回e的左孩子的值
   }
   return Nil; // 其余情况返回空
 }

 TElemType RightChild(BiTree T,TElemType e)
 { // 初始条件: 二叉树T存在,e是T中某个结点
   // 操作结果: 返回e的右孩子。若e无右孩子,则返回"空"
   BiTree a;
   if(T) // 非空树
   {
     a=Point(T,e); // a是结点e的指针
     if(a&&a->rchild) // T中存在结点e且e存在右孩子
       return a->rchild->data; // 返回e的右孩子的值
   }
   return Nil; // 其余情况返回空
 }

 TElemType LeftSibling(BiTree T,TElemType e)
 { // 初始条件: 二叉树T存在,e是T中某个结点
   // 操作结果: 返回e的左兄弟。若e是T的左孩子或无左兄弟,则返回"空"
   TElemType a;
   BiTree p;
   if(T) // 非空树
   {
     a=Parent(T,e); // a为e的双亲
     p=Point(T,a); // p为指向结点a的指针
     if(p->lchild&&p->rchild&&p->rchild->data==e) // p存在左右孩子且右孩子是e
       return p->lchild->data; // 返回p的左孩子(e的左兄弟)
   }
   return Nil; // 树空或没找到e的左兄弟
 }

 TElemType RightSibling(BiTree T,TElemType e)
 { // 初始条件: 二叉树T存在,e是T中某个结点
   // 操作结果: 返回e的右兄弟。若e是T的右孩子或无右兄弟,则返回"空"
   TElemType a;
   BiTree p;
   if(T) // 非空树
   {
     a=Parent(T,e); // a为e的双亲
     p=Point(T,a); // p为指向结点a的指针
     if(p->lchild&&p->rchild&&p->lchild->data==e) // p存在左右孩子且左孩子是e
       return p->rchild->data; // 返回p的右孩子(e的右兄弟)
   }
   return Nil; // 树空或没找到e的右兄弟
 }

 Status InsertChild(BiTree p,int LR,BiTree c) // 形参T无用
 { // 初始条件: 二叉树T存在,p指向T中某个结点,LR为0或1,非空二叉树c与T
   //           不相交且右子树为空
   // 操作结果: 根据LR为0或1,插入c为T中p所指结点的左或右子树。p所指结点的
   //           原有左或右子树则成为c的右子树
   if(p) // p不空
   {
     if(LR==0)
     {
       c->rchild=p->lchild;
       p->lchild=c;
     }
     else // LR==1
     {
       c->rchild=p->rchild;
       p->rchild=c;
     }
     return OK;
   }
   return ERROR; // p空
 }

 Status DeleteChild(BiTree p,int LR) // 形参T无用
 { // 初始条件: 二叉树T存在,p指向T中某个结点,LR为0或1
   // 操作结果: 根据LR为0或1,删除T中p所指结点的左或右子树
   if(p) // p不空
   {
     if(LR==0) // 删除左子树
       ClearBiTree(p->lchild);
     else // 删除右子树
       ClearBiTree(p->rchild);
     return OK;
   }
   return ERROR; // p空
 }

 void PreOrderTraverse(BiTree T,Status(*Visit)(TElemType))
 { // 初始条件: 二叉树T存在,Visit是对结点操作的应用函数。算法6.1,有改动
   // 操作结果: 先序递归遍历T,对每个结点调用函数Visit一次且仅一次
   if(T) // T不空
   {
     Visit(T->data); // 先访问根结点
     PreOrderTraverse(T->lchild,Visit); // 再先序遍历左子树
     PreOrderTraverse(T->rchild,Visit); // 最后先序遍历右子树
   }
 }

 void InOrderTraverse(BiTree T,Status(*Visit)(TElemType))
 { // 初始条件: 二叉树T存在,Visit是对结点操作的应用函数
   // 操作结果: 中序递归遍历T,对每个结点调用函数Visit一次且仅一次
   if(T)
   {
     InOrderTraverse(T->lchild,Visit); // 先中序遍历左子树
     Visit(T->data); // 再访问根结点
     InOrderTraverse(T->rchild,Visit); // 最后中序遍历右子树
   }
 }

 typedef BiTree SElemType; // 设栈元素为二叉树的指针类型
 #include"c3-1.h"
 #include"bo3-1.cpp"
 Status InOrderTraverse1(BiTree T,Status(*Visit)(TElemType))
 { // 采用二叉链表存储结构,Visit是对数据元素操作的应用函数。算法6.3
   // 中序遍历二叉树T的非递归算法(利用栈),对每个数据元素调用函数Visit
   SqStack S;
   InitStack(S);
   while(T||!StackEmpty(S))
   {
     if(T)
     { // 根指针进栈,遍历左子树
       Push(S,T);
       T=T->lchild;
     }
     else
     { // 根指针退栈,访问根结点,遍历右子树
       Pop(S,T);
       if(!Visit(T->data))
         return ERROR;
       T=T->rchild;
     }
   }
   printf("\n");
   return OK;
 }

 Status InOrderTraverse2(BiTree T,Status(*Visit)(TElemType))
 { // 采用二叉链表存储结构,Visit是对数据元素操作的应用函数。算法6.2
   // 中序遍历二叉树T的非递归算法(利用栈),对每个数据元素调用函数Visit
   SqStack S;
   BiTree p;
   InitStack(S);
   Push(S,T); // 根指针进栈
   while(!StackEmpty(S))
   {
     while(GetTop(S,p)&&p)
       Push(S,p->lchild); // 向左走到尽头
     Pop(S,p); // 空指针退栈
     if(!StackEmpty(S))
     { // 访问结点,向右一步
       Pop(S,p);
       if(!Visit(p->data))
         return ERROR;
       Push(S,p->rchild);
     }
   }
   printf("\n");
   return OK;
 }

 void PostOrderTraverse(BiTree T,Status(*Visit)(TElemType))
 { // 初始条件: 二叉树T存在,Visit是对结点操作的应用函数
   // 操作结果: 后序递归遍历T,对每个结点调用函数Visit一次且仅一次
   if(T) // T不空
   {
     PostOrderTraverse(T->lchild,Visit); // 先后序遍历左子树
     PostOrderTraverse(T->rchild,Visit); // 再后序遍历右子树
     Visit(T->data); // 最后访问根结点
   }
 }

 void LevelOrderTraverse(BiTree T,Status(*Visit)(TElemType))
 { // 初始条件:二叉树T存在,Visit是对结点操作的应用函数
   // 操作结果:层序递归遍历T(利用队列),对每个结点调用函数Visit一次且仅一次
   LinkQueue q;
   QElemType a;
   if(T)
   {
     InitQueue(q);
     EnQueue(q,T);
     while(!QueueEmpty(q))
     {
       DeQueue(q,a);
       Visit(a->data);
       if(a->lchild!=NULL)
         EnQueue(q,a->lchild);
       if(a->rchild!=NULL)
         EnQueue(q,a->rchild);
     }
     printf("\n");
   }
 }
 // main6-2.cpp 检验bo6-2.cpp的主程序,利用条件编译选择数据类型(另一种方法)
 #define CHAR // 字符型
 // #define INT // 整型(二者选一)
 #include"c1.h"
 #ifdef CHAR
   typedef char TElemType;
   TElemType Nil=' '; // 字符型以空格符为空
 #endif
 #ifdef INT
   typedef int TElemType;
   TElemType Nil=0; // 整型以0为空
 #endif
 #include"c6-2.h"
 #include"bo6-2.cpp"

 Status visitT(TElemType e)
 {
 #ifdef CHAR
   printf("%c ",e);
 #endif
 #ifdef INT
   printf("%d ",e);
 #endif
   return OK;
 }

 void main()
 {
   int i;
   BiTree T,p,c;
   TElemType e1,e2;
   InitBiTree(T);
   printf("构造空二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n",BiTreeEmpty(T),BiTreeDepth(T));
   e1=Root(T);
   if(e1!=Nil)
 #ifdef CHAR
     printf("二叉树的根为: %c\n",e1);
 #endif
 #ifdef INT
     printf("二叉树的根为: %d\n",e1);
 #endif
   else
     printf("树空,无根\n");
 #ifdef CHAR
   printf("请先序输入二叉树(如:ab三个空格表示a为根结点,b为左子树的二叉树)\n");
 #endif
 #ifdef INT
   printf("请先序输入二叉树(如:1 2 0 0 0表示1为根结点,2为左子树的二叉树)\n");
 #endif
   CreateBiTree(T);
   printf("建立二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n",BiTreeEmpty(T),BiTreeDepth(T));
   e1=Root(T);
   if(e1!=Nil)
 #ifdef CHAR
     printf("二叉树的根为: %c\n",e1);
 #endif
 #ifdef INT
     printf("二叉树的根为: %d\n",e1);
 #endif
   else
     printf("树空,无根\n");
   printf("中序递归遍历二叉树:\n");
   InOrderTraverse(T,visitT);
   printf("\n中序非递归遍历二叉树:\n");
   InOrderTraverse1(T,visitT);
   printf("中序非递归遍历二叉树(另一种方法):\n");
   InOrderTraverse2(T,visitT);
   printf("后序递归遍历二叉树:\n");
   PostOrderTraverse(T,visitT);
   printf("\n层序遍历二叉树:\n");
   LevelOrderTraverse(T,visitT);
   printf("请输入一个结点的值: ");
 #ifdef CHAR
   scanf("%*c%c",&e1);
 #endif
 #ifdef INT
   scanf("%d",&e1);
 #endif
   p=Point(T,e1); // p为e1的指针
 #ifdef CHAR
   printf("结点的值为%c\n",Value(p));
 #endif
 #ifdef INT
   printf("结点的值为%d\n",Value(p));
 #endif
   printf("欲改变此结点的值,请输入新值: ");
 #ifdef CHAR
   scanf("%*c%c%*c",&e2);
 #endif
 #ifdef INT
   scanf("%d",&e2);
 #endif
   Assign(p,e2);
   printf("层序遍历二叉树:\n");
   LevelOrderTraverse(T,visitT);
   e1=Parent(T,e2);
   if(e1!=Nil)
 #ifdef CHAR
     printf("%c的双亲是%c\n",e2,e1);
 #endif
 #ifdef INT
     printf("%d的双亲是%d\n",e2,e1);
 #endif
   else
 #ifdef CHAR
     printf("%c没有双亲\n",e2);
 #endif
 #ifdef INT
     printf("%d没有双亲\n",e2);
 #endif
   e1=LeftChild(T,e2);
   if(e1!=Nil)
 #ifdef CHAR
     printf("%c的左孩子是%c\n",e2,e1);
 #endif
 #ifdef INT
     printf("%d的左孩子是%d\n",e2,e1);
 #endif
   else
 #ifdef CHAR
     printf("%c没有左孩子\n",e2);
 #endif
 #ifdef INT
     printf("%d没有左孩子\n",e2);
 #endif
   e1=RightChild(T,e2);
   if(e1!=Nil)
 #ifdef CHAR
     printf("%c的右孩子是%c\n",e2,e1);
 #endif
 #ifdef INT
     printf("%d的右孩子是%d\n",e2,e1);
 #endif
   else
 #ifdef CHAR
     printf("%c没有右孩子\n",e2);
 #endif
 #ifdef INT
     printf("%d没有右孩子\n",e2);
 #endif
   e1=LeftSibling(T,e2);
   if(e1!=Nil)
 #ifdef CHAR
     printf("%c的左兄弟是%c\n",e2,e1);
 #endif
 #ifdef INT
     printf("%d的左兄弟是%d\n",e2,e1);
 #endif
   else
 #ifdef CHAR
     printf("%c没有左兄弟\n",e2);
 #endif
 #ifdef INT
     printf("%d没有左兄弟\n",e2);
 #endif
   e1=RightSibling(T,e2);
   if(e1!=Nil)
 #ifdef CHAR
     printf("%c的右兄弟是%c\n",e2,e1);
 #endif
 #ifdef INT
     printf("%d的右兄弟是%d\n",e2,e1);
 #endif
   else
 #ifdef CHAR
     printf("%c没有右兄弟\n",e2);
 #endif
 #ifdef INT
     printf("%d没有右兄弟\n",e2);
 #endif
   InitBiTree(c);
   printf("构造一个右子树为空的二叉树c:\n");
 #ifdef CHAR
   printf("请先序输入二叉树(如:ab三个空格表示a为根结点,b为左子树的二叉树)\n");
 #endif
 #ifdef INT
   printf("请先序输入二叉树(如:1 2 0 0 0表示1为根结点,2为左子树的二叉树)\n");
 #endif
   CreateBiTree(c);
   printf("先序递归遍历二叉树c:\n");
   PreOrderTraverse(c,visitT);
   printf("\n树c插到树T中,请输入树T中树c的双亲结点 c为左(0)或右(1)子树: ");
 #ifdef CHAR
   scanf("%*c%c%d",&e1,&i);
 #endif
 #ifdef INT
   scanf("%d%d",&e1,&i);
 #endif
   p=Point(T,e1); // p是T中树c的双亲结点指针
   InsertChild(p,i,c);
   printf("先序递归遍历二叉树:\n");
   PreOrderTraverse(T,visitT);
   printf("\n删除子树,请输入待删除子树的双亲结点  左(0)或右(1)子树: ");
 #ifdef CHAR
   scanf("%*c%c%d",&e1,&i);
 #endif
 #ifdef INT
   scanf("%d%d",&e1,&i);
 #endif
   p=Point(T,e1);
   DeleteChild(p,i);
   printf("先序递归遍历二叉树:\n");
   PreOrderTraverse(T,visitT);
   printf("\n");
   DestroyBiTree(T);
 }

除了二叉链表还有三叉链表,三叉链表就是在二叉链表的基础上多一个指向父节点的指针

静态链表实现二叉树存储

 先序遍历

 

void PreOrderTraverse(BiTree T,Status(*Visit)(TElemType))
 { // 初始条件: 二叉树T存在,Visit是对结点操作的应用函数。算法6.1,有改动
   // 操作结果: 先序递归遍历T,对每个结点调用函数Visit一次且仅一次
   if(T) // T不空
   {
     Visit(T->data); // 先访问根结点
     PreOrderTraverse(T->lchild,Visit); // 再先序遍历左子树
     PreOrderTraverse(T->rchild,Visit); // 最后先序遍历右子树
   }
 }

中序遍历

 void InOrderTraverse(BiTree T,Status(*Visit)(TElemType))
 { // 初始条件: 二叉树T存在,Visit是对结点操作的应用函数
   // 操作结果: 中序递归遍历T,对每个结点调用函数Visit一次且仅一次
   if(T)
   {
     InOrderTraverse(T->lchild,Visit); // 先中序遍历左子树
     Visit(T->data); // 再访问根结点
     InOrderTraverse(T->rchild,Visit); // 最后中序遍历右子树
   }
 }

以非递归算法实现中序遍历

Status InOrderTraverse1(BiTree T,Status(*Visit)(TElemType))
 { // 采用二叉链表存储结构,Visit是对数据元素操作的应用函数。算法6.3
   // 中序遍历二叉树T的非递归算法(利用栈),对每个数据元素调用函数Visit
   SqStack S;
   InitStack(S);
   while(T||!StackEmpty(S))
   {
     if(T)
     { // 根指针进栈,遍历左子树
       Push(S,T);
       T=T->lchild;
     }
     else
     { // T为空,根指针退栈,访问根结点,遍历右子树
       Pop(S,T);
       if(!Visit(T->data))
         return ERROR;
       T=T->rchild;
     }
   }
   printf("\n");
   return OK;
 }

 

判断节点是否有左子树,有的话就将这个节点入栈,然后左子树成为新的节点;如果不存在左子树就访问这个节点的值,然后访问他的右子树,右子树不存在就返回这个节点的父节点;.........

后序遍历

void PostOrderTraverse(BiTree T,Status(*Visit)(TElemType))
 { // 初始条件: 二叉树T存在,Visit是对结点操作的应用函数
   // 操作结果: 后序递归遍历T,对每个结点调用函数Visit一次且仅一次
   if(T) // T不空
   {
     PostOrderTraverse(T->lchild,Visit); // 先后序遍历左子树
     PostOrderTraverse(T->rchild,Visit); // 再后序遍历右子树
     Visit(T->data); // 最后访问根结点
   }
 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: (Tree)是一种非线性的数据结构,它由n(n>=0)个结点构成,其中一个结点为根结点,其余结点可分为m(m>=0)个互不相交的子集T1、T2、……、Tm,其中每一个子集本身又是一棵,并称为根的子的特点是:每个结点有零个或多个子结点;没有父结点的结点称为根结点;每一个非根结点有且只有一个父结点;除了根结点之外,每个子结点可以分为多个不相交的子。 下面是一个基本的的结构定义: ```c // 的结构体定义 typedef struct TreeNode { int data; // 数据域 struct TreeNode *firstChild;// 第一个子节点 struct TreeNode *nextSibling;// 兄弟节点 }TreeNode, *Tree; ``` 其中,data表示结点的数据域,firstChild指向该结点的第一个子节点,nextSibling指向该结点的下一个兄弟节点。 下面是一个创建的函数: ```c // 创建 Tree createTree(int data) { Tree root = (Tree)malloc(sizeof(TreeNode)); root->data = data; root->firstChild = NULL; root->nextSibling = NULL; return root; } ``` 下面是一个向中添加子节点的函数: ```c // 添加子节点 void addChild(Tree parent, int data) { Tree child = (Tree)malloc(sizeof(TreeNode)); child->data = data; child->firstChild = NULL; child->nextSibling = NULL; if (parent->firstChild == NULL) parent->firstChild = child; else { Tree p = parent->firstChild; while (p->nextSibling != NULL) p = p->nextSibling; p->nextSibling = child; } } ``` 下面是一个先序遍历的函数: ```c // 先序遍历 void preOrderTraversal(Tree root) { if (root != NULL) { printf("%d ", root->data); preOrderTraversal(root->firstChild); preOrderTraversal(root->nextSibling); } } ``` 下面是一个后序遍历的函数: ```c // 后序遍历 void postOrderTraversal(Tree root) { if (root != NULL) { postOrderTraversal(root->firstChild); postOrderTraversal(root->nextSibling); printf("%d ", root->data); } } ``` 下面是一个层次遍历的函数: ```c // 层次遍历 void levelOrderTraversal(Tree root) { Queue q; initQueue(&q); if (root != NULL) { enQueue(&q, root); while (!isQueueEmpty(&q)) { Tree p = deQueue(&q); printf("%d ", p->data); if (p->firstChild != NULL) enQueue(&q, p->firstChild); if (p->nextSibling != NULL) enQueue(&q, p->nextSibling); } } } ``` 其中,Queue是一个队列结构体。 以上就是一个简单的的实现。 ### 回答2: 是一种常见的数据结构,用于存储具有层次关系的数据。它由节点和边组成,通常包含一个根节点和若干子节点。 在C语言中,我们可以使用结构体来定义的节点。一个最基本的节点结构体可能包含两个成员变量:数据和指向子节点的指针。例如: ``` typedef struct TreeNode { int data; struct TreeNode* left; struct TreeNode* right; } TreeNode; ``` 上述代码定义了一个名为TreeNode的结构体,它包含一个整型数据成员和两个指向左子节点和右子节点的指针。 为了方便操作,我们可以定义一些基本的函数。其中,创建节点的函数可以使用动态内存分配来分配新节点的内存空间。例如: ``` TreeNode* createNode(int data) { TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode)); newNode->data = data; newNode->left = NULL; newNode->right = NULL; return newNode; } ``` 我们还可以定义插入节点、删除节点、搜索节点等函数来操作的结构。 除此之外,还可以实现一些遍历的算法,如先序遍历、中序遍历和后序遍历。这些遍历方法可以递归地遍历的节点,并对节点进行指定的操作。 编写的操作函数时,需要考虑到不同的特点,例如二叉搜索要保持左子节点的值小于根节点,右子节点的值大于根节点。 总之,编写一个经典C语言数据结构-需要定义节点的结构体,实现节点的创建、插入、删除和搜索等操作函数,同时可以实现遍历的算法。 ### 回答3: 是一种经典的数据结构,C语言可以很方便地实现的相关操作。首先,我们可以定义一个的节点结构体: ```c typedef struct Node { int data; // 节点存储的数据 struct Node* left; // 左子指针 struct Node* right; // 右子指针 } Node; ``` 接下来,我们可以实现一些的基本操作,例如创建、插入节点、删除节点和遍历。下面是一个简单的示例: ```c // 创建一个节点 Node* createNode(int data) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = data; newNode->left = NULL; newNode->right = NULL; return newNode; } // 在中插入一个节点 Node* insertNode(Node* root, int data) { if (root == NULL) { return createNode(data); } else if (data < root->data) { root->left = insertNode(root->left, data); } else if (data > root->data) { root->right = insertNode(root->right, data); } return root; } // 在中删除一个节点 Node* deleteNode(Node* root, int data) { if (root == NULL) { return root; } else if (data < root->data) { root->left = deleteNode(root->left, data); } else if (data > root->data) { root->right = deleteNode(root->right, data); } else { if (root->left == NULL) { Node* temp = root->right; free(root); return temp; } else if (root->right == NULL) { Node* temp = root->left; free(root); return temp; } Node* temp = findMinNode(root->right); root->data = temp->data; root->right = deleteNode(root->right, temp->data); } return root; } // 遍历:前序遍历(中--右) void preOrderTraversal(Node* root) { if (root != NULL) { printf("%d ", root->data); preOrderTraversal(root->left); preOrderTraversal(root->right); } } ``` 这只是的基本实现,还有很多其他操作,例如查找节点、判断是否为空、计算的高度等。可以根据具体需求进行扩展。通过以上实现,我们可以使用经典的C语言来构建和操作结构。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jjj34

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值