图
图: 邻接矩阵 MGraph *G int j; for(j=0;j<n;j++) if(G->a[i][j]!=0) printf("%d",j); //邻接表 LGragh *G ENode *p=G->a[i]; while(p){ printf("%d",p->adjVex); p=p->nextArc; } //图的深度优先遍历(邻接表) void DFS(LGraph *G,int i,int visited[]) { printf("%d",i)//访问节点 visited[i]=1;//设置结点i已访问 Enode *p=G->a[i];//获取顶点i的邻接链表的头结点 while(p){ //依次考察i的邻接链表中的每一个结点 if(!visited[p->adjVex]) //如果该结点表示的顶点未被访问,则对该结点执行DFS DFS(G,p->adjVex,visited) } void DFS_Graph(LGragh *G) { int i; int *visited=(int*)malloc(G->n*sizeof(int);//创建顶点是否已访问标记数组 for(i=0;i<G->n;i++)//初始化visited数组,设置均未被访问 visited[i]=0; for(i=0;i<G->n;i++)//防止存在图不连通的情况,依次检查各顶点是否被访问 { if(!visited[i])//如果未被访问,则执行DFS,否则检查下一个结点 DFS(G,i,visited); } } //遍历顶点i的所有邻接顶点 //邻接矩阵 //求有向图的根结点数量 void DFS(LGraph *G, int i, int visited[]){ visited[i]=1;//设置结点i已访问 ENode *p=G->a[i];//获取顶点i的邻接链表的头结点 while(p)//依次考察i的邻接链表中的每一个结点 { if(!visited[p->adjVex])//如果该结点表示的顶点未被访问,则对该结点执行DFS DFS(G,P->adjVex,visited) } } int DFS_Graph(LGraph *G)//寻找根结点,返回该结点,不存在则返回-1 { int i,j,tmp=0,count=0; int *visited=(int*)malloc(G->n*sizeof(int)); for(i=0;i<G->n;i++){ for(i=0;i<G->n;i++) visited[i]=0; tmp=0; DFS(G,i,visited); for(j=0;j<G->n;j++) tmp=visited[j]+tmp; if(tmp==G->n) count++; } return count; } //将图的邻接矩阵改为邻接表存储 void Transfer(MGraph *mg, LGraph *lg) { ENode *p; int i, j; lg = (LGraph*)malloc(sizeof(LGraph)); //可有可无 lg->n=mg->n; lg->e=mg->e; lg->a = (ENode **)malloc(sizeof(ENode*)*lg->n); for(i=0;i<mg->n;i++) for(j=0;j<mg->n;j++) if(mg->a[i][j]==1){ p=(ENode *)malloc(sizeof(ENode)); p->adjVex=j; p->nextArc=lg->a[i]; lg->a[i]=p; } } //图的深度优先遍历 void DFS(LGraph *G, int visited[], int i){ visited[i]=1; //访问顶点i ENode *p=G->a[i]; while(p){ if(!visited[p->adjVex]) DFS(G, visited, p->adjVex); p=p->nextArc; } } void DFSTraverse(LGraph *G){ int i; int *visited=(int *)malloc(sizeof(int)*G->n); for(i=0;i<G->n;i++) visited[i]=0; for(i=0;i<G->n;i++) if(!visited[i]) DFS(G, visited, i); } //判断无向图G是否连通,若连通则返回1,否则0 算法思想:采用遍历方式判断无向图是否连通,若用深度优先遍历算法,先给visited[]数组置初值为0,然后从顶点0开始遍历该图,在一次遍历以后,若所有顶点i的visited[i]均为1,则该图是连通的 int DFSTrave(Graph *G,int I,int j) { int i; bool*visited=(bool*)malloc(sizeof(bool)); for(i=0;i<G->n;i++) visited[i]=0; DFS(G,i,visited);//从顶点i开始深度优先遍历 for(i=0;i<G->n;i++) if(visited[i]==0) return 0; return 1; } void DFS(LGragh *G,int i, bool visited[]) { if(visited[i]) return; visited[i]=true; ENode *p=G->a[i]; while(p){ DFS(G,p->adjVex,visited); p=p->nextArc; } } //判断一个无向图G是否为一棵树 void DFS(LGraph *G, int visited[], int i){ visited[i]=1; ENode *p=G->a[i]; while(p){ if(!visited[p->adjVex]) DFS(G, visited, p->adjVex); p=p->nextArc; } } BOOL IsTree(LGraph *G){ int i; if(G->e != G->n-1) return FALSE; //检查条件1 int *visited=(int *)malloc(sizeof(int)*G->n); for(i=0;i<G->n;i++) visited[i]=0; DFS(G, visited, 0); for(i=0;i<G->n;i++) if(visited[i]==0) return FALSE; return TRUE; } // 补充:检测无向图的回路 方法一: void DFS(LGraph *G, int visited[], int i,int from, int *isCycle){ if(visited[i]) { isCycle=1; return; } visited[i]=1; ENode *p=G->a[i]; while(p){ if(p->adjVex!=from) DFS(G, visited, p->adjVex); p=p->nextArc; } } BOOL IsCycle(LGraph *G){ int i, isCycle=0; int *visited=(int *)malloc(sizeof(int)*G->n); for(i=0;i<G->n;i++) visited[i]=0; for(i=0;i<G->n;i++){ if(!visited[i]) DFS(G, visited, i); if(isCycle==1) return TRUE; } if(isCycle==1) return TRUE; else return FALSE; } //有向图检测回路 利用类似拓扑排序的方法,不断删除入度为0的顶点及其出边,当堆栈为空,还有未处理的顶点时,表面存在回路 void Degree(int*inDegree,Graph*g) { int i; ENode *p; for(i=0;i<g->n;i++) inDegree[i]=0; for(i=0;i<g->n;i++) for(p=g->a[i];p;p=p->nextArc) inDegree[p->adjVex]++;//顶点i的邻接顶点入度加1 } bool IsCycle(LGraph*g) { int i,j,k; ENode *p; Stack s; int *inDegree=(int*)malloc(sizeof(int)*g->n); Degree(inDegree,g);//计算顶点的入度 for(i=0;i<g->n;i++) if(!inDegree[i]) Push(s,i);//入度为0的顶点进栈 for(i=0;i<g->n;i++)//寻找拓扑序列 { if(IsEmpty(s)) return true;//若堆栈为空则有回路 else{ j=pop(s);顶点出栈 for(p==g->a[j];p;p=p->nextArc){//考察j每一个邻接顶点 inDegree[p->adjVex]--;将j的邻接结点的入度减一,即删除出边 if(!inDegree[p->adjVex])//若该邻接结点入度为0,则进栈 Push(s,p->adjVex); } } } return false; } //扩展题:打印从i到j的路径 void DFS(LGraph *G, int visited[], int i, int path[], int from){ visited[i]=1; path[i]=from; ENode *p=G->a[i]; while(p){ if(!visited[p->adjVex]) DFS(G, visited, p->adjVex, path, i); p=p->nextArc; } } void PrintPath(LGraph *G, int start, int end){ int i; Stack S; int *visited=(int *)malloc(sizeof(int)*G->n); int *path=(int *)malloc(sizeof(int)*G->n); for(i=0;i<G->n;i++){ visited[i]=0; path[i]=-1;} DFS(G, visited, start, path, -1); if(visited[end]){ i=end; do{ Push(S, i); i=path[i]; }while(path[i]!=start); Push(S, start); while(!IsEmpty(S)) { printf("%d ", Top(S)), Pop(S);} } else printf("......"); } //计算各顶点的入度和出度 邻接表 void DegreeCount(LGraph *G,int inDegree[], int outDegree[]) { int i,count; ENode *p; for(i=0;i<G->n;i++) inDegree[i]=outDegree[i]=0; for(int i=0;i<G->n;i++) { count=0; p=G->a[i]; while(p){ count++; inDegree[p->adjVex]++; } outDegree[i]=count; } } //我们将入度和出度相等的顶点定义为"平衡顶点",试编写一个算法输出一个采用邻接表存储结构的有向图中的所有平衡顶点 算法思想:分别计算各顶点的入度和出度,再判定是否相等,相等则输出, void BalanceNodes(LGraph *G) { int *inDegree=(int*)malloc(sizeof(int)*G->n); int *outDegree=(int*)malloc(sizeof(int)*G->n; for(int i=0;i<G.n;i++) inDegree[i]=outDegree[i]=0; ENode *p; for(int i=0;i<G->n;i++){ p=G->a[i]; while(!p){ outDegree[i]++; inDegree[p->adjVex]++; p=p->link; } } printf(" 平衡顶点: "); for(int i=0;i<G->n;i++) if(inDegree[i]==outDegree[i]) printf("%d",i); printf("\n"); } //判断G1是否是G2的子图 BOOL IsSublist(ENode *L1,ENode *L2)//判断L1是否是L2的子集 { if(!L1) return TRUE; if(L1&&!L2) return FALSE; ENode *p=L1, *q; while(p){ q=L2; do{ if(p->adjVex==q->adjVex) break; q=q->nextArc; }while(q); if(!q) return FALSE; p=p->nextArc; } return TRUE; } BOOL IsSubGraph(LGraph *G1,LGragh *G2) { int i; if(!G1) return TRUE; if(G1&&!G2) return FALSE; if(G1->n>G2->n) return FALSE;//如果G1顶点数量较多,则肯定不是子图 for(i=0;i<G1->n;i++) { if(!IsSubList(G1->a[i],G2->a[i]))//如果G1的顶点i的邻接顶点链表不是G2的顶点i的 return FALSE; //邻接顶点链表子集,则不是子图 return TRUE; } } 5 算法思想: (1) 最小值存在于根节点的左孩子的左孩子的。。。(最左的子孙节点) (1) 最大值存在于根节点的右孩子的右孩子的。。。(最右的子孙节点) //求用邻接表存储的无向图中,"节点总数恰好为k"的连通分量的个数 void DFS(LGraph *G, int visited[], int i, int *count){ visited[i]=1; *count++; ENode *p=G->a[i]; while(p){ if(!visited[p->adjVex]) DFS(G, visited, p->adjVex); p=p->nextArc; } } int FindSubGraphs(LGraph *G, int k){ int i, count=0, num=0; int *visited=(int *)malloc(sizeof(int)*G->n); for(i=0;i<G->n;i++) visited[i]=0; for(i=0;i<G->n;i++){ count=0; if(!visited[i]) DFS(G, visited, i, &count); if(count==k) num++; } return num; } //用拉链法构造散列表,并解决冲突,设计算法实现散列表搜索和插入 typedef struct node{ int data; struct node *next; }Node; typedef struct ht{ Node **table; int M; }HT; int Hash(int x, int M) { return x%M; } BOOL Search(HT *h, int x){ int addr=Hash(x, h->M); Node *p=h->table[addr]; while(p){ if(p->data==x) return TRUE; p=p->next; } return FALSE; } BOOL Insert(HT *h, int x){ int addr=Hash(x, h->M); if(Search(h, x)) return FALSE; Node *p=(Node*)malloc(sizeof(Node)); p->data=x; p->next=h->table[addr]; h->table[addr]=p; return TRUE; } 排序设数组中存放了一个无序的关键字序列K0,K1,....Kn-1.现要求将一指定元素Ki放在该元素在排序之后的正确位置上(例如,对于序列23,12,8,45,38而言,元素23在排序后应放在2号位,从0开始编号) void SetLoc(int[]K,int n,int i) { if(i<n||i>=n){ printf("The index i is illegal"); return; } int seq=0; for(int j=0;j<n;j++) if(K[j]<K[i]) seq++; int tmp=K[i]; k[i]=K[seq]; K[seq]=tmp; }