1. 程式人生 > >人非生而知之者,孰能無惑?

人非生而知之者,孰能無惑?

老規矩,1.你必須明白,什麼是圖?

2.圖是幹什麼的?

3.圖的最基本的物理儲存有哪些?

4.遍歷圖到底是在幹什麼?有哪些方式?

弄清楚這些,我這裡介紹一種,圖的鄰接表儲存方式實現的,完成初始化,輸出,和兩種遍歷方式。上程式碼,自己看

#include<iostream>
#include<fstream>
#include"sq_Queue.h"
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 create_Link_GP(int,T2[]);
		void create_Link_GP(int ,T2[],char *);
		void prt_Link_GP();
		void dfs_Link_GP();
		void bfs_Link_GP();
};

template <class T1,class T2>
void Link_GP<T1,T2>::create_Link_GP(int n,T2 d[]){
	node<T1> *p;
	int k,m;
	T1 v;
	nn=n;
	gp=new gpnode<T1,T2>[nn];
	for(k=0;k<n;k++){
	(gp+k)->data=d[k];
	(gp+k)->link=NULL;
	cout<<"input the "<<k<< "after the node the info:"<<endl;
	cin>>m>>v;
	while(m>=0){
	p=new node<T1>;
	p->num=m;p->val=v;
	p->next=(gp+k)->next;
	(gp+k)->link=p;
	cin>>m>>v;
	}
	}
	return;
}

template <class T1,class T2>
void Link_GP<T1,T2>::create_Link_GP(int n,T2 d[],char *filename){
	node<T1> *p;
	int k,m;
	T1 v;
	ifstream infile(filename,ios::in);
	nn=n;
	gp=new gpnode<T1,T2>[nn];
	for(k=0;k<n;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;
}
寫了兩種初始化方式,你可以呼叫由鍵盤輸入生成圖的方式,也可以由檔案資料生成圖的方式
#include"Link_GP.h"
int main(){
	char d[8]={'A','B','C','D','E','F','G','H'};
	Link_GP<int,char> g;
	g.create_Link_GP(8,d,"f1.txt");
	cout<<"A=1,B=2,C=3,D=4,E=5,F=6,G=7,H=8"<<endl;
	cout<<endl;
	cout<<"圖g鄰接表:"<<endl;
	g.prt_Link_GP();
	cout<<"DFS :"<<endl;
	g.dfs_Link_GP();
	cout<<"BFS :"<<endl;
	g.bfs_Link_GP();
	return 0;
}
其中,f1.txt就放在當前專案的目錄下,輸入內容如下:
6 35 8 20 4 55 3 30 -1 -1
7 35 4 45 3 10 -1 -1
2 10 1 30 8 25 6 35 5 30 -1 -1
2 45 1 55 7 55 5 10 -1 -1
4 10 3 30 7 50 6 15 -1 -1
5 15 3 35 8 20 1 35 -1 -1
5 50 4 55 8 15 2 35 -1 -1
1 20 3 25 6 20 7 15 -1 -1
關於初始化:

其實,這個沒什麼難的,主要你明白圖的順序儲存空間結點,和單鏈表結點,這兩種型別,是怎麼回事?那麼初始化就很自然了。

關於深度遍歷:

1.要記住,它是遞迴

的深度遍歷。

需要一個輔助陣列,來標記它裡面的元素是否,被查詢過,具體怎麼找?

那就是遞迴的找,找到第一個點之後,找這個點鄰接的第一個點,這個點繼續找鄰接的鄰接的第一個點,有點繞,不過,你要首先明白,深度遍歷幹什麼?

假如,不理解遞迴,也可以這樣想:

1.我找一個結點作為當前結點

2.我找它的第一個後件結點,那麼現在判斷:1)假如它已經標記找到,那麼找當前節點的第二個結點

2)沒標記過,那麼呼叫這個函式,來遍歷它。

就這麼簡單,因為遞迴就是一個迴圈,假如你繞亂了,你就這麼簡單的邏輯想就好了。

關於廣度遍歷:

2.千萬記住,這個遍歷,需要一種資料結構,就是前面說的佇列,為什麼要用呢?你自己看看廣度遍歷到底在幹什麼,相信我就不用說了

1.找一個結點把它進佇列

2.把它出佇列,然後,找到它依次的後件結點,繼續把它們進佇列

3.把剛才這些的點,繼續出佇列,然後同樣的把後件進佇列

4.重複這個過程,值得標誌陣列,都為1,說明都找完了

附個結果圖,大家看看:


可以這樣講,假如你看不懂,最重要的一點就是,你根本不明白,深度遍歷,和廣度遍歷的過程,它們到底怎麼工作的。