数据结构上机实验(6个)
关于文件的输入输出,只要在主函数中添加:
freopen("E:\\read9.txt","r",stdin);
freopen("E:\\write9.txt","w",stdout);
即可。
其余地方的输入输出不变,但是必须用scanf和printf进行输入输出。
实验一 迷宫问题(bfs)
#include"iostream" #include"stdio.h" #include"algorithm" #include"queue" #include"string.h" #include"cmath" #include"stack" #include"fstream" #define mx 105 #define inf 1000 using namespace std; int n,m; int sx,sy,ex,ey; int maze[mx][mx],vis[mx][mx]; int dir[8][2]= {{0,1},{0,-1},{1,0},{-1,0},{-1,-1},{-1,1},{1,-1},{1,1}}; bool judge(int x,int y) { if(maze[x][y]==0&&x>=0&&x<n&&y>=0&&y<m) { return true; } return false; } void output(int step) { int i; stack<int>path; path.push(ex*m+ey); printf("%s%d\n","最少步骤是:",step); int x=ex,y=ey,dx,dy; while(vis[x][y]!=0) { for(i=0;i<8;i++) { dx=x+dir[i][0]; dy=y+dir[i][1]; if(dx>=0&&dx<n&&dy>=0&&dy<m) if(vis[dx][dy]==vis[x][y]-1) { path.push(dx*m+dy); break; } } x=dx;y=dy; } printf("%s","最短路径为:"); while(!path.empty()) { int u=path.top(); path.pop(); x=u/m;y=u%m; if(x!=ex||y!=ey) printf("%s%d%s%d%s%s","(",x,",",y,")","->"); else printf("%s%d%s%d%s\n\n","(",x,",",y,")"); } } void bfs(int step) { queue<int>q; int i,x,y,dx,dy,u; x=sx;y=sy; u=x*m+y; q.push(u); while(!q.empty()) { u=q.front(); q.pop(); x=u/m;y=u%m; if(x==ex&&y==ey) { output(step); return; } int flag=1; step=vis[x][y]; for(i=0;i<8;i++) { dx=x+dir[i][0]; dy=y+dir[i][1]; if(judge(dx,dy)) { if(flag){step++;flag=0;} maze[dx][dy]=1; if(step<vis[dx][dy]) vis[dx][dy]=step; u=dx*m+dy; q.push(u); } } } printf("%s","没有满足条件的通路!\n"); } int main() { int i,j; freopen("C://read.txt","r",stdin); freopen("C://write.txt","w",stdout); while(scanf("%d%d",&n,&m),n||m) { for(i=0;i<n;i++) { for(j=0;j<m;j++) {scanf("%d",&maze[i][j]);vis[i][j]=inf;} } scanf("%d%d%d%d",&sx,&sy,&ex,&ey); maze[sx][sy]=1; vis[sx][sy]=0; bfs(0); } return 0; }
实验二 锦标赛问题(简单的分治思想)
#include"iostream" #include"stdio.h" #include"cmath" #include"string.h" #include"algorithm" #include"queue" using namespace std; const int mx=1005; int calendar[mx][mx];//日程表 FILE* rfile=fopen("E:\\read2.txt","r"); FILE* wfile=fopen("E:\\write2.txt","w");//文件读写 void championship(int k) { int i,j,t; calendar[1][1]=1;//只有两个人比赛的情况 calendar[1][2]=2; calendar[2][1]=2; calendar[2][2]=1; int temp=1; for(t=1;t<k;t++) { temp*=2; for(i=1;i<=temp;i++) { for(j=1;j<=temp;j++) { calendar[i+temp][j+temp]=calendar[i][j]; } } for(i=1;i<=temp;i++)//用分治的方式打表 { for(j=1;j<=temp;j++) { calendar[i+temp][j]=calendar[i][j]+temp; } } for(i=temp+1;i<=temp*2;i++) { for(j=1;j<=temp;j++) { calendar[i-temp][j+temp]=calendar[i][j]; } } } int n=pow(2,k); for(i=1;i<=n;i++)//日程表的输出 { for(j=1;j<=n;j++) fprintf(wfile,"%d ",calendar[i][j]); fprintf(wfile,"%s\n",""); } fprintf(wfile,"%s\n","");//文件输出 } int main() { int k,icase=0; while((fscanf(rfile,"%d",&k),k!=-1)) { fprintf(wfile,"%s%d%s\n","Case ",++icase," :"); fprintf(wfile,"%s%d\n","input k :",k); championship(k); } fclose(wfile); fclose(rfile); return 0; }
实验三 kruskal算法(最小生成树)
#include"iostream" #include"stdio.h" #include"algorithm" #include"cmath" #include"string.h" #include"string" using namespace std; const int mx=105; const int inf=32767; FILE* rfile=fopen("E:\\read3.txt","r"); FILE* wfile=fopen("E:\\write3.txt","w");//文件读写 struct Edge//记录边的两个端点和权值 { int u; int v; int w; }; struct Mgraph { int edges[mx][mx];//存储边 int n;//顶点数 }; struct UFStree//并查集的数据结构 { int data;//节点对应的编号 int parent;//节点对应双亲下标 int rank;//节点对应秩 }; bool cmp(const Edge a,const Edge b) { return a.w<b.w; } void Make_set(UFStree t[],int n)//初始化 { for(int i=0;i<n;i++) { t[i].rank=0; t[i].parent=i; } } int Find_set(UFStree t[],int x)//查找集合的代表元素 { while(x!=t[x].parent) x=t[x].parent; return x; } void Union(UFStree t[],int x,int y)//将两个集合并为一个 { x=Find_set(t,x); y=Find_set(t,y); if(t[x].rank>t[y].rank)//将秩小的作为秩大的子集 t[y].parent=x; else { t[x].parent=y; if(t[x].rank==t[y].rank) t[y].rank++; } } void Kruskal(Mgraph g)//求最小生成树的算法 { int i,j,k,u1,v1,sn1,sn2; UFStree t[mx]; Edge E[mx]; k=1; //E数组的下标从1开始 for(i=0;i<g.n;i++) //由g产生的边集E for(j=0;j<g.n;j++) { if(g.edges[i][j]!=0&&g.edges[i][j]!=inf)//取出图的邻接矩阵中所有的边 { E[k].u=i;E[k].v=j;E[k++].w=g.edges[i][j]; } } sort(E,E+k,cmp);//按边的权值从小到大排序 Make_set(t,g.n); k=1;//k表示当前构造生成树的第几条边,初值为1 j=1;//E中边的下标,初值为1 while(k<g.n) { u1=E[j].u; v1=E[j].v; sn1=Find_set(t,u1); sn2=Find_set(t,v1); if(sn1!=sn2)//两定顶点属于不同的集合,该边是最小生成树的一条边 { fprintf(wfile,"%s%d%s%d%s%d\n","(",u1,",",v1,"):",E[j].w); k++;//生成边数增1 Union(t,u1,v1);//将 u1和v1两个顶点合并 } j++; } } int main() { Mgraph g; int i,j,n; fprintf(wfile,"%s\n\n","输入顶点数为0时结束!"); while(fscanf(rfile,"%d",&n),n) { fprintf(wfile,"%s%d\n","输入图的顶点数目:",n); g.n=n; fprintf(wfile,"%s\n","输入每个顶点与n个顶点边的权值:"); for(i=0;i<n;i++) { for(j=0;j<n;j++) {fscanf(rfile,"%d",&g.edges[i][j]);//取地址符很关键 fprintf(wfile,"%d ",g.edges[i][j]); } fprintf(wfile,"%s\n",""); } fprintf(wfile,"%s\n","输出构成最小生成树的边和顶点集:"); Kruskal(g); fprintf(wfile,"%s\n",""); } fclose(wfile);//关闭文件 fclose(rfile); return 0; }
实验四 哈夫曼编码
#include"iostream" #include"stdio.h" #include"algorithm" #include"string" #include"string.h" #include"cmath" #include"fstream" using namespace std; const int mx=105; const int inf=32767;//表示无穷 FILE* rfile=fopen("E:\\read4.txt","r"); FILE* wfile=fopen("E:\\write4.txt","w"); struct htnode { char data;//节点值 double weight;//权重 int parent;//双亲节点 int lchild;//左孩子节点 int rchild;//右孩子节点 }; struct hcode { char cd[mx];//存放当前结点的哈夫曼码 int start;//cd[start]~cd[n]存放哈夫曼码 }; void CreatHuffman(htnode ht[],int n) { int i,j,k,lnode,rnode; double min1,min2; for(i=0;i<2*n-1;i++)//所有节点的相关域置初值-1 { ht[i].parent=ht[i].lchild=ht[i].rchild=-1; } for(i=n;i<2*n-1;i++)//构造哈弗曼树 { min1=min2=inf; lnode=rnode=-1;//lnode和rnode为最小权重的两个结点位置 for(k=0;k<=i-1;k++)//在ht[]中找权值最小的两个结点 { if(ht[k].parent==-1)//只在尚未构造二叉树的结点中查找 { if(ht[k].weight<min1) { min2=min1;rnode=lnode; min1=ht[k].weight;lnode=k; } else if(ht[k].weight<min2) { min2=ht[k].weight;rnode=k; } } } ht[i].weight=ht[lnode].weight+ht[rnode].weight; ht[i].lchild=lnode;ht[i].rchild=rnode;//ht[i]作为双亲结点 ht[lnode].parent=i;ht[rnode].parent=i; } } void CreatHuffmanCode(htnode ht[],hcode hcd[],int n) { int i,f,c; hcode hc; for(i=0;i<n;i++)//根据哈夫曼树求哈夫曼编码 { hc.start=n;c=i; f=ht[i].parent; while(f!=-1) { if(ht[f].lchild==c) hc.cd[hc.start--]='0'; else hc.cd[hc.start--]='1'; c=f;f=ht[f].parent; } hc.start++;hcd[i]=hc; } } void display(htnode ht[],hcode hcd[],int n) { for(int i=0;i<n;i++) { fprintf(wfile,"%c%s",ht[i].data,": "); for(int j=hcd[i].start;j<=n;j++) fprintf(wfile,"%c",hcd[i].cd[j]); fprintf(wfile,"%s\n",""); } fprintf(wfile,"%s\n",""); } int main() { htnode ht[mx]; hcode hcd[mx]; char enter;//用于清除换行 int n,i,j; while(fscanf(rfile,"%d",&n),n) { for(i=0;i<n;i++) { fscanf(rfile,"%c%c%lf",&enter,&ht[i].data,&ht[i].weight); } CreatHuffman(ht,n); CreatHuffmanCode(ht,hcd,n); display(ht,hcd,n); } fclose(wfile); fclose(rfile); return 0; }
实验五 树和二叉树
任务(1)和(2):
#include"iostream" #include"stdio.h" #include"algorithm" #include"string" #include"string.h" #include"Stack" #include"queue" #include"vector" //顺序表ADT的定义 //datatype的定义 #ifndef datatype #define datatype NODE #define _ERROR NULL #endif FILE* rfile=fopen("E:\\read5.txt","r"); FILE* wfile=fopen("E:\\write5.txt","w"); //树结点的定义 struct Tnode{ struct Tnode * lchild; struct Tnode * rchild; char* data;//data用于保存节点信息,类型为字符串 }; typedef struct Tnode * Bitree; typedef struct Tnode * NODE; struct Table{ //为了定义栈 datatype* Table_head; int Length; int Max_Length; }; typedef struct Table* mystable; //栈ADT的定义 typedef struct Table* mystack; //为顺序表分配空间,将所有数据初始化为init mystable Assign(const int maxlen,datatype init) { mystable temp; if((temp=(mystable)malloc(sizeof(struct Table)))!=NULL){//分配空间成功 temp->Max_Length = maxlen; temp->Length=0; if((temp->Table_head=(datatype *)malloc(sizeof(datatype)*maxlen))!=NULL) for(int i=0;i<maxlen;i++) *(temp->Table_head+i)=init; else return NULL; return temp; } return NULL; } //判断表是否为空 int isEmpty(const mystable table) { if (table==NULL) return -1; if(table->Length == 0) return 1; return 0; } //判断表是否为满 int isFull(const mystable table) { if (table==NULL) return -1; if(table->Length == table->Max_Length) return 1; return 0; } //获取position位置的数据 datatype get(const mystable table,int position) { if (position>table->Length-1 || position<0) return _ERROR; return *(table->Table_head + position); } //获取表长 int getLength(const mystable table) { if (table==NULL) return -1; return table->Length; } //从表中删除一个数据 int Remove(const mystable table,int position) { int i=0; if(table==NULL) return -1; if(position>table->Length-1 || position<0) return 0; for(i=position;i<table->Length-1;i++) *(table->Table_head+i)=*(table->Table_head+(i+1)); table->Length--; return 1; } //插入一个数据到position位置 int Insert(mystable table,int position,datatype data) { int i=0; if(table==NULL) return -1; if(position>table->Length || position<0) return 0; if(isFull(table)==0){ for(i=table->Length;i>position;i--) *(table->Table_head+i)=*(table->Table_head+(i-1)); *(table->Table_head+i)=data; table->Length++; }else{ mystable temp; if((temp=(mystable)malloc(sizeof(struct Table)))==NULL) return -1; if((temp->Table_head=(datatype*) malloc(sizeof(datatype)*(table->Max_Length+1)))==NULL) return -1; temp->Length=table->Max_Length+1; temp->Max_Length=table->Max_Length+1; for(i=0;i<position;i++) *(temp->Table_head+i)=*(table->Table_head+i); *(temp->Table_head+i)=data; for(i++;i<temp->Length;i++) *(temp->Table_head+i)=*(table->Table_head+(i-1)); free(table->Table_head); free(table); table=temp; } return 1; } //释放表占用的空间 int del(const mystable table) { free(table->Table_head); free(table); return 1; } //在表的最后插入一个数据 int add(const mystable table,datatype x) { return Insert(table,table->Length,x); } //初始化栈,分配空间 mystack initial() { return Assign(100,0); } //从栈中弹出一个数据 datatype pop(mystack Stack) { if(Stack==NULL) return _ERROR; if(isEmpty(Stack)) return _ERROR; datatype data; data=get(Stack,Stack->Length-1); Remove(Stack,Stack->Length-1); return data; } //返回栈顶的数据但不弹出 datatype peek(mystack Stack) { if(Stack==NULL) return _ERROR; if(isEmpty(Stack)) return _ERROR; datatype data; data=get(Stack,Stack->Length-1); return data; } //向栈中压入数据 int push(mystack Stack,datatype x) { return Insert(Stack,Stack->Length,x); } //分配一个新的树节点 NODE newNode(char* data) { NODE temp=(NODE)malloc(sizeof(struct Tnode)); if(temp==NULL) return NULL; temp->lchild=NULL; temp->rchild=NULL; temp->data=data; return temp; } //字符串转化为中缀顺序表,这是本实验的核心代码 mystable char_to_infix(char ex[]) { int length=strlen(ex); mystable infix=Assign(length,NULL); char* temp; for (int i = 0; i < length; i++) { if ((ex[i] >= '0' && ex[i] <= '9') || ex[i] == '.' ) { //若是数字字符则查询直到遇到一个不是数字的字符 int Count=0; for(int j=i;(ex[j] >= '0' && ex[j] <= '9') || ex[j] == '.';j++,Count++); temp=(char *)malloc(sizeof(char)*(Count+1)); for(int j=0;j<Count;j++) temp[j]=ex[i+j]; temp[Count]='\0'; add(infix,newNode(temp)); i=i+Count-1; }else{ temp=(char *)malloc(sizeof(char)*2); temp[0]=ex[i];temp[1]='\0'; add(infix,newNode(temp)); } } return infix; } //中缀表达式转化为后缀表达式 mystable infix_to_postfix(mystable infix) { mystack Stack=initial(); mystable postfix=Assign(getLength(infix),NULL); for (int i = 0; i < getLength(infix); i++) { char opF,opS; opF=get(infix,i)->data[0]; if ((opF>='0' && opF<='9') || opF=='.' || (opF>='a' && opF<='z')) //数字则直接压入后缀表达式 add(postfix,get(infix,i)); else{ if (getLength(Stack) == 0) { push(Stack,get(infix,i)); } else if (opF == '(') { push(Stack,get(infix,i)); } else if (opF == ')') { //遇到右括号,将栈中的数据依次弹出,直到遇到左括号 do { opS = peek(Stack)->data[0]; if (opS != '(') add(postfix,pop(Stack)); else pop(Stack); } while (opS != '('); } else { //比较优先级,若优先级高于栈顶元素则压入栈,否则弹出 do { opS = peek(Stack)->data[0]; int spriority,fpriority; switch(opS){ //设置优先级 case '+':spriority=4;break; case '-':spriority=4;break; case '*':spriority=3;break; case '/':spriority=3;break; case '^':spriority=2;break; case '(':spriority=7;break; } switch(opF){ case '+':fpriority=4;break; case '-':fpriority=4;break; case '*':fpriority=3;break; case '/':fpriority=3;break; case '^':fpriority=2;break; case '(':spriority=7;break; } if (fpriority >= spriority) add(postfix,pop(Stack)); else break; } while (getLength(Stack) != 0); push(Stack,get(infix,i)); } } } while (getLength(Stack) != 0) add(postfix,pop(Stack)); //释放括号占用的内存 for(int i=0;i<getLength(infix);i++){ NODE temp=get(infix,i); if(temp->data[0]=='(' || temp->data[0]==')'){ free(temp->data); free(temp); } } //释放栈占用的内存 del(Stack); //释放掉前缀表达式占用的内存 del(infix); return postfix; } //生成表达式树 Bitree postfix_to_binarytree(mystable postfix) { mystack Stack=initial(); for (int i = 0; i < getLength(postfix); i++) { char name; name=get(postfix,i)->data[0]; if ((name>='0' && name<='9') || name=='.' || (name>='a' && name<='z')){ push(Stack,get(postfix,i)); }else{ NODE parent=get(postfix,i); NODE lchild,rchild; //从栈中弹出操作数,将运算符节点的两个儿子指针指向操作数结点 if(getLength(Stack)!=0){ rchild=pop(Stack); parent->rchild=rchild; } if(getLength(Stack)!=0){ lchild=pop(Stack); parent->lchild=lchild; } push(Stack,parent); } } if(getLength(Stack)!=1){ return NULL; }else{ NODE result=pop(Stack); //释放内存 free(Stack); free(postfix); return result; } } //打印前缀表达式 void print_prefix(Bitree node) { if(node==NULL) return; fprintf(wfile,"%s",node->data); if(node->lchild!=NULL) print_prefix(node->lchild); if(node->rchild!=NULL) print_prefix(node->rchild); } //打印后缀表达式 void print_postfix(Bitree node) { if(node==NULL) return; if(node->lchild!=NULL) print_postfix(node->lchild); if(node->rchild!=NULL) print_postfix(node->rchild); fprintf(wfile,"%s",node->data); } //递归打印叶节点递归函数入口 void _print_path_with_recursion(Bitree tree,NODE path[],int depth) { if(tree==NULL) return; //若为叶节点则打印路径 if(tree->lchild==NULL && tree->rchild==NULL){ fprintf(wfile,"%s : %s",tree->data,tree->data); for(int i=depth-1;i>=0;i--) fprintf(wfile," %s",path[i]->data); fprintf(wfile,"%s\n",""); } if(tree->lchild!=NULL){ path[depth]=tree; _print_path_with_recursion(tree->lchild,path,depth+1); } if(tree->rchild!=NULL){ path[depth]=tree; _print_path_with_recursion(tree->rchild,path,depth+1); } } //非递归打印叶节点 void print_path_without_recursion(Bitree tree) { NODE curr=tree; NODE path[100]; //存放深度的数组 int depth[100]; int top=0,curdepth=0; mystack track=initial(); do{ if(curr!=NULL){ if(curr->lchild==NULL && curr->rchild==NULL){ fprintf(wfile,"%s : %s",curr->data,curr->data); for(int i=curdepth-1;i>=0;i--) fprintf(wfile," %s",path[i]->data); fprintf(wfile,"%s\n",""); //从栈中弹出下一个要访问的结点,并将当前深度更新为该结点深度 curr=pop(track); curdepth=depth[--top]; }else{ path[curdepth]=curr; push(track,curr->rchild); depth[top++]=++curdepth; curr=curr->lchild; } }else{ curr=pop(track); curdepth=depth[--top]; } }while(curr!=NULL || getLength(track)!=0); } //递归打印叶节点主程序入口 void print_path_with_recursion(Bitree tree) { NODE path[100]; _print_path_with_recursion(tree,path,0); } int main(){ char ch[100]; int icase=1; while(fscanf(rfile,"%s",ch),strcmp(ch,"no")!=0)//输入表达式 { fprintf(wfile,"%s%d%s\n\n","案例 #",icase++,": "); mystable infix=char_to_infix(ch); mystable postfix=infix_to_postfix(infix); Bitree root=postfix_to_binarytree(postfix); if(root==NULL) fprintf(wfile,"%s","输入有误!\n\n"); else{ fprintf(wfile,"%s","输出前缀表达式: "); print_prefix(root);//输出前缀式 fprintf(wfile,"%s\n\n",""); fprintf(wfile,"%s","输出后缀表达式: "); print_postfix(root);//输出后缀式2 fprintf(wfile,"%s\n\n",""); fprintf(wfile,"%s\n","用递归打印从根节点到叶子节点的路径:"); print_path_with_recursion(root); fprintf(wfile,"%s\n",""); fprintf(wfile,"%s\n","用非递归打印从根节点到叶子节点的路径:"); print_path_without_recursion(root); } } return 0; }
任务(3):
对于拓扑排序,我用了两种方法,一种是利用邻接矩阵:
#include"iostream" #include"stdio.h" #include"cmath" #include"string.h" #include"queue" #include"stack" #include"vector" #include"algorithm" #include"fstream" using namespace std; const int mx=105; const int inf=32767;//表示无穷大 FILE* rfile=fopen("E:\\read6.txt","r"); FILE* wfile=fopen("E:\\write6.txt","w"); int n,m;;//n表示节点的数目,m表示边的数目 int topoArray[mx];//拓扑排序的数组 bool visited[mx];//用来标记该顶点是否已被访问过 bool cnt[mx];//用于拓扑排序中判断某个点是否已进栈 struct Mgraph//图的邻接矩阵 { int NumVertices,NumEdges; int Edges[mx][mx]; }; struct EdgeNode//邻接表的边节点类型 { int dest;//边的另一顶点位置 int weight;//边的权重 EdgeNode *link;//下一条链指针 }; struct VertexNode//顶点节点类型(表头节点) { int data; EdgeNode *first; }; struct ALGraph//邻接表类型 { VertexNode verticeslish[mx]; int NumVetices,NumEdeges; }; //创建图的邻接矩阵表示 void Creat_Mgraph(Mgraph &M) { int i; M.NumVertices=n; M.NumEdges=m; //初始化所有边之间的权值为-1,表示两个结点之间无直接通路 memset(M.Edges,-1,sizeof(M.Edges)); for(i=0;i<m;i++) { int p,q,w; fscanf(rfile,"%d%d%d",&p,&q,&w); M.Edges[p][q]=w; } } //将邻接矩阵转换为邻接表表示 void Mgraph_to_ALGraph(Mgraph &M,ALGraph &ALG) { ALG.NumVetices=M.NumVertices; ALG.NumEdeges=M.NumEdges; int i,j; for(i=0;i<n;i++) { ALG.verticeslish[i].data=i; ALG.verticeslish[i].first=NULL; for(j=0;j<n;j++) { if(M.Edges[i][j]!=-1) { EdgeNode *temp=new EdgeNode; temp->link=ALG.verticeslish[i].first; temp->weight=M.Edges[i][j]; temp->dest=j; ALG.verticeslish[i].first=temp; } } } } //输出图的邻接矩阵表示 void Output_Mgraph(Mgraph &M) { int i,j; for(i=0;i<M.NumVertices;i++) { fprintf(wfile,"%d%s",i,": "); for(j=0;j<M.NumVertices;j++) { fprintf(wfile,"%d%s",M.Edges[i][j]," "); } fprintf(wfile,"%s\n",""); } fprintf(wfile,"%s\n",""); } //输出图的邻接表表示 void Output_ALGraph(ALGraph &ALG) { int i; for(i=0;i<ALG.NumVetices;i++) { int flag=false; fprintf(wfile,"%d%s",i,": "); EdgeNode *temp; temp=ALG.verticeslish[i].first; while(temp!=NULL) { flag=true; fprintf(wfile,"%d%s%d%s",temp->dest,"(",temp->weight,") "); temp=temp->link; } if(!flag) fprintf(wfile,"%s\n","空"); fprintf(wfile,"%s\n",""); } } //用dfs递归遍历从0开始的深度优先遍历序列 void Dfs_From_0(int k,ALGraph &ALG) { if(!visited[k]) { fprintf(wfile,"%d%s",k," "); visited[k]=true; EdgeNode *temp=ALG.verticeslish[k].first; while(temp!=NULL) { Dfs_From_0(temp->dest,ALG); temp=temp->link; } } } //从0开始的广度优先遍历非递归算法 void Bfs_From_0(int k,ALGraph &ALG) { memset(visited,false,sizeof(visited)); fprintf(wfile,"%d%s",k," "); visited[k]=true; EdgeNode *temp=ALG.verticeslish[k].first; queue<EdgeNode *>q; while(temp!=NULL) { if(!visited[temp->dest]) {q.push(temp);visited[temp->dest]=true;} temp=temp->link; } EdgeNode *cur; while(!q.empty()) { cur=q.front(); q.pop(); k=cur->dest; fprintf(wfile,"%d%s",k," "); cur=ALG.verticeslish[k].first; while(cur!=NULL) { if(!visited[cur->dest]) {q.push(cur);visited[cur->dest]=true;} cur=cur->link; } } } //判断某个节点是否入度为零 bool Judge_Column(Mgraph &M,int k) { int i; for(i=0;i<M.NumVertices;i++) { if(M.Edges[i][k]!=-1) { return false; } } return true; } //输出拓扑排序的结果 void Output_Topoarray(Mgraph &M,int k) { if(k<M.NumVertices) fprintf(wfile,"%s\n","图中有有向环!"); else { fprintf(wfile,"%s","输出该图的拓扑序列: "); for(int i=0;i<k;i++) fprintf(wfile,"%d%s",topoArray[i]," "); } fprintf(wfile,"%s\n",""); } //进行拓扑排序 void TopologicalSort(Mgraph &M) { memset(cnt,false,sizeof(cnt)); stack<int>S; int k=0,i,j; for(i=0;i<M.NumVertices;i++) { if(Judge_Column(M,i)&&!cnt[i]) { cnt[i]=true; topoArray[k++]=i; S.push(i); } } while(!S.empty()) { int cur=S.top(); S.pop(); for(j=0;j<M.NumVertices;j++) M.Edges[cur][j]=-1; for(i=0;i<M.NumVertices;i++) { if(Judge_Column(M,i)&&!cnt[i]) { cnt[i]=true; topoArray[k++]=i; S.push(i); } } } Output_Topoarray(M,k); } int main() { int iCase=1;//案例个数 Mgraph M; ALGraph ALG; while(fscanf(rfile,"%d%d",&n,&m),n&&m) { fprintf(wfile,"%s%d%s\n","案例 #",iCase++,": "); Creat_Mgraph(M); Mgraph_to_ALGraph(M,ALG); fprintf(wfile,"%s\n","输出图的邻接矩阵表示:"); Output_Mgraph(M); fprintf(wfile,"%s\n","输出图的邻接表表示:"); Output_ALGraph(ALG); memset(visited,false,sizeof(visited)); fprintf(wfile,"%s","输出从0开始的递归dfs遍历:"); Dfs_From_0(0,ALG); fprintf(wfile,"%s\n",""); fprintf(wfile,"%s","输出从0开始的非递归bfs遍历: "); Bfs_From_0(0,ALG); fprintf(wfile,"%s\n",""); TopologicalSort(M); fprintf(wfile,"%s\n",""); } return 0; }
一种是利用邻接表:
#include <stdio.h> #include <stdlib.h> #include <Queue> #include <string.h> #include <Stack> using namespace std; bool visit[1000]; int inCount[1000]; typedef struct EdgeNode{ int dest; int cost; struct EdgeNode *Link; }; typedef struct VertexNode { int data; struct EdgeNode *first; }; typedef struct ALGraph { VertexNode *VerticesList; int numVertices,numEdges; }; void InitGraph(ALGraph& G) { G.numVertices=0; G.numEdges=0; G.VerticesList=new VertexNode[1000]; for (int i=0;i<1000;i++) { G.VerticesList[i].first=NULL; } }; int GetVertexPos(ALGraph& G,int vertex)/*找出该顶点的顶点号*/ { for (int i=0;i<G.numVertices;i++) if (G.VerticesList[i].data==vertex) return i; return -1; } int GetValue(ALGraph& G,int i)/*返回顶点i,不合理则返回0*/ { if (i==-1) return 0; else return G.VerticesList[i].data; }; int FirstNeighbor(ALGraph& G,int v)/*返回顶点v的第一个邻接顶点的顶点号,若无则返回-1*/ { if (v!=-1) { EdgeNode *p=G.VerticesList[v].first; if (p!=NULL) return p->dest; } else return -1; } int NextNeighbor(ALGraph &g, int v, int w)/*返回在顶点v的邻接顶点w后的下一个顶点号,没有则返回-1*/ { EdgeNode *p; p=g.VerticesList[v].first; while(p) { if(p->dest==w&&p->Link!=NULL) return p->Link->dest; p=p->Link; } return -1; } void creat(ALGraph& G) { int i,j,k; EdgeNode *s; int n,m; int weight; printf("请输入顶点数和边数:\n"); scanf("%d %d",&G.numVertices,&G.numEdges); printf("输入顶点信息:\n"); for (i=0;i<G.numVertices;i++) { scanf("%d",&G.VerticesList[i].data); G.VerticesList[i].first=NULL; } printf("输入边的信息:\n"); for (k=0;k<G.numEdges;k++) { scanf("%d %d %d",&i,&j,&weight); s=new EdgeNode; s->dest=j; inCount[j]++; s->cost=weight; s->Link=G.VerticesList[i].first; G.VerticesList[i].first=s; } } int Numberofvertices(ALGraph& G)/*返回图中的顶点个数*/ { return G.numVertices; } void PrintfGraph(ALGraph& G)/*输出有向图邻接表*/ { int i,j; EdgeNode *p; printf("图G的顶点数是:%d\n",G.numVertices); printf("顶点向量的值是:"); for (i=0;i<G.numVertices;i++) printf("%d ",G.VerticesList[i].data); printf("\n"); printf("图G的边数是:%d\n",G.numEdges); for (i=0;i<G.numVertices;i++){ for (p=G.VerticesList[i].first;p!=NULL;p=p->Link) printf("(%d,%d,%d)\n",i,p->dest,p->cost); } }; void DFS(ALGraph& G,int v,bool visited[])/*DFS*/ { printf("%d ",GetValue(G,v)); visited[v]=true; int w=FirstNeighbor(G,v); while (w!=-1) { if (visited[w]==false) DFS(G,w,visited); w=NextNeighbor(G,v,w); } }; void BFS(ALGraph&G, int v)/*BFS*/ { int i,k,w,n=Numberofvertices(G); for (i=0;i<n;i++) visit[i]=false; queue <int > q;/*创建队列*/ if (!visit[v]) { printf("%d ",G.VerticesList[v].data); visit[v]=true; } q.push(v); while (!q.empty()) { int vv=q.front(); q.pop(); for (int w = FirstNeighbor(G, vv); w >= 0; w = NextNeighbor(G, vv, w)) { if (!visit[w]) { printf("%d ",G.VerticesList[w].data); visit[w] = true; q.push(w); } } } delete[]visit; }; void TopologicalSort(ALGraph& g)//拓扑排序算法 { stack<int> s; for(int i=1;i<=g.numVertices;i++) if(!inCount[i]) s.push(g.VerticesList[i].data);//入度为0者进栈 int count=0; while(!s.empty()) { int v = s.top(); s.pop(); printf("%d ",v); count++; for(EdgeNode *p = g.VerticesList[v].first ; p!=NULL ; p=p->Link) { //对i号顶点的每个邻接点的入度减1,新产生的入度为0的顶点进栈 int k = p->dest; if(!(--inCount[g.VerticesList[k].data])) s.push(g.VerticesList[k].data); } } printf("\n") if(count<g.numVertices) printf("存在回路\n"); else printf("存在拓扑排序\n"); } int main() { int start; int i,j; ALGraph G; InitGraph(G); creat(G); PrintfGraph(G); TopologicalSort(G); printf("输入从哪个点开始DFS遍历:\n"); scanf("%d",&start); DFS(G,start,visit); printf("\n"); printf("输入从哪个点开始BFS遍历:\n"); scanf("%d",&start); BFS(G,start); printf("\n"); return 0; } /* 5 7 0 1 2 3 4 0 1 10 1 2 50 0 4 100 0 3 30 2 4 10 3 2 20 3 4 60 */
实验六:
1、顺序查找和二分查找
#include"iostream" #include"stdio.h" #include"algorithm" #include"string.h" #include"string" #include"fstream" #include"cmath" #include"queue" #include"stack" #include"vector" using namespace std; const int mx=1005; FILE* rfile=fopen("E:\\read7.txt","r"); FILE* wfile=fopen("E:\\write7.txt","w"); struct SeqList //顺序表的数据结构 { int DataNum; int data[mx]; }; //顺序查找 int SeqFind(SeqList &L,int x) { int step=1; L.data[L.DataNum]=x;//监视哨 for(int i=0;i<=L.DataNum;i++) { fprintf(wfile,"%s%d%s%d %d\n","第 ",step++," 步查找到的值和下标分别为:",L.data[i],i); if(x==L.data[i]) return i; } } //二分查找 int BinFind(SeqList &L,int x) { int step=1; int mid,left,high; left=0;high=L.DataNum-1; while(left<=high) { mid=(left+high)/2; fprintf(wfile,"%s%d%s%d %d\n","第 ",step++," 步查找到的值和下标分别为:",L.data[mid],mid); if(L.data[mid]==x) return mid; else if(x<L.data[mid]) high=mid-1; else left=mid+1; } return L.DataNum; } int main() { int iCase=1;//案例个数 int num;//元素个数; int i,j,FindNum;//FindNum为查找返回的下标 while(fscanf(rfile,"%d",&num),num!=0) { fprintf(wfile,"%s%d%s\n","案例 #",iCase++,": "); SeqList L; L.DataNum=num; fprintf(wfile,"%s","输出原始序列: "); for(i=0;i<num;i++) {fscanf(rfile,"%d",&L.data[i]);fprintf(wfile,"%d ",L.data[i]);} fprintf(wfile,"%s\n",""); fscanf(rfile,"%d",&FindNum); fprintf(wfile,"%s%d\n\n","需要查找的数(顺序查找): ",FindNum); fprintf(wfile,"%s\n","输出查找过程: "); int FindResult=SeqFind(L,FindNum); fprintf(wfile,"%s\n","输出查找结果: "); if(FindResult==L.DataNum) fprintf(wfile,"%s%d%s\n\n","原序列中不存在 ",FindNum,"!"); else fprintf(wfile,"%d%s%d\n\n",FindNum," 在原序列中的下标为: ",FindResult); sort(L.data,L.data+L.DataNum); fprintf(wfile,"%s","将上面的序列排好序输出: "); for(i=0;i<num;i++) fprintf(wfile,"%d%s",L.data[i]," "); fprintf(wfile,"%s\n\n",""); fprintf(wfile,"%s%d\n\n","需要查找的数(折半查找): ",FindNum); FindResult=BinFind(L,FindNum); fprintf(wfile,"%s\n","输出查找结果: "); if(FindResult==L.DataNum) fprintf(wfile,"%s%d%s\n\n","新序列中不存在 ",FindNum,"!"); else fprintf(wfile,"%d%s%d\n\n",FindNum," 在新序列中的下标为: ",FindResult); } return 0; }
2、直接插入排序
#include"iostream" #include"stdio.h" #include"algorithm" #include"string.h" #include"string" #include"cmath" #include"queue" #include"stack" #include"vector" #include"fstream" using namespace std; const int mx=1005; //输出序列 void Output_Array(int Array[],int Num) { int i; for(i=0;i<Num;i++) printf("%d ",Array[i]); printf("\n"); } //直接插入排序 void Straight_Insertion_Sort(int Array[],int Num) { int i,j; for(i=1;i<Num;i++) { if(Array[i]<Array[i-1]) { int temp=Array[i]; for(j=i-1;j>=0&&Array[j]>temp;j--) { Array[j+1]=Array[j]; } Array[j+1]=temp; } printf("第%d次进行插入排序得到的序列: ",i); Output_Array(Array,Num); } } int main() { int iCase=1; freopen("E:\\read8.txt","r",stdin); freopen("E:\\write8.txt","w",stdout); int Array[mx]; int i,j,Num; while(scanf("%d",&Num),Num!=0) { printf("案例 #%d :\n",iCase++); for(i=0;i<Num;i++) scanf("%d",&Array[i]); printf("原始序列:"); for(i=0;i<Num;i++) printf("%d ",Array[i]); printf("\n"); Straight_Insertion_Sort(Array,Num); } }
3、快速排序
#include"iostream" #include"stdio.h" #include"algorithm" #include"string.h" #include"string" #include"cmath" #include"queue" #include"stack" #include"vector" #include"map" using namespace std; const int mx=1005; int step;//记录快速排序进行的步数 int num;//记录序列中元素的个数 void Quick_Sort(int Array[],int low,int high) { if(low>=high) return; int first=low; int last=high; int key=Array[first]; while(first<last)//将比key小的放到key前面,比key大的放到key后面 { while(first<last&&Array[last]>=key) last--; Array[first]=Array[last]; while(first<last&&Array[first]<=key) first++; Array[last]=Array[first]; } Array[first]=key; printf("第 %d 次排序后的序列: ",step++);//输出序列 for(int i=0;i<num;i++) printf("%d ",Array[i]); printf("\n"); Quick_Sort(Array,low,first-1);//分治的思想 Quick_Sort(Array,first+1,high); } int main() { int i,iCase=1; int Array[mx]; freopen("E:\\read9.txt","r",stdin); freopen("E:\\write9.txt","w",stdout); while(scanf("%d",&num),num!=0) { step=1; printf("案例 #%d : \n",iCase++); for(i=0;i<num;i++) scanf("%d",&Array[i]); printf("进行快速排序:\n"); Quick_Sort(Array,0,num-1); } return 0; }