圖鄰接表類(圖的遍歷方法,最短距離及路徑)

一:總結圖的基本概念:

1.圖分爲有向圖(入度和出度)和無向圖(最大邊數n(n-1)/2);

2.圖的存儲結構:

1)關聯矩陣(表示了圖的結構,即圖中各結點的後件關係):表示各個結點的前件與後件關係,矩陣R(i,j)=1,表示結點i是結點j的前件,矩陣R(i,j)=0,表示結點i不是結點j的前件,無向圖的關聯矩陣是對稱矩陣,且對角線上的元素均爲0.有向圖的不一定是對稱矩陣且對角線不一定爲0;

2)求值矩陣(表示了圖中每兩個結點之間的求值函數):在求值矩陣V中,一般用-1表示兩個結點無直接連通;

3)鄰接表(存儲結構也稱“順序--索引---鏈接”存儲結構):首先,用一個順序存儲空間來存儲圖中各個結點信息。其次,對應圖中每個結點構造一個單鏈表,該單鏈表的頭指針即爲順序空間中的對應存儲結點的指針域。

二:圖鄰接表類

1.圖鄰接表類//文件名 :Link_GP.h

#include "sq_Queue.h"
#include <iostream>
#include <fstream>
using namespace std;
template <class T1>
struct node
{
	int num;
	T1 val;
	node * next;
};
template <class T1,class T2>
struct gpnode
{
	T2 data;
	node<T1> *link;
};
//定義圖鄰接表類
template <class T1,class T2>
class Link_GP
{
    private:
		int nn;   //圖中結點個數
		gpnode<T1,T2> *gp;//圖鄰接表中順序存儲空間首地址
	public:
		Link_GP(){gp=NULL;return;}//圖鄰接表初始化
		void creat_Link_GP(int,T2[]);//由鍵盤輸入生成圖鄰接表
		void creat_Link_GP(int,T2[],char *);//由文件數據生成圖鄰接表
		void prt_Link_GP();//輸出圖鄰接表
		void dfs_Link_GP();//縱向優先搜索法遍歷圖
		void bfs_Link_GP();//橫向優先搜索法遍歷圖
		void short_Link_GP(int);//求指定結點到其餘各結點的最短距離
		void short_path_Link_GP(int);//求指定結點到其餘各結點的最短距離與路徑

};
//由鍵盤輸入生成圖鄰接表
template <class T1,class T2>
void Link_GP<T1,T2>::creat_Link_GP(int n,T2 d[])
{
	node<T1> *p;
	nn=n;                  //圖中結點個數
	int k,m;
	T1 v;
	gp=new gpnode<T1,T2>[nn];//申請圖鄰接表中順序存儲空間
	for(k=0;k<nn;k++)  //依次對圖中的每個結點建立鏈接所有後件的單鏈表
	{
		(gp+k)->data=d[k];//置順序存儲空間的結點值
		(gp+k)->Link=NULL;//置順序存儲空間結點的指針域爲空
		cout<<"請輸入圖中第"<<k<<"個結點的後件信息:"<<endl;
		cin>>m>>v;  //輸入後件信息
		while(m>=0)
		{
			p=new node<T1>;  //申請單鏈表結點
			p->num=m;p->val=v;
			p->next=(gp+k)->link;//新結點指針指向原頭結點
			(gp+k)->link=p;//將新結點鏈接到單鏈錶鏈頭
			cin>>m>>v;

		}
	}
	return;
}
//由文件數據生成圖鄰接表
template<class T1,class T2>
void Link_GP<T1,T2>::creat_Link_GP(int n,T2 d[],char * filename)
{
	node<T1> *p;
	int k,m;
	nn=n;
	T1 v;
	ifstream infile(filename,ios::in);//打開文件
	gp=new gpnode<T1,T2>[nn];
	for(k=0;k<nn;k++)  //依次對圖中的每個結點建立鏈接所有後件的單鏈表
	{
		(gp+k)->data=d[k];//置順序存儲空間的結點值
		(gp+k)->link=NULL;//置順序存儲空間結點的指針域爲空

		infile>>m>>v;  //輸入後件信息
		while(m>=0)
		{
			p=new node<T1>;  //申請單鏈表結點
			p->num=m;p->val=v;
			p->next=(gp+k)->link;//新結點指針指向原頭結點
			(gp+k)->link=p;//將新結點鏈接到單鏈錶鏈頭
			infile>>m>>v;
			
		}
	}
	return;
	
}
template<class T1,class T2>
void Link_GP<T1,T2>::prt_Link_GP()
{
	node<T1> *q;
	int k;
	for(k=0;k<nn;k++)
	{
		cout<<(gp+k)->data;
		q=(gp+k)->link;
		while(q!=NULL)
		{
			cout<<"---->";
			cout<<q->num<<","<<q->val;
			q=q->next;
		}
		cout<<endl;
	}
	return;
}

