数据结构学习笔记6-图

在这篇文章中,我们要讨论一下关于图的知识点:

1.图的存储方式——邻接矩阵存储和邻接表存储

*邻接矩阵存储code如下所示

#include <iostream>

using namespace std;

template <class T>
class Graph
{
protected:
    int n,e;									 //e是边数,n是节点数
public:
    virtual bool GInsert(int u,int v,T w)=0;   //图中在节点u和v之间插入一条权值为w的边
    virtual bool GRemove(int u,int v)=0;        //删除图中节点u和v之间的边
    virtual bool GExist(int u,int v) const=0;    //判断图中节点u和v之间是否存在路径
};

template <class T>
class MGraph:public Graph<T>
{
protected:                          //这里用protected权限是为了未来可能存在的继承该MGraph的类可以访问
    T **a;                          //二维数组指针指向图的邻接矩阵
public:
    MGraph(int mSize);
    ~MGraph();
    bool GInsert(int u,int v,T w);
    bool GRemove(int u,int v);
    bool GExist(int u, int v)const;
};
template <class T>
MGraph<T>::MGraph(int mSize)               //邻接矩阵是n*n的大小,即有n个节点
{
    n=mSize;
    a=new T* [n];                   //申请一个大小为n的T*指针类型数组空间,每个空间存储一个T指针
    for(int i=0;i<n;i++)            //初始化邻接矩阵
    {
        a[i]=new T [n];             //i个数组空间中的指针a[i]分别指向一段n连续的T类型数组空间
            for(int j=0;j<n;j++)
            {
                a[i][j]=-1;          //赋值-1,表明i和j节点之间没有边
            }
            a[i][i]=0;              //节点无自回路
    }
}
template <class T>
MGraph<T>::~MGraph()
{
    for(int i=0;i<n;i++)
        delete []a[i];
    delete []a;
}
template <class T>
bool MGraph<T>::GInsert(int u, int v, T w)
{
    if(u<0||v<0||u>n-1||v>n-1)
    {
        cout<<"节点值越界"<<endl;
        return false;
    }
    if(a[u][v]!=-1)
    {
        cout<<"边已经存在"<<endl;
        return false;
    }
    a[u][v]=w;
    e++;
    return true;
}
template <class T>
bool MGraph<T>::GRemove(int u,int v)
{
    if(u<0||v<0||u>n-1||v>n-1)
    {
        cout<<"节点值越界"<<endl;
        return false;
    }
    if(a[u][v]==-1)
    {
        cout<<"要删除的边不存在"<<endl;
        return false;
    }
    a[u][v]==-1;
    e--;
    return true;
}

template <class T>
bool MGraph<T>::GExist(int u, int v) const
{
    if(u<0||v<0||u>n-1||v>n-1)
    {
        cout<<"GExit:节点越界"<<endl;
        return false;
    }
    if(a[u][v]==-1)
    {
        cout<<"GExit:边不存在"<<endl;
        return false;
    }
    cout<<"GExit:边存在"<<endl;
    return true;
}


int main()
{
    MGraph<int> a(4);
	a.GInsert(0,1,1);
	a.GExist(0,2);
    return 0;
}

*邻接表类似于一个哈希表,邻接表存储方式的图code如下所示

#include <iostream>
using namespace std;

template <class T> class LGraph;
template <class T>
class LNode					//邻接表节点类
{
private:
	int adjVex;				//节点号
	T w;					//边权值
	LNode<T> *nextArc;		//节点指针
public:
	LNode(int vertex,T weight,LNode<T> *next)
	{
		adjVex=vertex;
		w=weight;
		nextArc=next;
	}

	friend class LGraph<T>;	//友元类LGraph可以访问类LNode中的private成员
};

template <class T>
class LGraph				//邻接表类
{
private:
	LNode<T> **a;			//邻接表二维指针
	int n;					//图的节点数
	int e;					//图的边数
public:
	LGraph(int mSize);
	~LGraph();
	bool LExist(int u,int v);
	bool LInsert(int u,int v,T w);
	bool LRemove(int u,int v);
};

