本站首页    管理页面    写新日志    退出


«June 2026»
123456
78910111213
14151617181920
21222324252627
282930


公告
暂无公告...

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:
日志总数:32
评论数量:44
留言数量:0
访问次数:181886
建立时间:2005年1月4日




数据结构--树和二叉树
文章收藏

eaglebetter 发表于 2006/8/6 0:24:12

6-1  树的定义和术语6-1-1  树的定义1.树的定义2.树的其他表示法 (1) 嵌套集合法(2) 圆括号表示法(3) 凹入法6-1-2  基本术语6-2  二叉树6-2-1  二叉树的定义1.定义2.二叉树的形态3.二叉树的基本操作:6-2-2  二叉树的性质(1) 满二叉树(2) 完全二叉树6-2-3  二叉树的存储1.顺序存储结构(1) 一维数组存储法(2) 二维数组存储法2.链式存储结构(1) 二叉链表存储typedef struct BT       // 定义二叉树结构体{ char data;             // 定义数据域BT *lchild;                // 定义结点的左指针BT *rchild;                // 定义结点的右指针}BT;                           // 将BT定义为指向二叉树结点结构体的指针类型(2) 三叉链表存储6-3  遍历二叉树和线索二叉树6-3-1  遍历二叉树1.先序遍历(DLR)    void Preorder(BT *T)       // 先序遍历二叉树BT{   if  (bt==NULL)  return;     // 递归调用的结束条件    {  printf(T->data);       // 输出结点的数据域  Preorder(T->lchild);    // 先序递归遍历左子树  Preorder(T->rchild);    // 先序递归遍历右子树    }}2.中序遍历(LDR)void Inorder(BT *T)           // 中序遍历二叉树BT{ if  (bt==NULL) return;     // 递归调用的结束条件  { Inorder(T->lchild);       //  中序递归遍历左子树printf(T->data);          // 输出结点的数据域Inorder(T->rchild);        // 中序递归遍历右子树  }}3.后序遍历(LRD)void Postorder(BT *T)           // 后序遍历二叉树BT{ if  (bt==NULL) return;       // 递归调用的结束条件    { Postorder(T->lchild);     // 后序递归遍历左子树    Postorder(T->rchild);    // 后序递归遍历右子树  printf(T->data);          // 输出结点的数据域    }}4.层次遍历void Levelorder(BT *T)         // 按层次遍历二叉树BT{ int i,j;BT *q[MAXLEN],*p;           // 设置一个数组来模拟队列p=T;if(p!=NULL)  // 若二叉树非空,则根结点地址入队     { i=1;q[i]=p;j=2; }while(i!=j)    { p=q[i];printf(p->data);         // 访问队首结点的数据域 if( p->lchild!=NULL)            // 将队首结点的左孩子结点入队列{ q[j]=p->lchild;j++;}if(p->rchild!=NULL)          // 将队首结点的右孩子结点入队列{ q[j]=p->rchild;j++; }i++;  }}6-3-2  恢复二叉树1.由先序和中序恢复二叉树2.由中序和后序恢复二叉树6-3-3  线索二叉树1.什么是线索二叉树2.线索二叉树的方法3.线索二叉树的优点4.线索二叉树的缺点6-4  二叉树的转换6-4-1  一般树转换为二叉树1.一般树和二叉树的二叉链表存储结构比较2.将一棵树转换为二叉树的方法:6-4-2  森林转换为二叉树【例6-5】将图6-22给出的森林转换为二叉树。6-4-3  二叉树转换为树和森林【例6-6】将图6-24给出二叉树转换为树的过程。6-5  二叉树的应用6-5-1  二叉树的基本应用1.统计二叉树叶子结点数(1) 基本思想(2) 算法void Leafnum(BT *T)       // 求二叉树叶子结点数{  if(T)                          // 若树不为空                   // 开始时,BT为根结点所在的链结点的指针,返回值为BT的叶子数{  if(T->lchild==NULL&&T->rchild==NULL)count++;              // 若左子树和右子树都为空,count计数器加1   Leafnum(T->lchild);      // 递归统计T的左子树叶子结点数   Leafnum(T->rchild);      // 递归统计T的右子树叶子结点数}}2.求二叉树结点总数(1) 基本思想(2) 算法void Nodenum(BT *T)           // 求二叉树总结点数{  if(T)    { count++;                   // 如果二叉树不空,加上一个结点数Nodenum(T->lchild);        // 递归统计T的左子树结点数Nodenum(T->rchild);        // 递归统计T的右子树结点数    }}3.求二叉树的深度(1) 基本思想(2) 算法int TreeDepth(BT *T)         // 求二叉树深度{int ldep,rdep;                  // 定义两个整型变量,用以存放左、右子树的深度 if(T==NULL)                   // 若树空则返回0  return 0;else{ ldep=TreeDepth(T->lchild); // 递归统计T的左子树深度   rdep=TreeDepth(T->rchild); // 递归统计T的右子树深度   if(ldep>rdep)          // 若左子树深度大于右子树深度,则返回左子树深度加1 return ldep+1;   else return rdep+1;     // 否则返回右子树深度加1}}4.查找数据元素(1) 基本思想(2)算法BiTree  Search(BiTree bt,elemtype x){ BiTree  p;  if (bt->data==x) return bt;    // 若查找根结点成功,即返回。否则,分别在左、右子树查找  if (bt->lchild!=NULL) return (Search (bt->lchild,x));                            // 在bt->lchild为根结点指针的二叉树中查找数据元素x  if (bt->rchild!=NULL) return (Search (bt->rchild,x));                          // 在bt->rchild为根结点指针的二叉树中查找数据元素x  return NULL;          // 查找失败,返回}6-5-2  标识符树与表达式1.标识符树的特点2.从表达式产生标识符树的方法3.应用举例6-6  哈夫曼树及其应用6-6-1 哈夫曼树的引入1.几个术语2.如何求树的带权路径长度3.为什么要使用哈夫曼树if  (n<60)  b="E";else if (n<70)  b="D"      else if (n<80)  b="C"            else if (n<90)  b="B"                  else  b="A";表6-1分数n 0~59 60~69 70~79 80~89 90~100 比例数 5% 15% 40% 30% 10% 等级b E D C B A 6-6-2  哈夫曼树的建立1.哈夫曼树构成的基本思想是:2.哈夫曼树的构造算法6-6-3  哈夫曼编码1.什么是哈夫编码2.求哈夫曼编码的方法(1) 构造哈夫曼树(2) 在哈夫曼树上求叶子结点的编码3.哈夫曼树及哈夫曼编码的源程序#include <stdio.h>#define MAXLEN 100typedef struct                          // 定义结构体{ int weight;                       // 定义一个整型权值变量int lchild,rchild,parent;      // 定义左、右孩子及双亲指针}HTNode;typedef HTNode HFMT [MAXLEN];      // 是向量类型的int n;void InitHFMT (HFMT  T)              // 初始化  { int i;printf ("\n\t\t请输入共有多少个权值 (小于100):");scanf ("%d",&n);getchar();for (i=0; i<2*n-1; i++){ T[i].weight=0;T[i].lchild=-1;T[i].rchild=-1;T[i].parent=-1;}}void InputWeight(HFMT T)            // 输入权值{ int w;int i;for (i=0; i<n;i++){ printf ("\n\t\t输入第%d个权值:",i+1);scanf ("%d",&w);getchar();T[i].weight=w;  }}void SelectMin (HFMT T, int i, int *p1,int *p2)  // 选择两个结点中小的结点{ long min1=999999;            // 预设两个值,并使它大于可能出现的最大权值long min2=999999;           int j;for (j=0;j<=i;j++){  if (T[j].parent==-1){ if (min1>T[j].weight){ min1=T[j].weight;   // 找出最小的权值*p1=j;             // 通过*p1带回序号}}}for (j=0;j<=i;j++){ if (T[j].parent==-1){ if (min2>T[j].weight&&j!=(*p1)){ min2=T[j].weight;      // 找出次最小的权值*p2=j;            // 通过*p2带回序号}}}}                                       // 选择结束void CreatHFMT (HFMT T)        // 构造哈夫曼树,T[2*n-1]为其根结点{ int i,p1,p2;InitHFMT (T);InputWeight (T);for  (i=n;i<2*n-1;i++){ SelectMin (T,i-1,&p1,&p2);T[p1].parent=T[p2].parent=i;T[i].lchild=T[p1].weight;T[i].rchild=T[p2].weight;T[i].weight=T[p1].weight+T[p2].weight;}}void PrintHFMT (HFMT T)             // 输出向量状态表{ int i,k=0;for (i=0; i<2*n-1; i++)while (T[i].lchild!=-1){   if (!(k%2))printf ("\n");printf ("\t\t(%d %d),(%d %d)",T[i].weight,T[i].lchild,T[i].weight,T[i].rchild);k++;break;}}void hfnode (HFMT T,int i,int j){ j=T[i].parent;if (T[j].rchild= =T[i].weight) printf("1");else               printf("0");if(T[j].parent!= -1) i=j,hfnode (T,i,j);}void huffmannode (HFMT T)             // 求哈夫曼编码{  int i,j,a,k=0;printf ("\n");for (i=0;i<n;i++){ j=0;a=i;if (!(k%2))printf ("\n");  printf("\t\t%i: ",T[i].weight);k++;hfnode(T,i,j);i=a;}}void main()                         // 主函数{ HFMT HT;CreatHFMT(HT);PrintHFMT(HT);huffmannode(HT);printf("\n ");}小结实验6  树子系统1.实验目的2.实验内容3.实验步骤:4.参考程序#include <stdio.h>#define MAXLEN 100typedef struct BT             // 定义二叉树结构体{ char data;BT* lchild;BT*rchild;}BT;BT *CreateBT();                void ShowTree(BT *T);void Preorder(BT *T);void Postorder(BT *T);void Levelorder(BT *T);void Inorder(BT *T);void Leafnum(BT *T);void Nodenum(BT *T);int TreeDepth(BT *T);int count=0;           // 定义计算结点个数数的变量void main()                              // 树子系统住函数{ BT *T=NULL;char ch1,ch2,a;ch1='y';while(ch1=='y'||ch1=='Y'){ printf("\n\n\n\n");printf("\n\n\t\t\t二 叉 树 子 系 统\n");printf("\n\t\t***************************************");printf("\n\t\t*           1---------建 二 叉 树           *");printf("\n\t\t*           2---------凹 入 显 示           *");printf("\n\t\t*           3---------先 序 遍 历           *");printf("\n\t\t*           4---------中 序 遍 历           *");printf("\n\t\t*           5---------后 序 遍 历           *");printf("\n\t\t*           6---------层 次 遍 历           *");printf("\n\t\t*           7---------求 叶 子 数           *");printf("\n\t\t*           8---------求 结 点 数           *");printf("\n\t\t*           9---------求 树 深 度           *");printf("\n\t\t*           0---------返       回           *");printf("\n\t\t***************************************");printf("\n\t\t请选择菜单号(0--9):");scanf("%c",&ch2);getchar();printf("\n");switch(ch2){case '1':printf("\n\t\t请输入按先序建立二叉树的结点序列:");printf("\n\t\t说明:'0'代表后继结点为空,请逐个输入,按回车输入下一结点。");printf("\n\t\t请输入根结点:");T=CreateBT();printf("\n\t\t二叉树成功建立!\n");break;case '2':ShowTree(T);break;case '3':printf("\n\t\t该二叉树的先序遍历序列为:");Preorder(T);break;case '4':printf("\n\t\t该二叉树的中序遍历序列为:");Inorder(T);break;case '5':printf("\n\t\t该二叉树的后序遍历序列为:");Postorder(T);break;case '6':printf("\n\t\t该二叉树的层次遍历序列为:");Levelorder(T);break;case '7':count=0;Leafnum(T);printf("\n\t\t该二叉树有%d个叶子。\n",count);break;case '8':count=0;Nodenum(T);printf("\n\t\t该二叉树总共有%d个结点。\n",count);break;case '9':printf("\n\t\t该树的深度是:%d",TreeDepth(T));break;case '0':ch1='n';break;default:printf("\n\t\t***请注意:输入有误!***");}if(ch2!='0'){ printf("\n\n\t\t按回车键继续,按任意键返回主菜单!\n");a=getchar();if(a!='\xA'){ getchar();ch1='n'; }}}}BT *CreateBT()               // 建立二叉树{   BT *t;char x;scanf("%c",&x);getchar();if(x=='0')t=NULL;else{ t=new BT;t->data=x;printf("\n\t\t请输入%c结点的左子结点:",t->data);t->lchild=CreateBT();printf("\n\t\t请输入%c结点的右子结点:",t->data);t->rchild=CreateBT();}return t;}void Preorder(BT *T)                 // 先序遍历{ if(T){ printf("%3c",T->data);Preorder(T->lchild);Preorder(T->rchild);}}void Inorder(BT *T)             // 中序遍历{ if(T){ Inorder(T->lchild);printf("%3c",T->data);Inorder(T->rchild);}}void Postorder(BT *T)                // 后序遍历{ if(T){ Postorder(T->lchild);Postorder(T->rchild);printf("%3c",T->data);}}void Levelorder(BT *T)                // 层次遍历{int i,j;BT *q[100],*p;p=T;if(p!=NULL){i=1;q[i]=p;j=2;}while(i!=j){p=q[i];printf("%3c",p->data);if(p->lchild!=NULL){q[j]=p->lchild;j++;}if(p->rchild!=NULL){q[j]=p->rchild;j++;}i++;}}void Leafnum(BT *T)               // 求叶结点数{if(T){if(T->lchild==NULL&&T->rchild==NULL)count++;Leafnum(T->lchild);Leafnum(T->rchild);}}void Nodenum(BT *T)       // 求二叉树总结点数{if(T){count++;Nodenum(T->lchild);Nodenum(T->rchild);}}int TreeDepth(BT *T)          // 求树深度{int ldep,rdep;if(T==NULL)return 0;else{ ldep=TreeDepth(T->lchild);rdep=TreeDepth(T->rchild);if(ldep>rdep)return ldep+1;elsereturn rdep+1;}}void ShowTree(BT *T)                  // 凹入法显示二叉树{BT *stack[MAXLEN],*p;int level[MAXLEN][2],top,n,i,width=4;if(T!=NULL){printf("\n\t\t二叉树的凹入表示法:\n\t\t");top=1;stack[top]=T;                  // 根结点入栈level[top][0]=width;while(top>0){p=stack[top];               // 退栈并显示结点的值n=level[top][0];for(i=1;i<=n;i++)          // n为显示宽度,字符以右对齐显示printf(" ");printf("%c",p->data);for(i=n+1;i<50;i+=2)printf("▃");printf("\n\t\t");top- -;if(p->rchild!=NULL){                           // 右子树根结点入栈top++;stack[top]=p->rchild;level[top][0]=n+width;  // 显示宽度增加widthlevel[top][1]=2;        // 左子树根结点入栈}if(p->lchild!=NULL){top++;stack[top]=p->lchild;level[top][0]=n+width;   // 显示宽度增加widthlevel[top][1]=1;}}}}


阅读全文(2822) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.035 second(s), page refreshed 144841248 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号