//縱向優先搜索法遍歷圖
template<class T1,class T2>
void Link_GP<T1,T2>::dfs_Link_GP()
{
	int k,*mark;
	mark=new int[nn];//申請標誌數組空間
	for(k=0;k<nn;k++)
		mark[k]=0;
	for(k=0;k<nn;k++)
		if(mark[k]==0) dfs(gp,k,mark);
		cout<<endl;
	delete mark;
	return;
}
template<class T1,class T2>
static dfs(gpnode<T1,T2> *q,int k,int *mark)
{
	node<T1> *p;
	cout<<(q+k)->data<<" ";//輸出當前圖結點值
	mark[k]=1; //記錄當前結點已查訪標誌
	p=(q+k)->link;
	while(p!=NULL)
	{
		if(mark[p->num-1]==0)//該後件結點未查訪過
			dfs(q,p->num-1,mark);
		p=p->next;//下一個後件結點
	}
	return 0;
}
//橫向優先搜索法遍歷圖
template<class T1,class T2>
void Link_GP<T1,T2>::bfs_Link_GP()
{
	int *mark,k;
	sq_Queue<int> q(nn); //建立循環隊列空間並初始化
	node<T1> *p;
	mark=new int[nn];   //申請標誌數組空間
	for(k=0;k<nn;k++)
		mark[k]=0;
	for(k=0;k<nn;k++)   //對每個圖結點橫向優先搜索
	{
		if(mark[k]==0)  //當前未查訪過
		{
			mark[k]=1;   //記錄當前結點已經查訪過
			cout<<gp->data<<" "; //輸出當前值
			q.ins_sq_Queue(k);   //當前結點編號入隊
			while(q.flag_sq_Queue())//隊列不空
			{
				k=q.del_sq_Queue(); //從隊列中退出一個結點作爲當前結點
				p=(gp+k)->link;// 所有後件結點鏈表指針
				while(p!=NULL) //還有後件
				{
					k=p->num-1;
					if(mark[k]==0)
					{
						cout<<(gp+k)->data<<"  ";
						mark[k]=1;
						q.ins_sq_Queue(k);
					}
					p=p->next;  //下一個後件
				}
			}
		}
	}
cout<<endl;
delete mark;
return;
}


//求指定結點到其餘各結點的最短距離

template <class T1>
struct pathnode
{
	T1 path;    //最短距離
	node<T1> *elink;  //路徑單鏈表指針
};
template <class T1,class T2>
void Link_GP<T1,T2>::short_Link_GP(int m)
{
	int *mark,k,j,h;
	pathnode<T1> *e;
	node<T1> *p,*pp;
	sq_Queue<int> q(nn);
	e=new pathnode<T1>[nn];
	mark=new int[nn];
	for(k=0;k<nn;k++)
		mark[k]=0;
	for(k=0;k<nn;k++)
	{
		(e+k)->path=-1;(e+k)->elink=NULL;
	}
	(e+m-1)->path=0;
	q.ins_sq_Queue(m);
	mark[m-1]=1;
	while(q.flag_sq_Queue())
	{
		k=q.del_sq_Queue();
		p=(gp+k-1)->link;
		while(p!=NULL)
		{
			j=p->num;
			h=((e+k-1)->path)+p->val;
			if(((e+j-1)->path==-1)||((e+j-1)->path>h))
			{
				(e+j-1)->path=h;
				pp=(e+j-1)->elink;
				if(pp==NULL)
					pp=new node<T1>;
				pp->num=j;pp->val=p->val;
				pp->next=(e+k-1)->elink;(e+j-1)->elink=pp;
				if(mark[j-1]==0)
				{
					mark[j-1]=1;
					q.ins_sq_Queue(j);
				}
			}
			p=p->next;
		}
	}
	cout<<"k  "<<"PATH "<<endl;
	for(k=0;k<nn;k++)                       //輸出各結點到起始結點的最短距離與路徑
	{
		cout<<k+1<<"  "<<(e+k)->path<<"  ";//輸出結點編號與最短距離
/*
			p=(e+k)->elink;
			while(p!=NULL)   //輸出路徑
			{
				cout<<"--->";
				cout<<p->num<<","<<p->val;
				p=p->next;
			}
			cout<<endl;

	}*/
		cout<<endl;
	}
	delete mark;
	delete e;
	return;
}

//求指定結點到其餘各結點的最短距離與路徑
//定義最短距離與路徑順序存儲空間結點類型
/*
template <class T1>
struct pathnode
{
	T1 path;    //最短距離
	node<T1> *elink;  //路徑單鏈表指針
};*/