template<class T>
LGraph<T>::LGraph(int mSize)	//初始化邻接表
{
	n=mSize;
	a=new LNode<T>* [n];
	for(int i=0;i<n;i++)
	{
		a[i]=NULL;
	}
}

template<class T>
LGraph<T>::~LGraph()
{
	for(int i=0;i<n;i++)
	{
		delete [] a[i];
	}
	delete []a;
}

template<class T>
bool LGraph<T>::LExist(int u,int v)
{
	if(u<0||v<0||u>n-1||v>n-1)
	{
		cout<<"LExist:节点号越界"<<'\n';
		return false;
	}
	LNode<T> *p=a[u];
	while(p)
	{
		if(p->adjVex==v)
		{
			cout<<"LExist:存在"<<u<<"-"<<v<<"边"<<'\n';
			return true;
		}
		p=p->nextArc;
	}
	if(!p)
		return false;
}

template<class T>
bool LGraph<T>::LInsert(int u,int v,T w)
{
	if(u<0||v<0||u>n-1||v>n-1)
	{
		cout<<"LInsert:节点号越界"<<'\n';
		return false;
	}
	if(LExist(u,v))
	{
		cout<<"LInsert:已经存在"<<u<<"-"<<v<<"边"<<'\n';
		return false;
	}
	LNode<T> *p=new LNode<T>(v,w,a[u]);
	a[u]=p;
	e++;
	return true;
}

template<class T>
bool LGraph<T>::LRemove(int u,int v)
{
	if(u<0||v<0||u>n-1||v>n-1)
	{
		cout<<"LRemove:节点号越界"<<'\n';
		return false;
	}
	if(!LExist(u,v))
	{
		cout<<"LRemove:不存在"<<u<<"-"<<v<<"边"<<'\n';
		return false;
	}
	LNode<T> *p=a[u],*q=NULL;
	while(p&&p->adjVex!=v)
	{
		q=p;
		p=p->nextArc;
	}
	if(!p)
		return false;
	if(q)
		q->nextArc=p->nextArc;
	else
		a[u]=p->nextArc;
	delete p;
	e--;
	return true;
}

2.图的深度优先遍历(DFS),这里我们讨论以邻接表形式存储的图如何进行深度优先遍历。这里采用了递归法,大致思路如下

(1)访问任意节点v,并对v打上已经访问过的标记

(2)依次从v的未访问邻接点出发,深度优先搜索图

#include "lgraph.cpp"

//图的搜索
template <class T>
class ExtLGraph:public LGraph<T>
{
private:
	void DFS(int v,bool *visited);			//从v节点出发深度优先搜索,visited是标志位数组指针
	//void BFS();
public:
	ExtLGraph(int mSize):LGraph<T>(mSize){}	//调用父类的构造函数来初始化子类构造函数
	void DFS();								//深度优先遍历
	//void BFS();								//宽度优先遍历
};
template <class T>
void ExtLGraph<T>::DFS()
{
	bool *visited=new bool [n];				//创建标志位数组
	for(int i=0;i<n;i++)
		visited[i]=false;					//所有标志位至false,表明未访问过
	for(int i=0;i<n;i++)
		if(!visited[i])						//未访问过的节点进行深度优先搜索递归算法
			DFS(i,visited);
	delete [] visited;
}
template <class T>
void ExtLGraph<T>::DFS(int v,bool *visited)
{
	visited[v]=true;						//v节点标志位至为true
	cout<<" "<<v;							//打印输出访问到的节点v
	LNode<T> *p=a[v];
	while(p)
	{
		if(!visited[p->adjVex])
			DFS(p->adjVex,visited);
		p=p->nextArc;
	}
	
}

注意:由于ExtLGraph类是LGraph的子类,由于友元类无法继承的原因,在ExtLGraph类中无法访问LNode类中的private成员,因此LNode类中应该将ExtLGraph类设置为友元类!!!


【欢迎读者交流批评指正~】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值