图论基础:无向图与有向图的概念与算法

需积分: 10 3 下载量 55 浏览量 更新于2024-07-13 收藏 1.09MB PPT 举报
"这篇资料主要介绍了图论在数据结构中的应用,包括无向图和有向图的概念、术语以及图的表示方法,并提及了完全图的概念。" 在数据结构领域,图论是一种重要的理论基础,它广泛应用于网络设计、路径搜索、社交网络分析等诸多问题中。本章节主要围绕图的基本定义、术语以及算法展开。 首先,图(Graph)是由顶点(Vertices,V)集合和边(Edges,E)集合构成的数据结构。用数学符号表示为 Graph = (V, E),其中V是非空有限的顶点集,E是边集。图可以分为两大类:无向图和有向图。 1. 无向图:在无向图中,边是无序的,(v1, v2)和(v2, v1)被视为同一条边。图中的每个顶点可以通过多条边与其他顶点相连,但没有方向性。 2. 有向图:与无向图不同,有向图的边是有方向的,<v1, v2>和<v2, v1>代表两条不同的边。有向图中,每个顶点可以作为起点或终点,形成有向边。 举例来说,G1是一个无向图,包含四个顶点V1, V2, V3, V4,其边集E(G1)包含了所有可能的V1到其他顶点的连接。而G2是一个有向图,同样有三个顶点,边集E(G2)中每条边都有明确的方向。 接下来,资料提到了两种特殊类型的图: 1. 多重图:在多重图中,允许存在多条连接相同两个顶点的边,但在实际应用中,多重图通常不被讨论,因为它们在很多情况下可以被替代为无重边的图(简单图)。 2. 完全图:在无向图中,如果任意两个不同的顶点之间都有一条边相连,那么这个图就被称为完全无向图。对于n个顶点的完全无向图,它的边数最多为n*(n-1)/2。而在有向图中,每个顶点都可以作为另一个顶点的起点或终点,因此边数最多为n*(n-1)。当这个条件满足时,我们称其为完全有向图。 理解这些基本概念后,我们可以应用图论来解决诸如最短路径、最小生成树、网络流等问题,这些问题在计算机科学和工程中有着广泛的应用。例如,Dijkstra算法用于寻找图中单源最短路径,而Kruskal或Prim算法则用于构造最小生成树。在实际应用中,根据问题的具体情况选择合适的图表示和算法是非常关键的。例如,如果图的边数量很大,但更新操作频繁,那么可能需要选择更利于动态修改的图数据结构,如邻接表,而不是邻接矩阵,因为后者的时间复杂度较高。 图论在数据结构中占据着核心地位,深入理解其概念和术语,以及如何有效地表示和操作图,对于解决复杂问题至关重要。在实际编程中,需要结合具体场景,选择合适的数据结构和算法,以实现高效的问题求解。
2009-03-13 上传
其涵盖了数据结构中图章节的大部分算法 #include<iostream.h> #include<stdio.h> #include<stdlib.h> #include<conio.h> #include<math.h> #ifndef ONCE_GRAPH #define ONCE_GRAPH const int MAX_NUM=32767; const int QUEUESIZE=100; struct ArcNode {int adjvex; ArcNode *nextarc; int weight; }; struct VNode {char* pointdata; ArcNode *firstarc; }; struct edge { int u; int v; void swap(const int p,const int n) { int temp; if(p>n) { temp=u; u=u>v?u:v; v=v<temp?v:temp; } else if(p<n) { temp=u; u=u<v?u:v; v=v>temp?v:temp; } } }; class Graph {private: VNode *a; int pointnum; int edgenum; int kind; bool *vision; void BFSpart(int start); void DFSpart(int start); void findindegree(int *array); bool Hamiton(int start,int *&path,int &count); void Criticalpoint_part(int s,int &count,int *vis,int *low); void Thedoubleconnectsweight_part(const int cp,const int parent,edge *const stack,int &top,int &count,int *vis,int *low)const; void Topologicsort_helpCriticalpath(int *array,int &tp,int *earlist); public: Graph(int pointnum,int kind); ~Graph(); void creatGraph(); void DFS(int start); void BFS(int start); bool isConnectedGraph(); void Topologicsort(); void Criticalpoint(int start=1); void Criticalpath(); void Thedoubleconnectsweight(const int start)const; void Minimumandborntree_a(int satrt); void Minimumandborntree_b(); void Theshortestpath_a(int start=1); void Theshortestpath_b(); void Hamitontrack(); }; //************************************************************************************************** Graph::Graph(int pointnum,int kind) { this->pointnum=pointnum; this->kind=kind; a=new VNode[pointnum+1]; vision=new bool[pointnum+1]; for(int i=1;i<=pointnum;i++) { a[i].firstarc=NULL; vision[i]=false; } edgenum=0; } //********************************************************************************** Graph::~Graph() { for(int i=1;i<=pointnum;i++) { ArcNode *p=a[i].firstarc, *q; while(p) { q=p->nextarc; delete p; p=q; } } //**************************** delete []a; delete []vision; //**************************** } //********************************************************************************** void Graph::creatGraph() { cout<<"Attention:"<<endl; cout<<"Input format: <starting point><end point><weight>"<<endl; cout<<"When the input point value is not greater than zero or the weight is less than zero,we'll stop the establishment!"<<endl;; int i=1, ps, pe, weight; while(1) { cout<<i++<<"th:"; cin>>ps>>pe>>weight; if(ps<=0||ps>pointnum||pe<=0||pe>pointnum||pe==ps||weight<0) break; ArcNode *p=a[pe].firstarc; while(p) { if(p->adjvex==ps) { p->weight=weight; ArcNode *q=a[ps].firstarc; if(kind==1) { while(q) { if(q->adjvex==pe) { q->weight=weight; break; } q=q->nextarc; } } break; } p=p->nextarc; } if(!p) { if(kind==1) { ArcNode *arc1=new ArcNode, *arc2=new ArcNode; arc1->adjvex=pe; arc1->weight=weight; arc2->adjvex=ps; arc2->weight=weight; arc1->nextarc=a[ps].firstarc; a[ps].firstarc=arc1; arc2->nextarc=a[pe].firstarc; a[pe].firstarc=arc2; } else { ArcNode *arc1=new ArcNode; arc1->adjvex=pe; arc1->weight=weight; arc1->nextarc=a[ps].firstarc; a[ps].firstarc=arc1; } edgenum++; } //cout<<endl; } //cout<<"end creatGraph!"<<endl; } //********************************************************************************** void Graph::DFS(int start=1) { //bool vision[pointnum+1]; for(int i=1;i<=pointnum;i++) { vision[i]=false; } start=start?start%(pointnum+1):1; DFSpart(start); for(i=1;i<=pointnum;i++) { DFSpart(i); } //cout<<"end of DFS!"<<endl; } //********************************************************************************** void Graph::DFSpart(int start=1) { //cout.flush(); if(vision[start]); else cout<<start<<" "; vision[start]=true; ArcNode *p=a[start].firstarc; while(p) { if(!vision[p->adjvex]) { DFSpart(p->adjvex); } p=p->nextarc; } } //********************************************************************************** void Graph::BFSpart(int start=1) { //cout<<"get into BFSpart!"<<endl; //bool vision[pointnum+1]; /*for(int i=1;i<=pointnum;i++) { vision[i]=false; } */ //cout.flush(); int queue[QUEUESIZE]; int front=0, rear=0; queue[rear++]=start; //vision[start]=true; while(front<rear) { //cout<<"get into BFSpart!"<<endl; //cout<<rear<<" "<<front<<" "<<queue[front]<<endl; if(!vision[queue[front]]) { cout<<queue[front]<<" "; vision[queue[front]]=true; } ArcNode *p=a[queue[front]].firstarc; while(p) { if(!vision[p->adjvex]) queue[rear++]=p->adjvex; p=p->nextarc; } front++; } } //********************************************************************************** void Graph::BFS(int start=1) { int i; for(i=1;i<=pointnum;i++) { vision[i]=false; } BFSpart(start); //cout<<"get into BFS!"<<endl; for(i=1;i<=pointnum;i++) BFSpart(i); } void Graph::findindegree(int *array) { for (int j=1;j<=pointnum;j++) array[j]=0; ArcNode *temp; for(int i=1;i<=pointnum;i++) { temp=a[i].firstarc; while(temp) { array[temp->adjvex]++; //cout<<"in while!"<<endl; temp=temp->nextarc; } //cout<<"in for!"<<endl; //cin>>j; } } //************************** ******************************************************** void Graph::Topologicsort() { //int pointnum=this->pointnum; if(kind==1) { cout<<"Just directed graph can be engaged in Topologicsort!"<<endl; return; } int num=0; ArcNode *temp; int *indegree=new int[pointnum+1]; findindegree(indegree); //cout<<"Have already walked findindegree!"<<endl; int *stack=new int[pointnum]; int top=-1; for(int i=1;i<=pointnum;i++) { if(indegree[i]==0) { stack[++top]=i; //array[num++]=i; } } cout<<"("; while(top>=0) { cout<<stack[top]<<","; temp=a[stack[top--]].firstarc; while(temp) { if(!--indegree[temp->adjvex]) { stack[++top]=temp->adjvex; //array[num++]=temp->adjvex; } temp=temp->nextarc; } } cout<<");"<<endl; //**************************** delete []indegree; delete []stack; //**************************** } //********************************************************************************** void Graph::Minimumandborntree_a(int start=1) { int min; struct arraynode { int weight; int startpoint; }; arraynode *choos=new arraynode[pointnum]; for (int i=1;i<=pointnum;i++) { choos[i].startpoint=start; choos[i].weight=MAX_NUM; vision[i]=false; } vision[start]=true; ArcNode *temp=a[start].firstarc; while (temp) { choos[temp->adjvex].weight=temp->weight; temp=temp->nextarc; } int j=1; while(true) { j=1; for(;j<=pointnum&&vision[j];j++); min=j; j++; for (;j<=pointnum&&!vision[j];j++) if(choos[min].weight>choos[j].weight&&!vision[j]) min=j; if (min>pointnum) return; vision[min]=true; cout<<"("<<choos[min].startpoint<<","<<min<<")"<<choos[min].weight<<endl; temp=a[min].firstarc; while (temp) { if(temp->weight<choos[temp->adjvex].weight&&!vision[temp->adjvex]) { choos[temp->adjvex].startpoint=min; choos[temp->adjvex].weight=temp->weight; } temp=temp->nextarc; } } //***************** delete []choos; //***************** } //********************************************************************************** void Graph::Minimumandborntree_b() { //*******************************据邻接表求边集数组************************************* struct edgepoint { int start; int end; int weight; }; edgepoint *edge=new edgepoint[edgenum+1];//new! for(int i=1;i<=edgenum;i++) edge[i].weight=-1; int count=1; if(kind==1) { for(int j=1;j<=pointnum;j++) for(ArcNode *temp=a[j].firstarc;temp;temp=temp->nextarc) if (temp->adjvex<=j); else { edge[count].start=j; edge[count].end=temp->adjvex; edge[count].weight=temp->weight; count++; } } else { for(int j=1;j<=pointnum;j++) for(ArcNode *temp=a[j].firstarc;temp;temp=temp->nextarc) { edge[count].start=j; edge[count].end=temp->adjvex; edge[count].weight=temp->weight; count++; } } //cout<<"edge end!"<<endl; //********************************************************************************** //for(int e=1;e<=edgenum;e++) // cout<<edge[e].start<<" "<<edge[e].end<<" "<<edge[e].weight<<endl; //cout<<"edgenum is "<<edgenum<<endl; bool *vis=new bool[edgenum+1];//new! int *collect=new int[pointnum+1];//new! for(int m=1;m<=edgenum;m++) vis[m]=false; for(int M=1;M<=pointnum;M++) { collect[M]=-1; } //cout<<"Endow with an early value end!"<<endl; while(true) { //cout<<"now in while!"<<endl; int min=-1, j; for(j=1;j<=edgenum&&vis[j];j++); min=j; //cout<<"min is "<<min<<endl; if(min!=-1&&min<=edgenum) { //cout<<"min is "<<min<<endl; for(;j<=edgenum;j++) if(edge[min].weight>edge[j].weight&&!vis[j]) min=j; //cout<<"min is "<<min<<endl; int parent_s=edge[min].start, parent_e=edge[min].end; //cout<<"no wrong!"<<endl; //cout<<parent_s<<" "<<parent_e; //cout.flush(); while (collect[parent_s]!=-1) parent_s=collect[parent_s]; while(collect[parent_e]!=-1) parent_e=collect[parent_e]; //cout<<"no wrong dddd!"<<endl; if(parent_s!=parent_e) { collect[parent_e]=parent_s; cout<<"("<<edge[min].start<<","<<edge[min].end<<")"<<edge[min].weight<<endl; } vis[min]=true; } else break; //cout<<"while end!"<<endl; } cout<<endl; //**************************** delete []vis; delete []collect; delete []edge; //**************************** } void Graph::Theshortestpath_a(int start) { if(start<=0) { cout<<"wrong start point!"<<endl; return; } int *path=new int[pointnum+1];//new! struct wegnode { int weight; int currentpoint; }; wegnode *we=new wegnode[pointnum+1];//new! ArcNode *temp=a[start].firstarc; for(int i=1;i<=pointnum;i++) { vision[i]=false; we[i].weight=MAX_NUM; path[i]=-1; we[i].currentpoint=start; } vision[start]=true; while(temp) { we[temp->adjvex].weight=temp->weight; temp=temp->nextarc; } while(true) { int j, min=-1; for(j=1;j<=pointnum&&vision[j];j++); if(j<=pointnum) { min=j++; for(;j<=pointnum;j++) if(we[min].weight>we[j].weight&&!vision[j]) min=j; vision[min]=true; path[min]=we[min].currentpoint; temp=a[min].firstarc; while(temp) { if(!vision[temp->adjvex]) { if((we[min].weight+temp->weight)<we[temp->adjvex].weight) { we[temp->adjvex].weight=we[min].weight+temp->weight; we[temp->adjvex].currentpoint=min; } } temp=temp->nextarc; } } else break; } int *stack=new int[pointnum],//new! top=-1; for(int u=1;u<=pointnum;u++) { if(u!=start) { int up=u; while(up!=-1) { stack[++top]=up; up=path[up]; } } if(top!=-1) { cout<<start<<" to "<<u<<" ("; while(top!=-1) cout<<","<<stack[top--]; cout<<")"<<" path weight:"<<we[u].weight<<endl; } } //**************************** delete []stack; delete []we; delete []path; //**************************** } //********************************************************************************** void Graph::Theshortestpath_b() { int** path=new int*[pointnum+1];//new! int** d=new int*[pointnum+1];//new! for(int i=1;i<=pointnum+1;i++)//new! { path[i]=new int[pointnum+1]; d[i]=new int[pointnum+1]; } for(int m=1;m<=pointnum;m++) for(int n=1;n<=pointnum;n++) { path[m][n]=-1; d[m][n]=MAX_NUM; } ArcNode *temp; for(int j=1;j<=pointnum;j++) { temp=a[j].firstarc; while(temp) { path[j][temp->adjvex]=j; d[j][temp->adjvex]=temp->weight; temp=temp->nextarc; } } for(int p=1;p<=pointnum;p++) for(int q=1;q<=pointnum;q++) for(int e=1;e<=pointnum;e++) { if(d[p][e]+d[e][q]<d[p][q]) { d[p][q]=d[p][e]+d[e][q]; path[p][q]=path[e][q]; } } //cout<<"Didn't die three for before!"<<endl; //************************打印结果段******************** for(int w=1;w<=pointnum;w++) for(int s=1;s<=pointnum;s++) { //cout<<"in for!"; if (w>s) { //cin>>p; cout<<"The shortest path from "<<s<<" to "<<w<<": "<<"("<<s; int t=path[w][s]; while (t!=w) { cout<<","<<t; t=path[w][t]; } cout<<","<<w<<")"<<"---------weight: "<<d[w][s]<<endl<<endl; } } //****************************************************** //********************************* for (int h=1;h<=pointnum;h++) { delete []path[h]; delete []d[h]; } //cout<<"no wrong"<<endl; //delete path[0]; //delete d[0]; //cout<<"no wrong"<<endl; //delete []path; //delete []d; //?????????????????????????怎么释放path和d????????????????? //********************************* } //********************************************************************************** bool Graph::Hamiton(int start,int *&path,int &count) { //cout<<"in Hamiton"<<endl; ArcNode *temp=a[start].firstarc; path[++count]=start; vision[start]=true; while(temp) { //cout<<"in Hamiton while"<<endl; if(!vision[temp->adjvex]) if(Hamiton(temp->adjvex,path,count)) return true; if(vision[temp->adjvex]&&temp->adjvex==path[0]&&count==(pointnum-1)) return true; temp=temp->nextarc; } vision[start]=false; count--; //cout<<"in Hamiton end"<<endl; return false; } //********************************************************************************** void Graph::Hamitontrack() { int *path=new int[pointnum], count=-1, start; for(int i=1;i<=pointnum;i++) vision[i]=false; while(true) { cout<<"Please input a start point between "<<1<<" to "<<pointnum<<" to order"<<endl; cin>>start; if(start<1||start>pointnum) cout<<"Illegal point!"<<endl; else break; } cout<<endl<<"Press any key to start..."; cout.flush(); getch(); system("cls"); if(Hamiton(start,path,count)) { cout<<"Hamitontrack:"<<endl; for(int i=0;i<pointnum;i++) cout<<path[i]<<">>>"; cout<<path[0]<<endl; } else { cout<<"No Hamitontrack in this graph!"<<endl; } //for(int j=0;j<pointnum;j++) // cout<<path[j]<<">>>"; cout.flush(); //**************************** delete []path; //**************************** } //********************************************************************************** bool Graph::isConnectedGraph() { int *coll=new int[pointnum+1];//new! ArcNode *temp; for(int i=1;i<=pointnum;i++) coll[i]=-1; if(kind==1) for(int j=1;j<=pointnum;j++) { temp=a[j].firstarc; while(temp) { if(j<temp->adjvex) { coll[temp->adjvex]=j; } temp=temp->nextarc; } } else { delete []coll; return false; } for(int m=1;m<=pointnum;m++) for(int n=coll[m],t=m;n!=-1;t=n,n=coll[n]) if(coll[n]!=-1) coll[t]=coll[n]; int ancestor, t=1; while(coll[t]!=-1) t=coll[t]; ancestor=t; for(int e=2;e<=pointnum;e++) { t=e; while (coll[t]!=-1) t=coll[t]; if(ancestor!=t) return false; } delete []coll; return true; } //********************************************************************************** void Graph::Criticalpoint(int start) { int *vis=new int[pointnum+1], *low=new int[pointnum+1], count=0; for(int i=1;i<=pointnum;i++) vis[i]=0; cout<<"Critical point below:"<<endl; Criticalpoint_part(start,count,vis,low); //cout<<"kkkkkkkkk"<<endl; if(count<pointnum) { cout<<" "<<start; ArcNode *temp=a[start].firstarc; while(temp) { if(!vis[temp->adjvex]) Criticalpoint_part(temp->adjvex,count,vis,low); temp=temp->nextarc; } } cout<<endl; //********************** delete []vis; delete []low; //********************** } //********************************************************************************** void Graph::Criticalpoint_part(int s,int &count,int *vis,int *low) { int min; min=vis[s]=++count; ArcNode *temp=a[s].firstarc; while(temp) { //cout<<"kkkkkwhlll"<<endl; if(!vis[temp->adjvex]) { //cout<<"kkkif"<<endl; Criticalpoint_part(temp->adjvex,count,vis,low); if(low[temp->adjvex]<min) min=low[temp->adjvex]; if(low[temp->adjvex]>=vis[s]) cout<<" "<<s; } else if(vis[temp->adjvex]<min) { min=vis[temp->adjvex]; //cout<<"kkk else if"<<endl; } temp=temp->nextarc; } low[s]=min; } //********************************************************************************** void Graph::Thedoubleconnectsweight_part(const int cp,const int parent,edge *const stack,int &top,int &count,int *vis,int *low)const { int min; edge e; min=vis[cp]=++count; ArcNode *temp=a[cp].firstarc; while(temp) { if(temp->adjvex!=parent&&vis[temp->adjvex]<vis[cp]) { e.u=cp; e.v=temp->adjvex; stack[++top]=e; } if(!vis[temp->adjvex]) { Thedoubleconnectsweight_part(temp->adjvex,cp,stack,top,count,vis,low); if(low[temp->adjvex]>=vis[cp]) { cout<<"{"; do { e=stack[top--]; e.swap(cp,temp->adjvex); cout<<"("<<e.u<<","<<e.v<<") "; } while (e.u!=cp||e.v!=temp->adjvex); cout<<"}"<<endl; } if(min>low[temp->adjvex]) min=low[temp->adjvex]; } else if(vis[temp->adjvex]<min) min=vis[temp->adjvex]; temp=temp->nextarc; } low[cp]=min; } //********************************************************************************** void Graph::Thedoubleconnectsweight(const int start)const { if(start<1||start>pointnum) return; int *vis=new int[pointnum+1], *low=new int[pointnum+1], count=0, top=-1; edge *stack=new edge[edgenum]; for(int i=1;i<=pointnum;i++) vis[i]=0; Thedoubleconnectsweight_part(start,-1,stack,top,count,vis,low); //************************* delete []vis; delete []low; delete []stack; //************************* } //********************************************************************************** void Graph::Topologicsort_helpCriticalpath(int *array,int &tp,int *earlist) { tp=-1; //int pointnum=this->pointnum; if(kind==1) { cout<<"Just directed graph can be engaged in Topologicsort!"<<endl; return; } int num=0; ArcNode *temp; int *indegree=new int[pointnum+1]; findindegree(indegree); //cout<<"Have already walked findindegree!"<<endl; int *stack=new int[pointnum]; int top=-1; for(int i=1;i<=pointnum;i++) { if(indegree[i]==0) { stack[++top]=i; //array[num++]=i; } earlist[i]=0; } //cout<<"Have already walked for!"<<endl; while(top>=0) { array[++tp]=stack[top]; int topc; temp=a[topc=stack[top--]].firstarc; //cout<<"in while --!"<<endl; while(temp) { //cout<<"in while!"<<endl; if(!--indegree[temp->adjvex]) { stack[++top]=temp->adjvex; //array[num++]=temp->adjvex; } //cout<<"end if!"<<endl; //cout<<topc<<endl; if(earlist[temp->adjvex]<earlist[topc]+temp->weight) earlist[temp->adjvex]=earlist[topc]+temp->weight; //cout<<"end if if!"<<endl; temp=temp->nextarc; } } //**************************** delete []indegree; delete []stack; //**************************** } //********************************************************************************** void Graph::Criticalpath() { int *stack=new int[pointnum+1], *earliest=new int[pointnum+1], *lastest=new int[pointnum+1], top=-1; Topologicsort_helpCriticalpath(stack,top,earliest); //cout<<"end Topologicsort_helpCriticalpath"<<endl; for(int i=1;i<=pointnum;i++) lastest[i]=earliest[pointnum]; while (top>=0) for(ArcNode *temp=a[stack[top--]].firstarc;temp;temp=temp->nextarc) if(lastest[temp->adjvex]>lastest[stack[top+1]]-temp->weight) lastest[temp->adjvex]=lastest[stack[top+1]]-temp->weight; for(int t=1;t<=pointnum;t++) { cout<<earliest[t]<<" "<<lastest[t]<<endl; } cout<<"{"; for(int m=1;m<=pointnum;m++) for(ArcNode *tp=a[m].firstarc;tp;tp=tp->nextarc) if(earliest[m]==(lastest[tp->adjvex]-tp->weight)) cout<<"("<<m<<","<<tp->adjvex<<") "; cout<<"}"<<endl; //*********************** delete []stack; delete []earliest; delete []lastest; //*********************** } //********************************************************************************** //////////////////////////////////////////////////////////////////////////////////// #endif