图的储存结构(邻接表)
图用邻接矩阵储存时,是用的一个二维数组,操作这个图的时候就相当于操作这个二维数组。但一但使用数组时就有一个很明显的缺点,那就是动态扩容性,基于邻接矩阵的图不能添加节点,只能添加边。如果图是一个节点非常多的稀疏图,比如说这个n为一亿,那么所需要的内存就是100000000 * 100000000 = 10000000000000000个单位,而其中非常多的内存是被浪费了的。因而可以使用另外一种储存结构——邻接表来储存图。邻接表是在一维的基础上进行扩展的,把节点排列成一维的线性表,然后线性表的每个元素又是一个链表,这条链的头就是当前节点,而链中的元素就是这个节点在图中的邻接节点,把邻接节点按序号排列成一个线性链。这样的好处就是只储存了有意义的关系,不会像邻接矩阵那样浪费没有连接关系的储存单元。
下面是用邻接表来实现图
#pragma once
#ifndef ADJLISTDIRGRAPH
#define ADJLISTDIRGRAPH
#include "graph.h"
#include "linklist.h"
namespace dataStructure
{
template<typename T>
struct AdjListGraphNode
{
T data;
int tag;
LinkList<int> *adjLink = NULL;
};
template<typename T>
class AdjListDirGraph:public Graph<T>
{
public:
AdjListDirGraph();
~AdjListDirGraph();
bool InsertNode(const T &t);
bool DeleteNode(const int v);
//获取节点的值
bool GetElem(int v, T &t);
//设置节点的值
bool SetElem(int v, const T &t);
//返回节点元素
T GetVexData(int v)const;
//返回节点个数
int GetVexNum()const;
//返回边数
int GetEdgeNum()const;
//返回第一个邻接点
int FirstAdjVex(int v)const;
//返回下一个邻接点
int NextAdjVex(int v1, int v2)const;
//插入一条边
void InsertEdge(int v1, int v2);
//删除一条边
void DeleteEdge(int v1, int v2);
//获取节点上的标志
bool GetTag(int v, int &tag)const;
//设置节点上的标志
bool SetTag(int v, const int &tag);
//深搜
void DFSTraverse(void(*visit)(const T &t))const;
//广搜
void BFSTraverse(void(*visit)(const T &t))const;
private:
int vexNum, edgeNum;
LinkList<AdjListGraphNode<T>*> *adjList;
};
template<typename T>
AdjListDirGraph<T>::AdjListDirGraph()
{
adjList = new LinkList<AdjListGraphNode<T>*>;
vexNum = 0;
edgeNum = 0;
}
template<typename T>
AdjListDirGraph<T>::~AdjListDirGraph()
{
if(adjList)
{
delete adjList;
}
}
template<typename T>
bool AdjListDirGraph<T>::InsertNode(const T &t)
{
AdjListGraphNode<T> *newNode = new AdjListGraphNode<T>;
newNode->data = t;
newNode->adjLink = new LinkList<int>;
adjList->Add(newNode);
++vexNum;
return true;
}
template<typename T>
bool AdjListDirGraph<T>::DeleteNode(const int v)
{
if(v >=0 && v < vexNum)
{
AdjListGraphNode<T> *node = NULL;
bool result = adjList->Delete(adjList->Length() - 1, node);
if (node)
{
--vexNum;
return true;
}
}
return false;
}
//获取节点的值
template<typename T>
bool AdjListDirGraph<T>::GetElem(int v, T &t)
{
if(v >=0 && v < vexNum)
{
AdjListGraphNode<T> *node = NULL;
adjList->GetElem(v, node);
if (node)
{
t = node->data;
return true;
}
else
{
return false;
}
}
return false;
}
//设置节点的值
template<typename T>
bool AdjListDirGraph<T>::SetElem(int v, const T &t)
{
if (v >= 0 && v < vexNum)
{
AdjListGraphNode<T> *node = NULL;
adjList->GetElem(v, node);
if (node)
{
node->data = t;
return true;
}
else
{
return false;
}
}
return false;
}
//返回节点元素
template<typename T>
T AdjListDirGraph<T>::GetVexData(int v)const
{
if (v >= 0 && v < vexNum)
{
AdjListGraphNode<T> *node = NULL;
adjList->GetElem(v, node);
if (node)
{
return node->data;
}
else
{
}
}
}
//返回节点个数
template<typename T>
int AdjListDirGraph<T>::GetVexNum()const
{
return vexNum;
}
//返回边数
template<typename T>
int AdjListDirGraph<T>::GetEdgeNum()const
{
return edgeNum;
}
//返回第一个邻接点
template<typename T>
int AdjListDirGraph<T>::FirstAdjVex(int v)const
{
if(v >=0 && v <vexNum)
{
AdjListGraphNode<T> *node = NULL;
adjList->GetElem(v, node);
if(node)
{
int firstV = -1;
node->adjLink->GetElem(0, firstV);
return firstV;
}
}
return -1;
}
//返回下一个邻接点
template<typename T>
int AdjListDirGraph<T>::NextAdjVex(int v1, int v2)const
{
if (v1 >= 0 && v1 < vexNum)
{
AdjListGraphNode<T> *node = NULL;
adjList->GetElem(v1, node);
if(node)
{
if (v2 >= 0 && v2 < node->adjLink->Length())
{
int nextV = -1;
int index = -1;
int v = -1;
for (int i = 0;i < node->adjLink->Length();i++)
{
node->adjLink->GetElem(i, v);
if (v == v2 && i + 1 < node->adjLink->Length())
{
index = i + 1;
}
}
node->adjLink->GetElem(index, nextV);
return nextV;
}
}
}
return -1;
}
//插入一条边
template<typename T>
void AdjListDirGraph<T>::InsertEdge(int v1, int v2)
{
if (v1 >= 0 && v1 < vexNum && v2 >= 0 && v2 < vexNum)
{
AdjListGraphNode<T> *node = NULL;
adjList->GetElem(v1, node);
if (node)
{
//查找添加边的节点的位置
int index = -1;
int k = -1;
for (int i = 0;i < node->adjLink->Length();i++)
{
node->adjLink->GetElem(i, k);
if(v2 < k && i == 0)//比第一个节点的值都小
{
index = 0;
break;
}
if(v2 > k )//v2比当前节点的值要大
{
if ((i + 1) < node->adjLink->Length())//后面还有一个节点
{
node->adjLink->GetElem(i + 1, k);
if(k > v2)//index应该在i和i+1之间
{
index = i + 1;
break;
}
}
}
}
if(index < 0)
{
index = node->adjLink->Length();
}
node->adjLink->Insert(index, v2);
++edgeNum;
}
}
}
//删除一条边
template<typename T>
void AdjListDirGraph<T>::DeleteEdge(int v1, int v2)
{
if (v1 >= 0 && v1 < vexNum && v2 >= 0 && v2 < vexNum)
{
AdjListGraphNode<T> *node = NULL;
adjList->GetElem(v1, node);
if (node)
{
int index = -1;
int value = -1;
for (int i = 0;i < node->adjLink->Length();i++)
{
node->adjLink->GetElem(i, value);
if(value == v2)
{
index = i;
break;
}
}
if(index >= 0)
{
int k = -1;
node->adjLink->Delete(index, k);
++edgeNum;
}
}
}
}
//获取节点上的标志
template<typename T>
bool AdjListDirGraph<T>::GetTag(int v, int &tag)const
{
if(v >=0 && v < vexNum)
{
AdjListGraphNode<T> *node = NULL;
adjList->GetElem(v, node);
if(node)
{
tag = node->tag;
return true;
}
}
return false;
}
//设置节点上的标志
template<typename T>
bool AdjListDirGraph<T>::SetTag(int v, const int &tag)
{
if (v >= 0 && v < vexNum)
{
AdjListGraphNode<T> *node = NULL;
adjList->GetElem(v, node);
if (node)
{
node->tag = tag;
return true;
}
}
return false;
}
//深搜
template<typename T>
void AdjListDirGraph<T>::DFSTraverse(void(*visit)(const T &t))const
{
}
//广搜
template<typename T>
void AdjListDirGraph<T>::BFSTraverse(void(*visit)(const T &t))const
{
}
}
#endif
下面是测试代码,同样可以用断点调试的方式查看生成的图的结构#include "stdafx.h"
#include <iostream>
#include "adjlistdirgraph.h"
using namespace std;
using namespace dataStructure;
int main()
{
AdjListDirGraph<char> *graph = new AdjListDirGraph<char>;
char a = 'A';
char b = 'B';
char c = 'C';
char d = 'D';
char e = 'E';
graph->InsertNode(a);
graph->InsertNode(b);
graph->InsertNode(c);
graph->InsertNode(d);
graph->InsertNode(e);
graph->InsertEdge(0, 2);
graph->InsertEdge(0, 3);
graph->InsertEdge(1, 2);
graph->InsertEdge(1, 4);
graph->InsertEdge(2, 0);
graph->InsertEdge(2, 1);
graph->InsertEdge(2, 4);
graph->InsertEdge(3, 0);
graph->InsertEdge(3, 4);
graph->InsertEdge(4, 1);
graph->InsertEdge(4, 2);
graph->InsertEdge(4, 3);
system("pause");
return 0;
}