二叉树遍历的非递归实现 图的两种遍历深度优先搜索和广度优先搜索
数据结构实验报告
班级:
学号:
姓名:
设计日期:
西计算机学院
1.实验题目
1)二叉树遍历的递归实现
2)二叉树遍历的非递归实现
3)哈夫曼树与哈夫曼编码
4)图的两种遍历深度优先搜索和广度优先搜索
2.需求分析
本演示程序用C语言编写,实现二叉树的两种遍历算法,并且构建哈夫曼树及相应的哈夫曼编码,实现图的深度优先遍历和广度优先遍历。
1)递归遍历先判断二叉树是否为空,若为空则遍历结束,注意先序遍历,中序遍历和后序遍历三种遍历的特点。
2)非递归遍历:先序遍历注意要用一维数组实现栈,变量top表示栈顶位置,要判断栈空,栈空则结束;后序遍历结点要入两次栈,出两次栈,故需设置一标志flag。
3)构建哈夫曼树:根据输入的结点数目n和权值Wi,不断将两个小子树合并成一个较大的树。
4)根据哈夫曼树将其左分支写0,右分支写1,依次写下去则可得到从根结点到每个叶结点所经过路径分支组成的0和1的哈夫曼编码。
5)图的遍历:为保证图中各顶点在遍历过程中都被访问且仅访问一次,需为每个顶点设一个访问标志visited,其值为0表示未被访问,1则表示已访问。6)程序所能达到的功能,完成二叉树的递归和非递归遍历,构建出哈夫曼树并输出其哈夫曼编码,完成图的遍历。
3.概要设计
本程序包含
①二叉树的递归遍历包含的函数:
1)主函数main()
2)建立二叉树CreateBiTree()
3)二叉树的的深度函数depth()
4)先序遍历PreOrder( )
5)中序遍历InOrder( )
6)后序遍历PostOrder( )
7)层次遍历LevelOrder( )
②二叉树的非递归遍历包含的函数:
1)主函数main()
2)建立二叉树CreateBiTree()
3)存放数组stack[ ]
4)二叉树的的深度函数depth()
5)先序遍历PreOrder( )
6)中序遍历InOrder( )
7)后序遍历PostOrder( )
8)层次遍历LevelOrder( )
③建立二叉树和哈夫曼编码所包含的函数:1)主函数main()
2)自定义出错函数Error( )
3)构建哈夫曼树HuffmanTree
4)MinCode Selec( )返回为编入的结点中权值最小的两结点的下标④图的深度优先搜索和广度优先搜索所包含的函数:
1)主函数main()
2)
4.详细设计
1)二叉树的递归遍历
#include "stdio.h"
#include
#define MAX 20
#define NULL 0
typedef char TElemType;
typedef int Status;
typedef struct BiTNode{
TElemType data;
struct BiTNode *lchild,*rchild;
} BiTNode,*BiTree;
Status CreatBiTree(BiTree *T)//先序建立二叉树
{ char ch;
ch=getchar();
if(ch=='#')(*T)=NULL;
else
{ (*T)=(BiTree)malloc(sizeof(BiTNode));
(*T)->data =ch;
CreatBiTree(&(*T)->lchild );
CreatBiTree(&(*T)->rchild );
}
return 1;
}
void PreOrde(BiTree T)
{if(T)
{ printf("%2c",T->data);
PreOrde(T->lchild);
PreOrde(T->rchild);
}
}
void InOrde(BiTree T)
{ if(T)
{ InOrde(T->lchild);
printf("%2c",T->data);
InOrde(T->rchild);
}
}
void PostOrde(BiTree T)
{ if(T)
{ PostOrde(T->lchild);
PostOrde(T->rchild);
printf("%2c",T->data);
}
}
void LevelOrde(BiTree T)
{BiTree Queue[MAX],b;
int front,rear;
front=rear=0;
if(T)
{ Queue[rear++]=T;
while(front!=rear)
{ b=Queue[front++];
printf("%2c",b->data);
if(b->lchild!=NULL) Queue[rear++]=b->lchild;
if(b->rchild!=NULL) Queue[rear++]=b->rchild; }
}
}
int depth(BiTree T)
{ int dep1,dep2;
if(T==NULL) return 0;
else
{ dep1=depth(T->lchild );
dep2=depth(T->rchild );
return dep1>dep2?dep1+1:dep2+1;
}
}
changechild(BiTree T)
{BiTree b;
if(T)
{ b=T->lchild ;
T->lchild =T->rchild ;
T->rchild=b;
changechild(T->lchild );
changechild(T->rchild );
}
}
void afterchange(BiTree T)
{ changechild(T);
printf("\nThe preorder is:\n");
PreOrde(T);
printf("\nThe inorder is:\n");
InOrde(T);
printf("\nThe postorder is:\n");
PostOrde(T);
printf("\nThe level order is:\n");
LevelOrde(T);
}
void main()
{
BiTree T=NULL;
printf("\nCreat a Binary Tree\n");
CreatBiTree(&T);
printf("\nThe preorder is:\n");
PreOrde(T);
printf("\nThe inorder is:\n");
InOrde(T);
printf("\nThe postorder is:\n");
PostOrde(T);
printf("\nThe level order is:\n");
LevelOrde(T);
printf("\nThe depth is:%d\n",depth(T));
printf("\nAfter changed lchid and rchild:\n");
afterchange(T);
printf("\n");
}
运算结果:
2)二叉树的非递归遍历
#include "stdio.h"
#include
#define MAXNODE 20
#define NULL 0
typedef char TElemType;
typedef int Status;
typedef struct BiTNode
{
TElemType data;
struct BiTNode *lchild,*rchild;
} BiTNode,*BiTree;
Status CreatBiTree(BiTree *T)//先序建立二叉树{
char ch;
ch=getchar();
if(ch=='#')(*T)=NULL;
else
{
(*T)=(BiTree)malloc(sizeof(BiTNode));
(*T)->data =ch;
CreatBiTree(&(*T)->lchild );
CreatBiTree(&(*T)->rchild );
}
return 1;
}
//以下修改为非递归
typedef struct
{
BiTree link;
int flag;
}stacktype;
void NRPreOrder(BiTree T)
{
BiTree stack[MAXNODE],p;
int top;
if(T==NULL)return;
top=0;
p=T;
while(!(p==NULL&&top==0))
{ while(p!=NULL)
{ printf("%2c",p->data);
if(top { stack[top]=p; top++;} else {printf("栈溢出"); return; } p=p->lchild; } if(top<=0)return; else { top--; p=stack[top]; p=p->rchild; }}} void NRInOrder(BiTree T) { BiTree stack[MAXNODE],p; int top; if(T==NULL)return; top=0; p=T; while(!(p==NULL&&top==0)) { while(p!=NULL) { if(top { stack[top]=p; top++;} else { printf("栈溢出"); return; } p=p->lchild; } if(top<=0)return; else { top--; p=stack[top]; printf("%2c",p->data); p=p->rchild; }}} void NRPostOrder(BiTree T) { stacktype stack[MAXNODE]; BiTree p; int top,sigh; if(T==NULL)return; top=-1; p=T; while(!(p==NULL&&top==-1)) {if(p!=NULL) {top++; stack[top].link=p; stack[top].flag=1; p=p->lchild; } else { p=stack[top].link; sigh=stack[top].flag; top--; if(sigh==1) { top++; stack[top].link=p; stack[top].flag=2; p=p->rchild; } else { printf("%2c",p->data); p=NULL; }}}} void LevelOrder(BiTree T) { BiTree Queue[MAXNODE],b; int front,rear; front=rear=0; if(T) { Queue[rear++]=T; while(front!=rear) { b=Queue[front++]; printf("%2c",b->data); if(b->lchild!=NULL) Queue[rear++]=b->lchild; if(b->rchild!=NULL) Queue[rear++]=b->rchild; }}} int depth(BiTree T) { int dep1,dep2; if(T==NULL) return 0; else { dep1=depth(T->lchild ); dep2=depth(T->rchild ); return dep1>dep2?dep1+1:dep2+1; }} void changechild(BiTree T) {BiTree b; if(T) { b=T->lchild ; T->lchild =T->rchild ; T->rchild=b; changechild(T->lchild ); changechild(T->rchild ); }} afterchange(BiTree T) { changechild(T); printf("\nThe preorder is:\n"); NRPreOrder(T); printf("\nThe level order is:\n"); LevelOrder(T); return 0;} void main() { BiTree T=NULL; printf("\nCreat a Binary Tree\n"); CreatBiTree(&T); printf("\nThe NRpreorder is:\n"); NRPreOrder(T); printf("\nThe NRInorder is:\n"); NRInOrder(T); printf("\nThe NRpostorder is:\n"); NRPostOrder(T); printf("\nThe level order is:\n"); LevelOrder(T); printf("\nThe depth is:%d\n",depth(T)); printf("\nAfter changed lchid and rchild:\n"); afterchange(T); printf("\n"); }运行结果: 3)构建哈夫曼树和哈夫曼编码 #include #include #include #include #include typedef struct { unsigned int weight; unsigned int parent; unsigned int lchild; unsigned int rchild; } HTNode,*HuffmanTree;//哈夫曼节点上需要增加需要编码的字符的存储位置 typedef char **HuffmanCode;//HuffmanCode为二级字符指针结构体 typedef struct { unsigned int s1; unsigned int s2; } MinCode;//该结构体用来返回一棵哈夫曼树中尚未编入的结点中权值最小的两个结点的下标, //其中s1为两个下标中较小的下标,s2为较大的下标。 void Error(char *message);//函数声明 HuffmanCode HuffmanCoding(HuffmanTree HT,HuffmanCode HC,unsigned int *w,unsigned int n); //函数声明 MinCode Select(HuffmanTree HT,unsigned int n); //函数声明 void Error(char *message) //自定义出错函数 { //system("cls"); fprintf(stderr,"Error:%s\n",message); exit(1); } /*构建哈夫曼树,并进行哈弗曼编码*/ HuffmanCode HuffmanCoding(HuffmanTree HT,HuffmanCode HC,unsigned int *w,unsigned int n) { unsigned int i,s1=0,s2=0; HuffmanTree p; char *cd; unsigned int f,c,start,m; MinCode min; if(n<=1) Error("Code too small!"); m=2*n-1; HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); for(p=HT,i=0;i<=n;i++,p++,w++) //叶节点初始化 { p->weight=*w; p->parent=0; p->lchild=0; p->rchild=0; } for(;i<=m;i++,p++) //全部节点初始化 { p->weight=0; p->parent=0; p->lchild=0; p->rchild=0; } for(i=n+1;i<=m;i++) //所有节点加入哈夫曼树,该循环完成哈夫曼树的建立 { min=Select(HT,i-1); //该函数返回当前HT中下标由1到i-1(第一次i=n+1,也就是n个)//中未编入哈夫曼树中的结点中权值最小的两个结点的下标,放在min结构体中 s1=min.s1; s2=min.s2; HT[s1].parent=i; HT[s2].parent=i; HT[i].lchild=s1; HT[i].rchild=s2; //两个节点加入哈夫曼树HT[i].weight=HT[s1].weight+HT[s2].weight; //生成新的父节点权值 } printf("HT List:\n"); printf("Number\t\tweight\t\tparent\t\tlchild\t\trchild\n"); for(i=1;i<=m;i++) //输出哈夫曼树节点信息 printf("%d\t\t%d\t\t%d\t\t%d\t\t%d\n",i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild); /*下面到函数结束进行哈弗曼编码*/ HC=(HuffmanCode)malloc((n+1)*sizeof(char *)); cd=(char *)malloc(n*sizeof(char*)); cd[n-1]='\0'; for(i=1;i<=n;i++) { start=n-1; for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)//由叶节点到根节点逆向编码 if(HT[f].lchild==c)cd[--start]='0'; //节点为左支树编为0,右支树编为1 else cd[--start]='1'; HC[i]=(char*)malloc((n-start)*sizeof(char *)); strcpy(HC[i],&cd[start]); } free(cd); return HC;//返回编码字符串,HC为字符型指针数组,每个元素指向一个编码字符串 } MinCode Select(HuffmanTree HT,unsigned int n) //n为最新加入哈夫曼树的节点的下标,//此函数功能为用来返回一棵哈夫曼树中尚未编入的结点中权值最小的两个结点的下标,{ unsigned int min,secmin; unsigned int temp; unsigned int i,s1,s2,tempi; MinCode code; s1=1;s2=1; for(i=1;i<=n;i++) if(HT[i].parent==0) { min=HT[i].weight; s1=i; break; } tempi=i++; for(;i<=n;i++) if(HT[i].weight { min=HT[i].weight; s1=i; } for(i=tempi;i<=n;i++) if(HT[i].parent==0&&i!=s1) { secmin=HT[i].weight; s2=i; break; } for(i=1;i<=n;i++) if(HT[i].weight { secmin=HT[i].weight; s2=i; } if(s1>s2) { temp=s1; s1=s2; s2=temp; } code.s1=s1; code.s2=s2; return code; } void main() { HuffmanTree HT=NULL; HuffmanCode HC=NULL; unsigned int *w=NULL; unsigned int i,n; //system("cls"); printf("Input n:\n"); scanf("%d",&n); w=(unsigned int*)malloc((n+1)*sizeof(unsigned int *)); w[0]=0; printf("Enter weight:\n"); for(i=1;i<=n;i++) { printf("w[%d]=",i); scanf("%d",&w[i]); } HC=HuffmanCoding(HT,HC,w,n); //生成哈树及哈树编码printf("HuffmanCode:\n"); printf("Number\t\tWeight\t\tCode\n"); for(i=1;i<=n;i++) //输出哈树编码 printf("%d\t\t%d\t\t%s\n",i,w[i],HC[i]); } 运算结果: 4)图的遍历 #include "stdio.h" #include #define INFINITY 0 #define MAXNODE 6 #define TRUE 1 #define FALSE 0 typedef int VertexType; typedef int DataType; #define MAXSIZE 100 typedef struct { DataType data[MAXNODE]; int front; //头指针指示器 int rear; //为指针指示器 }SeqQueue; typedef struct { int adj; }ArcType; typedef struct { VertexType vertexs[MAXNODE]; ArcType arcs[MAXNODE][MAXNODE]; //邻接矩阵int vexnum,arcnum; }GraphType; int visited[MAXNODE]; //求顶点定位函数 int LocateVex(GraphType *G,VertexType u) { int i=-1,k,x; x=G->vexnum; for(k=0;k if(G->vertexs[k]==u) {i=k; break;} return(i); } //建立有向图 int CreateDN(GraphType *G) { int i,j,k,weight,x,y; VertexType v1,v2; //输入图的顶点数和弧数 printf("请输入图的顶点数和弧数:"); scanf("%d,%d",&G->arcnum,&G->vexnum); // printf("%d",G->vexnum); // printf("%d",G->arcnum); x=G->arcnum; y=G->vexnum; for(i=0;i for(j=0;j G->arcs[i][j].adj=INFINITY; for(i=0;i { printf("请输入图的顶点序号:"); scanf("%d",&G->vertexs[i]); //输入图的顶点 } for(k=0;k { printf("请输入弧的两个顶点及权值:"); scanf("%d,%d,%d",&v1,&v2,&weight);//输入弧的两个顶点及权值 i=LocateVex(G,v1); j=LocateVex(G,v2); G->arcs[i][j].adj=weight; //建立弧 } return(1); } //打印出有向图的邻接矩阵 void Print(GraphType *G) { int i,j,x,y; x=G->arcnum; for(i=0;i { for(j=0;j { y=G->arcs[i][j].adj; if(y>10) printf("%d ",y); else printf("%d ",y); } printf("\n");}} //visit函数 void visit(int x) { printf("%d ",x); } //深度优先遍历 void DepthFirstSearch(GraphType *G,int v0) { int vj; visit(v0); visited[v0-1]=1; for(vj=1;vj if(!visited[vj]&&G->arcs[v0-1][vj].adj!=0) DepthFirstSearch(G,vj+1); } //深度优先遍历 void TraveGraph(GraphType *G) { int v; for(v=0;v visited[v]=0; if(!visited[0]) DepthFirstSearch(G,1); } //初始化操作 void InitQueue(SeqQueue *Q) {//将*Q初始化为一个空的循环队列 Q->front=Q->rear=0; } //判断队列是否为空或满 int QueueEmpty(SeqQueue *Q) { if(Q->front==Q->rear) return 1; else return 0; }//入队操作 int EnQueue(SeqQueue *Q,DataType x) {//将元素x入队 if((Q->rear+1)%MAXSIZE==Q->front) //队列已经满了return(FALSE); Q->data[Q->rear]=x; Q->rear=(Q->rear+1)%MAXSIZE; //重新设置队尾指针 return(TRUE); //操作成功 }//出队操作 int DeQueue(SeqQueue *Q) {//删除队列的队头元素,用x返回其值 int x; if(Q->front==Q->rear) //队列为空 return(FALSE); x=Q->data[Q->front]; Q->front=(Q->front+1)%MAXSIZE; //重新设置队头指针return x; //操作成功 } //图的广度优先搜索算法 void BFSM(GraphType *G,int v0) {int i,j; SeqQueue Q; InitQueue(&Q); visit(v0); visited[v0-1]=1; EnQueue(&Q,v0); while(!QueueEmpty(&Q)) {i=DeQueue(&Q); //vi出队 for(j=0;j if(G->arcs[i-1][j].adj!=0) { if(visited[j]==1) continue; visit(j+1); visited[j]=1; EnQueue(&Q,j+1); }}} //广度优先遍历 void TraveGraph2(GraphType *G) { int v; for(v=0;v visited[v]=0; if(!visited[0]) BFSM(G,1); } void main() { GraphType G; printf("创建一个有向网:\n"); int x=CreateDN(&G); printf("该有向图的邻接矩阵为:\n"); Print(&G); printf("深度优先搜索:"); TraveGraph(&G); printf("\n"); printf("广度优先搜索:"); TraveGraph2(&G); printf("\n");} 二叉树的遍历 一、设计思想 二叉树的遍历分为三种方式,分别是先序遍历,中序遍历和后序遍历。先序遍历实现的顺序是:根左右,中序遍历实现的是:左根右,后续遍历实现的是:左右根。根据不同的算法分,又分为递归遍历和非递归遍历。 递归算法: 1.先序遍历:先序遍历就是首先判断根结点是否为空,为空则停止遍历,不为空则将左子作为新的根结点重新进行上述判断,左子遍历结束后,再将右子作为根结点判断,直至结束。到达每一个结点时,打印该结点数据,即得先序遍历结果。 2.中序遍历:中序遍历是首先判断该结点是否为空,为空则结束,不为空则将左子作为根结点再进行判断,打印左子,然后打印二叉树的根结点,最后再将右子作为参数进行判断,打印右子,直至结束。 3.后续遍历:指针到达一个结点时,判断该结点是否为空,为空则停止遍历,不为空则将左子作为新的结点参数进行判断,打印左子。左子判断完成后,将右子作为结点参数传入判断,打印右子。左右子判断完成后打印根结点。 非递归算法: 1.先序遍历:首先建立一个栈,当指针到达根结点时,打印根结点,判断根结点是否有左子和右子。有左子和右子的话就打印左子同时将右子入栈,将左子作为新的根结点进行判断,方法同上。若当前结点没有左子,则直接将右子打印,同时将右子作为新的根结点判断。若当前结点没有右子,则打印左子,同时将左子作为新的根结点判断。若当前结点既没有左子也没有右子,则当前结点为叶子结点,此时将从栈中出栈一个元素,作为当前的根结点,打印结点元素,同时将当前结点同样按上述方法判断,依次进行。直至当前结点的左右子都为 空,且栈为空时,遍历结束。 2.中序遍历:首先建立一个栈,定义一个常量flag(flag为0或者1),用flag记录结点的左子是否去过,没有去过为0,去过为1,默认为0.首先将指针指向根结点,将根结点入栈,然后将指针指向左子,左子作为新的结点,将新结点入栈,然后再将指针指向当前结点的左子,直至左子为空,则指针返回,flag置1,出栈一个元素,作为当前结点,打印该结点,然后判断flag,flag为1则将指针指向当前结点右子,将右子作为新的结点,结点入栈,再次进行上面的判断,直至当前结点右子也为空,则再出栈一个元素作为当前结点,一直到结束,使得当前结点右子为空,且栈空,遍历结束。 3.后续遍历:首先建立两个栈,然后定义两个常量。第一个为status,取值为0,1,2.0代表左右子都没有去过,1代表去过左子,2,代表左右子都去过,默认为0。第二个常量为flag,取值为0或者1,0代表进左栈,1代表进右栈。初始时指针指向根结点,判断根结点是否有左子,有左子则,将根结点入左栈,status置0,flag置0,若没有左子则判断结点有没有右子,有右子就把结点入右栈,status置0,flag置1,若左右子都没有,则打印该结点,并将指针指向空,此时判断flag,若flag为0,则从左栈出栈一个元素作为当前结点,重新判断;若flag为1则从右栈出栈一个元素作为当前结点,重新判断左右子是否去过,若status为1,则判断该结点有没有右子,若有右子,则将该结点入右栈,status置1,flag置1,若没有右子,则打印当前结点,并将指针置空,然后再次判断flag。若当前结点status为2,且栈为空,则遍历结束。若指针指向了左子,则将左子作为当前结点,判断其左右子情况,按上述方法处理,直至遍历结束。 二、算法流程图 合肥学院 计算机科学与技术系 课程设计报告 2013~2014学年第二学期 课程数据结构与算法 课程设计名称图的深度优先遍历算法的实现 学生姓名陈琳 学号1204091022 专业班级软件工程 指导教师何立新 2014 年9 月 一:问题分析和任务定义 涉及到数据结构遍会涉及到对应存储方法的遍历问题。本次程序采用邻接表的存储方法,并且以深度优先实现遍历的过程得到其遍历序列。 深度优先遍历图的方法是,从图中某顶点v 出发: (1)访问顶点v ; (2)依次从v 的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v 有路径相通的顶点都被访问; (3)若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。 二:数据结构的选择和概要设计 设计流程如图: 图1 设计流程 利用一维数组创建邻接表,同时还需要一个一维数组来存储顶点信息。之后利用创建的邻接表来创建图,最后用深度优先的方法来实现遍历。 图 2 原始图 1.从0开始,首先找到0的关联顶点3 2.由3出发,找到1;由1出发,没有关联的顶点。 3.回到3,从3出发,找到2;由2出发,没有关联的顶点。 4.回到4,出4出发,找到1,因为1已经被访问过了,所以不访问。 所以最后顺序是0,3,1,2,4 三:详细设计和编码 1.创建邻接表和图 void CreateALGraph (ALGraph* G) //建立邻接表函数. { int i,j,k,s; char y; EdgeNode* p; //工作指针. printf("请输入图的顶点数n与边数e(以逗号做分隔符):\n"); scanf("%d,%d",&(G->n),&(G->e)); scanf("%c",&y); //用y来接收回车符. for(s=0;s #include 数据结构(双语) ——项目文档报告用两种方式实现表达式自动计算 专业: 班级: 指导教师: 姓名: 学号: 目录 一、设计思想 (01) 二、算法流程图 (02) 三、源代码 (04) 四、运行结果 (11) 五、遇到的问题及解决 (11) 六、心得体会 (12) 一、设计思想 二叉树的遍历分为三种方式,分别是先序遍历,中序遍历和后序遍历。先序遍历实现的顺序是:根左右,中序遍历实现的是:左根右,后续遍历实现的是:左右根。根据不同的算法分,又分为递归遍历和非递归遍历。 递归算法: 1.先序遍历:先序遍历就是首先判断根结点是否为空,为空则停止遍历,不为空则将左子作为新的根结点重新进行上述判断,左子遍历结束后,再将右子作为根结点判断,直至结束。到达每一个结点时,打印该结点数据,即得先序遍历结果。 2.中序遍历:中序遍历是首先判断该结点是否为空,为空则结束,不为空则将左子作为根结点再进行判断,打印左子,然后打印二叉树的根结点,最后再将右子作为参数进行判断,打印右子,直至结束。 3.后续遍历:指针到达一个结点时,判断该结点是否为空,为空则停止遍历,不为空则将左子作为新的结点参数进行判断,打印左子。左子判断完成后,将右子作为结点参数传入判断,打印右子。左右子判断完成后打印根结点。 非递归算法: 1.先序遍历:首先建立一个栈,当指针到达根结点时,打印根结点,判断根结点是否有左子和右子。有左子和右子的话就打印左子同时将右子入栈,将左子作为新的根结点进行判断,方法同上。若当前结点没有左子,则直接将右子打印,同时将右子作为新的根结点判断。若当前结点没有右子,则打印左子,同时将左子作为新的根结点判断。若当前结点既没有左子也没有右子,则当前结点为叶子结点,此时将从栈中出栈一个元素,作为当前的根结点,打印结点元素,同时将当前结点同样按上述方法判断,依次进行。直至当前结点的左右子都为空,且栈为空时,遍历结束。 2.中序遍历:首先建立一个栈,定义一个常量flag(flag为0或者1),用flag记录结点的左子是否去过,没有去过为0,去过为1,默认为0.首先将指针指向根结点,将根结点入栈,然后将指针指向左子,左子作为新的结点,将新结点入栈,然后再将指针指向当前结点的左子,直至左子为空,则指针返回,flag置1,出栈一个元素,作为当前结点,打印该结点,然后判断flag,flag为1则将指针指向当前结点右子,将右子作为新的结点,结点入栈,再次进行上面的判断,直至当前结点右子也为空,则再出栈一个元素作为当前结点,一直到结束,使得当前结点右子为空,且栈空,遍历结束。 3.后续遍历:首先建立两个栈,然后定义两个常量。第一个为status,取值为0,1,2.0代表左右子都没有去过,1代表去过左子,2,代表左右子都去过,默认为0。第二个常量为flag,取值为0或者1,0代表进左栈,1代表进右栈。初始时指针指向根结点,判断根结点是否有左子,有左子则,将根结点入左栈,status置0,flag置0,若没有左子则判断结点有没有右子,有右子就把结点入右栈,status置0,flag置1,若左右子都没有,则打印该结点,并将指针指向空,此时判断flag,若flag为0,则从左栈出栈一个元素作为当前结点,重新判断;若flag为1则从右栈出栈一个元素作为当前结点,重新判断左右子是否去过,若status 为1,则判断该结点有没有右子,若有右子,则将该结点入右栈,status置1,flag置1,若没有右子,则打印当前结点,并将指针置空,然后再次判断flag。若当前结点status为2,且栈为空,则遍历结束。若指针指向了左子,则将左子作为当前结点,判断其左右子情况,按上述方法处理,直至遍历结束。 上机实验报告 学院:计算机与信息技术学院 专业:计算机科学与技术(师范)课程名称:数据结构 实验题目:深度优先遍历(邻接矩阵)班级序号:师范1班 学号:201421012731 学生姓名:邓雪 指导教师:杨红颖 完成时间:2015年12月25号 一、实验目的: 1﹒掌握图的基本概念和邻接矩阵存储结构。 2﹒掌握图的邻接矩阵存储结构的算法实现。 3﹒掌握图在邻接矩阵存储结构上遍历算法的实现。 二、实验环境: Windows 8.1 Microsoft Visual c++ 6.0 二、实验内容及要求: 编写图的深度优先遍历邻接矩阵算法。建立图的存储结构,能够输入图的顶点和边的信息,并存储到相应存储结构中,而后输出图的邻接矩阵。 四、概要设计: 深度优先搜索遍历类似于树的先根遍历,是树的先根遍历的推广。假设初始状态是图中所有的顶点未曾被访问,则深度优先遍历可从图的某个顶点V出发,访问此顶点,然后依次从V的未被访问的邻接点出发深度优先遍历图,直至图中所有和V有路径相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中的一个未被访问的顶点,重复上述过程,直至图中所有顶点都被访问到为止。 以图中无向图G4为例,深度优先遍历图的过程如图所示。假设从顶点V1出发进行搜索,在访问了顶点V1后,选择邻接点V2。因为V2未曾访问,则从V2出发进行搜索。依次类推,接着从V4,V8,V5出发进行搜索。在访问了V5之后,由于V5的邻接点已都被访问,则搜索回到V8。由于同样的理由,搜索继续回到V4,V2直至V1,此时由于V1的另一个邻接点为被访问,则搜索又从V1到V3,再继续进行下去。由此得到顶点的访问序列为: V1 V2 V4 V8 V5 V3 V6 V7 五、代码 #include #include <> #include <> #include <> #define MAX_TREE_SIZE 100 typedef struct { int data; int parent; ata,[i].parent); printf("\n"); } } /*用双亲表示法创建树*/ PTree CreatTree(PTree T) { int i=1; int fa,ch; PTNode p; for(i=1;ch!=-1;i++) { printf("输入第%d结点:\n",i); scanf("%d,%d",&fa,&ch); printf("\n"); =ch; =fa; ++; [].data = ; [].parent = ; } printf("\n"); printf("创建的树具体情况如下:\n"); print_ptree(T); return T; } /*一般树转换成二叉树*/ BTNode *change(PTree T) { int i,j=0; BTNode p[MAX_TREE_SIZE]; BTNode *ip,*is,*ir,*Tree; ip=(BTNode *)malloc(sizeof(BTNode)); is=(BTNode *)malloc(sizeof(BTNode)); ir=(BTNode *)malloc(sizeof(BTNode)); Tree=(BTNode *)malloc(sizeof(BTNode)); for(i=0;i<;i++) { p[i]=GetTreeNode[i].data); } for(i=1;i<;i++) { ip=&p[i]; is=&p[j]; while[i].parent!=is->data) { j++; is=&p[j]; } if(!(is->firstchild)) { is->firstchild=ip; ir=ip; } else { ir->rightsib=ip; ir=ip; } } Tree=&p[0]; return Tree; } /*主菜单*/ void Menu() { printf("=================主菜单=======================\n"); printf("***输入-以双亲法创建一棵一般树***\n"); printf("***输入2-------------树的前序遍历(递归)*******\n"); printf("***输入3-------------树的后序遍历(递归)*******\n"); printf("***输入4-------------树的前序遍历(非递归)*****\n"); printf("***输入5-------------树的后序遍历(非递归)*****\n"); printf("***输入6-------------层次序的非递归遍历*******\n"); printf("***输入0-------------退出程序*****************\n"); printf("==============================================\n"); 一.实验目的 熟悉图的存储结构,掌握用单链表存储数据元素信息和数据元素之间的关系的信息的方法,并能运用图的深度优先搜索遍历一个图,对其输出。 二.实验原理 深度优先搜索遍历是树的先根遍历的推广。假设初始状态时图中所有顶点未曾访问,则深度优先搜索可从图中某个顶点v出发,访问此顶点,然后依次从v的未被访问的邻接点出发深度优先遍历图,直至图中所有与v有路径相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未曾访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。 图的邻接表的存储表示: #define MAX_VERTEX_NUM 20 #define MAXNAME 10 typedef char VertexType[MAXNAME]; typedef struct ArcNode{ int adjvex; struct ArcNode *nextarc; }ArcNode; typedef struct VNode{ VertexType data; ArcNode *firstarc; }VNode,AdjList[MAX_VERTEX_NUM]; typedef struct{ AdjList vertices; int vexnum,arcnum; int kind; }ALGraph; 三.实验内容 编写LocateVex函数,Create函数,print函数,main函数,输入要构造的图的相关信息,得到其邻接表并输出显示。 四。实验步骤 1)结构体定义,预定义,全局变量定义。 #include"stdio.h" #include"stdlib.h" #include"string.h" #define FALSE 0 #define TRUE 1 #define MAX 20 typedef int Boolean; #define MAX_VERTEX_NUM 20 数据结构(双语) ——项目文档报告 用递归、非递归两种方法遍历二叉树 专业:计算机科学与技术 班级: 指导教师: 姓名: 学号: 目录 一、设计思想 (03) 二、算法流程图 (04) 三、源代码 (06) 四、运行结果 (12) 五、遇到的问题及解决 (14) 六、心得体会 (15) 一、设计思想 1.递归: (1)主函数main()主程序要包括:定义的二叉树T、建树函数、先序遍历函数、中序遍历函数、后序遍历函数。 (2)建树函数定义一个输入的数是字符型的,当ch为空时,T就为空值,否则的话就分配空间给T,T就指向它的结点,然后左指针域指向左孩子,右指针指向右孩子,若还有,继续调用,依次循环下去,直到ch遇到空时,结束。最后要返回建立的二叉树T。 (3)先序遍历函数根据先序遍历规则,当T为非空时,先输出结点处的数据,指针指向左、右孩子,依次进行下去。 (4) 中序遍历函数根据中序遍历规则,当T为非空时,先左指针指向左孩子数据,然后输出结点处的数据,再右指针指向右孩子,依次进行下去。 (5)后序遍历函数根据后序遍历规则,当T为非空时,先右指针指向右孩子,然后左指针指向左孩子,最后输出结点处的数据,依次进行下去。 2.非递归: (1)跟递归遍历二叉树的前提一样,首先应该创建一个二叉树,同样使用先序递归的方式创建二叉树。 (2)然后是中序,先序,后序非递归遍历二叉树。 (3)中序非递归遍历二叉树的思想是:首先是根节点压栈,当根节点的左子树不是空的时候,左子树压栈。直到左子树为空的时候,不再压栈。将栈顶元素出栈,访问栈顶元素,并将栈顶的右子树进栈。当右子树的左子树不是空的时候,左子树一直进栈,直到左子树为空,则不再进栈。重复上面的操作,直到栈空的时候。 (4)先序非递归遍历二叉树的思想是:首先是根节点进栈,然后当栈不为空的时候,将栈顶元素出栈,然后访问。同时将出栈元素的右子树进栈,左子树进栈。重复上面的操作,直到栈为空。 (5)后序非递归遍历二叉树的思想:首先是根节点进栈,当根节点的左子树不为空的时候,左子树进栈,直到左为空的时候,左子树不再进栈。指针指向的是右子树,当右子树为空的时候,直接访问根节点。当右子树不为空的时候,则右子树的指针进栈,当右子树的左子树不为空的时候,则左也进栈,直到左为空。重复上面的操作,直到栈为空的时候,则遍历树完成。 #include "stdio.h" #include "stdlib.h" #define STACK_INIT_SIZE 100 //栈存储空间初始分配量 #define STACKINCREMENT 10 //存储空间分配增量 //------二叉树的存储结构表示------// typedef struct BiTNode{ int data; struct BiTNode *lchild,*rchild; }BiTNode,*BiTree; //-----顺序栈的存储结构表示------// typedef struct{ BiTree *top; BiTree *base; int stacksize; }SqStack; //*************************************************** //构造一个空栈s SqStack *InitStack(); //创建一颗二叉树 BiTree CreatBiTree(); //判断栈空 int StackEmpty(SqStack *S); //插入元素e为新的栈顶元素 void Push(SqStack *S,BiTree p); //若栈不为空,则删除s栈顶的元素e,将e插入到链表L中void Pop(SqStack *S,BiTree *q); //非递归先序遍历二叉树 void PreOrderTraverse(BiTree L); //非递归中序遍历二叉树 void InOrderTraverse(BiTree L); //非递归后序遍历二叉树 void PostOrderTraverse(BiTree L); //递归后序遍历二叉树 void PostOrder(BiTree bt); //递归中序遍历二叉树 void InOrder(BiTree bt); //递归先序遍历二叉树 void PreOrder(BiTree bt); //*************************************************** 用递归、非递归两种方法遍历二叉树 一、设计思想 1. 用递归算法遍历 设计思想:主要是通过不同程序顺序,从而实现递归的顺序遍历 前序遍历:先判断节点是否为空,如果不为空,则输出。再判断左节点是否为空,如果不为空,则递归调用,直到遍历到最左边。接着再遍历最左边的右子树,如果此时右子树不为空,则递归遍历左子树的操作,直到遍历到叶子节点。如果右子树为空,则回溯上次的递归调用,重复输出和遍历右子树的操作。 中序遍历:先遍历左节点是否为空,如果不为空,则递归调用,直到遍历到最左边或者叶子节点,然后输出,接着再遍历最左边的右子树,如果此时右子树不为空,则递归重复遍历左子树的操作,直到遍历到叶子节点。如果右子树为空,则回溯到上次递归调用,重复输出和遍历右子树的操作。 后序遍历:先判断左节点是否为空,如果不为空则一直递归直到遍历到最左边,然后遍历右节点,再接着遍历到左子树的最右边,直到遍历到叶子节点。此时输出,回溯到上次递归,继续执行后面的操作,重复,直到将整个树遍历完毕。 2. 用非递归算法遍历 设计思想:主要是通过栈的存取,判空,从而实现树的遍历 前序遍历:通过一个循环实现。先输出节点的数值,因为栈的特性,则需要先判断右子树是否为空,如果不为空,则将右子树压栈。然后判断左子树是否为空,如果不为空,则将左子树压栈。接着再将栈里面的子树弹出赋给给当前节点变量,重复上述操作,直到栈为空后退出循环。 中序遍历:通过循环实现。将树一直遍历到最左端,并将中间所经过的节点保存在栈中,当遍历到最左边的时候,则弹出栈里面的子树。输出数值,将当前节点赋值为当前节点的右子树,遍历右子树,即重复上述操作,直到当前节点为空,并且栈内元素为0。 后序遍历:通过循环和标记栈实现。将数一直遍历到最左端,并将中间的节点保存在树栈中,同时同步的添加一个标记栈。当遍历到最左边的时候,弹栈并赋值给当前栈,然后判断标记栈的数值,如果数值为0的话则代表当前树没有遍历过,遍历右子树。然后重复上面的操作,如果数值为1的话则代表此时数已经遍历过了,可以开始输出了,为了避免重复输出,将当前栈赋为空。重复循环操作,直到栈内没有元素,且当前节点为空(因为一直左的操作并没有将右子树压栈)。 #include ○A ○C ○D ○B ○E○F G 《数据结构与算法》实验报告三 ——二叉树的操作与应用 一.实验目的 熟悉二叉链表存储结构的特征,掌握二叉树遍历操作及其应用 二. 实验要求(题目) 说明:以下题目中(一)为全体必做,(二)(三)任选其一完成 (一)从键盘输入二叉树的扩展先序遍历序列,建立二叉树的二叉链表存储结构;(二)分别用递归和非递归算法实现二叉树的三种遍历; (三)模拟WindowsXP资源管理器中的目录管理方式,模拟实际创建目录结构,并以二叉链表形式存储,按照凹入表形式打印目录结构(以扩展先序遍历序列输入建立二叉链表结构),如下图所示: (基本要求:限定目录名为单字符;扩展:允许目录名是多字符组合) 三. 分工说明 一起编写、探讨流程图,根据流程图分工编写算法,共同讨论修改,最后上机调试修改。 四. 概要设计 实现算法,需要链表的抽象数据类型: ADT Binarytree { 数据对象:D是具有相同特性的数据元素的集合 数据关系R: 若D为空集,则R为空集,称binarytree为空二叉树; 若D不为空集,则R为{H},H是如下二元关系; (1)在D中存在唯一的称为根的数据元素root,它在关系H下无前驱; (2)若D-{root}不为空,则存在D-{root}={D1,Dr},且D1∩Dr为空集; (3)若D1不为空,则D1中存在唯一的元素x1, 华北水利水电学院数据结构实验报告 20 10 ~20 11 学年第一学期2008级计算机专业 班级:107学号:200810702姓名:王文波 实验四图的应用 一、实验目的: 1.掌握图的存储结构及其构造方法 2.掌握图的两种遍历算法及其执行过程 二、实验内容: 以邻接矩阵或邻接表为存储结构,以用户指定的顶点为起始点,实现无向连通图的深度优先及广度优先搜索遍历,并输出遍历的结点序列。 提示:首先,根据用户输入的顶点总数和边数,构造无向图,然后以用户输入的顶点为起始点,进行深度优先和广度优先遍历,并输出遍历的结果。 三、实验要求: 1.各班学号为单号的同学采用邻接矩阵实现,学号为双号的同学采用邻接表实现。 2.C/ C++完成算法设计和程序设计并上机调试通过。 3.撰写实验报告,提供实验结果和数据。 4.写出算法设计小结和心得。 四、程序源代码: #include { int nData; QueueNode* next; }; struct QueueList { QueueNode* front; QueueNode* rear; }; void EnQueue(QueueList* Q,int e) { QueueNode *q=new QueueNode; q->nData=e; q->next=NULL; if(Q==NULL) return; if(Q->rear==NULL) Q->front=Q->rear=q; else { Q->rear->next=q; Q->rear=Q->rear->next; } } void DeQueue(QueueList* Q,int* e) { if (Q==NULL) return; if (Q->front==Q->rear) { *e=Q->front->nData; Q->front=Q->rear=NULL; } else { *e=Q->front->nData; Q->front=Q->front->next; } } //创建图 void CreatAdjList(Graph* G) { int i,j,k; edgenode* p1; edgenode* p2; *问题描述: 建立图的存储结构(图的类型可以是有向图、无向图、有向网、无向网,学生可以任选两种类型),能够输入图的顶点和边的信息,并存储到相应存储结构中,而后输出图的邻接矩阵。 1、邻接矩阵表示法: 设G=(V,E)是一个图,其中V={V1,V2,V3…,Vn}。G的邻接矩阵是一个他有下述性质的n阶方阵: 1,若(Vi,Vj)∈E 或 若图中每个顶点只含一个编号i(1≤i≤vnum),则只需一个二维数组表示图的邻接矩阵。此时存储结构可简单说明如下: type adjmatrix=array[1..vnum,1..vnum]of adj; 利用邻接矩阵很容易判定任意两个顶点之间是否有边(或弧)相联,并容易求得各个顶点的度。 对于无向图,顶点Vi的度是邻接矩阵中第i行元素之和,即 n n D(Vi)=∑A[i,j](或∑A[i,j]) j=1 i=1 对于有向图,顶点Vi的出度OD(Vi)为邻接矩阵第i行元素之和,顶点Vi 的入度ID(Vi)为第i列元素之和。即 n n OD(Vi)=∑A[i,j],OD(Vi)=∑A[j,i]) j=1j=1 用邻接矩阵也可以表示带权图,只要令 Wij, 若 import java.util.Stack; public class MyTree{ public static void main(String[] s){ new MyTree(); } public MyTree(){ TreeNode root = init();//初始化二叉树并返回根节点 System.out.println("递归先序遍历"); preorder(root); System.out.println(); System.out.println("递归中序遍历"); inorder(root); System.out.println(); System.out.println("递归后续遍历"); posorder(root); System.out.println(); System.out.println("非递归先序遍历"); preorder(root); System.out.println(); System.out.println("非递归中序遍历"); _inorder(root); System.out.println(); System.out.println("非递归后续遍历"); _posorder(root); System.out.println(); } public void preorder(TreeNode root){//递归二叉树的前序遍历 if(root != null){ System.out.print(root.getValue());//访问节点值 preorder(root.getLeft()); preorder(root.getRight()); } } public void _preorder(TreeNode p){ Stack 2007-05-27 晴 //采用非递归深度优先遍历算法,可以将回溯法表示为一个非递归过程 #include }; private: int Bound(int i); void Backtrack(int i); int c; //背包容量 int n; //物品数 int *w; //物品重量数组int *p; //物品价值数组int cw; //当前重量 int cp; //当前价值 int bestp; //当前最优值int *bestx; //当前最优解int *x; //当前解 }; int Knap::Bound(int i) //装满背包 if(i<=n) b+=p/w*cleft; return b; } void Knap::Backtrack(int i) { if(i>n) { if(bestp 第六章树二叉树 后序遍历的非递归算法。在对二叉树进行后序遍历的过程中,当指针p 指向某一个结点时,不能马上对它进行访问,而要先遍历它的左子树,因而要将此结点的地址进栈保存。当其左子树遍历完毕之后,再次搜索到该结点时(该结点的地址通过退栈得到) ,还不能对它进行访问,还需要遍历它的右子树,所以,再一次将此结点的地址进栈保存。为了区别同一结点的两次进栈,引入一个标志变量nae,有0 表示该结点暂不访问 1 表示该结点可以访问标志flag 的值随同进栈结点的地址一起进栈和出栈。因此,算法中设置两个空间足够的堆栈,其中, STACKlCM] 存放进栈结点的地址, STACK2[M] 存放相应的标志n 昭的值, 两个堆栈使用同一栈顶指针top , top 的初值为— 1 。 具体算法如下: #defineH 100 /?定义二叉树中结点最大数目。/ voidPOSTOiRDER(BTREET) { / *T 为二叉树根结点所在链结点的地址。/ BTREESTACKl[H] , p=T ;intSTACK2[M] , flag,top= —1;if(T!=NULL) d0{ while(p!=NULL){ STACK/[++top]=p ; /?当前p所指结点的地址进栈?/ STACK2[top]= 0 ; /,标志0 进栈?/ p=p->lchild ;/?将p 移到其左孩子结点x/ } p=STACKl[top) ;flag=STACK2[top--] ;if(flag==0){ STACKl[++top]=p ; /,当前p所指结点的地址进栈。/ STACK2[toP]=1 ; /?标志1 进栈?/ p=p->rchild ; /x将p移到其右孩子结点o/ } else{ VISIT(p) ; /x访问当前p所指的结点x/ p=NULL ; } }while(p!=NULLtttop!=-1) ; } 不难分析,上述算法的时间复杂度同样为O(n) 7.6.3 二叉树的线索化算法 对--X 树的线索化,就是把二叉树的二叉链表存储结构中结点的所有空指针域改造成指向某结点在某种遍历序列中的直接前驱或直接后继的过程, 因此, 二叉树的线索化过程只能 在对二叉树的遍历过程中进行。 下面给出二叉树的中序线索化的递归算法。算法中设有指针pre,用来指向中序遍历过 程中当前访问的结点的直接前驱结点,pre的初值为头结点的指针;T初始时指向头结点, 但在算法执行过程中,T总是指向当前访问的结点。voldlNTHREAD(TBTREET) { TBTREE pre ; if(T!=Null){ INTHREAD(T —>lchild); if(T —>rchild==NULL)树的遍历(递归和非递归)
图的深度优先遍历算法课程设计报告
连通图深度优先遍历
二叉树遍历C语言(递归,非递归)六种算法
深度优先遍历(邻接矩阵)
树转换成二叉树-树的前序、后序的递归、非递归和层次序的非递归
图的深度优先遍历实验报告
用递归非递归两种方法遍历二叉树
二叉树的建立及几种简单的遍历方法
递归非递归两种算法遍历二叉树讲解
邻接矩阵的深度优先遍历
用递归和非递归算法实现二叉树的三种遍历
图的深度优先遍历和广度优先遍历
邻接矩阵表示图深度广度优先遍历
java二叉树的遍历(递归非递归)
采用非递归深度优先遍历算法
后序遍历的非递归算法.doc