template <class T1,class T2>
void Link_GP<T1,T2>::short_path_Link_GP(int m)
{
	int *mark,k,j,h;
	pathnode<T1> *e;
	node<T1> *p,*pp;
	sq_Queue<int> q(nn);
	e=new pathnode<T1>[nn];
	mark=new int[nn];
	for(k=0;k<nn;k++)
		mark[k]=0;
	for(k=0;k<nn;k++)
	{
		(e+k)->path=-1;(e+k)->elink=NULL;
	}
	(e+m-1)->path=0;
	q.ins_sq_Queue(m);
	mark[m-1]=1;
	while(q.flag_sq_Queue())
	{
		k=q.del_sq_Queue();
		p=(gp+k-1)->link;
		while(p!=NULL)
		{
			j=p->num;
			h=((e+k-1)->path)+p->val;
			if(((e+j-1)->path==-1)||((e+j-1)->path>h))
			{
				(e+j-1)->path=h;
				pp=(e+j-1)->elink;
				if(pp==NULL)
					pp=new node<T1>;
				pp->num=j;pp->val=p->val;
				pp->next=(e+k-1)->elink;(e+j-1)->elink=pp;
				if(mark[j-1]==0)
				{
					mark[j-1]=1;
					q.ins_sq_Queue(j);
				}
			}
			p=p->next;
		}
	}
	cout<<"k  "<<"PATH "<<"ELINK  "<<endl;
	for(k=0;k<nn;k++)                       //輸出各結點到起始結點的最短距離與路徑
	{
		cout<<k+1<<"  "<<(e+k)->path<<"  ";//輸出結點編號與最短距離
		p=(e+k)->elink;
		while(p!=NULL)   //輸出路徑
		{
			cout<<"--->";
			cout<<p->num<<","<<p->val;
			p=p->next;
		}
		cout<<endl;
	}
	delete mark;
	delete e;
	return;
}

2.具體應用:

#include "Link_GP.h"
int main()
{
	char d[8]={'A','B','C','D','E','F','G','H'};
	Link_GP<int,char> g;
	g.creat_Link_GP(8,d,"f1.txt");
	cout<<"圖g鄰接表:"<<endl;
	g.prt_Link_GP();
	cout<<"縱向優先搜索法遍歷圖:"<<endl;
	g.dfs_Link_GP();
	cout<<"橫向優先搜索法遍歷圖:"<<endl;
	g.bfs_Link_GP();
	cout<<"第3個結點到其餘各結點的最短距離:"<<endl;
	g.short_Link_GP(3);
	cout<<"第3個結點到其餘結點的最短距離與路徑:"<<endl;
	g.short_path_Link_GP(3);
	return 0;
}


3.實驗結果


 

4.附件:sq_Queue.h

#include <iostream>
using namespace std;
template <class T>
class sq_Queue
{
private:
	int mm;//存儲空間容量
	int front;
	int rear;
	int s;//標誌
	T * q;
public:
	sq_Queue(int);
	void prt_sq_Queue();
	int flag_sq_Queue();
	void ins_sq_Queue(T);
	T del_sq_Queue();
};
template <class T>
sq_Queue<T>::sq_Queue(int m)
{
	mm=m;
	q=new T[mm];
	front=mm;
	rear=mm;
	s=0;
	return;
}
template <class T>
void sq_Queue<T>::prt_sq_Queue()
{
	int i;
	cout<<"front="<<front<<endl;
	cout<<"rear="<<rear<<endl;
	if(s==0)
	{
		cout<<"隊列空"<<endl;
		return;
	}
	i=front;
	do 
	{
		i=i+1;
		if(i==mm+1)
			i=1;
		cout<<q[i-1]<<endl;
		
	} while (i!=rear);
	return;
}
template <class T>
int sq_Queue<T>::flag_sq_Queue()
{
	if((s==1)&&(rear==front))
	{
		cout<<"隊列滿"<<endl;
		return (-1);
			
	}
	if(s==0)
	{
		cout<<"隊列空"<<endl;
		return 0;
	}
	return 1;
}
template <class T>
void sq_Queue<T>::ins_sq_Queue(T b)
{
	if((s==1)&&(rear==front))
	{
		cout<<"Queue overflow"<<endl;
		return;
	}
	rear=rear+1;
	if(rear==mm+1)rear=1;
	q[rear-1]=b;
	s=1;
	return;
}
template <class T>
T sq_Queue<T>::del_sq_Queue()
{
	T y;
	if(s==0)
	{
		cout<<"queue is empty"<<endl;
		return (0);
	}
	front=front+1;
	if(front==mm+1)//特別要注意等號“==”而不是“=“
		front=1;
	y=q[front-1];
	if(rear==front)
		s=0;
	return y;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章