目录
无向图的邻接表
链表(存相邻顶点下标)的类
数组里放的顶点
邻接表(操作)
构造和析构(创建销毁邻接表)
插入顶点
插入边
获取下标
插v1、v2之间的边
删除顶点
删除边
输出:
其他图邻接表
邻接表用一个一维数组存图的顶点和指针,指针指向一个链表,链表里存放与当前顶点相连的顶点在数组中的下标。如下图(无向图邻接表):
无向图的邻接表
链表(存相邻顶点下标)的类
class Edge
{
public:
Edge() :m_next(nullptr) {}
Edge(int v) :m_destindex(v), m_next(nullptr) {}
int m_destindex;//下标
Edge* m_next;//下一个邻接顶点的结点
};
数组里放的顶点
class Vertex
{
public:
Vertex() :m_list(nullptr) {}
Vertex(int v) :m_VerValue(v), m_list(nullptr) {}
char m_VerValue;//顶点值
Edge* m_list;//指针指向邻接顶点的链表
};
邻接表(操作)
插入顶点,插入边,删除顶点,删除边,获取顶点在数组中的下标(前面的操作需要用)
#define SIZE 10
class GraphLink
{
public:
GraphLink();
~GraphLink();
void InsertVertex(char v);//插顶点
void InsertEdge(char v1, char v2);//插边
void PrintGraph();//打印
void DelVertex(char v);//删顶点
void DelEdge(char v1, char v2);//删边
int GetVertexIndex(char v);//获取顶点下标
private:
int m_MaxVertex;//最多结点数
int m_NumVertex;//当前结点数
int m_NumEdge;//边数
Vertex* m_VerArr;//存顶点的数组(指针指向数组头)
};
构造和析构(创建销毁邻接表)
创建:给m_VerArr指针new最大顶点数m_MaxVertex个顶点Vertex大小的空间;
销毁:释放指向数组起始的指针的空间。
GraphLink::GraphLink() :m_MaxVertex(SIZE), m_NumVertex(0), m_NumEdge(0)
{
m_VerArr = new Vertex[m_MaxVertex];
}
GraphLink::~GraphLink()
{
if (m_VerArr != nullptr)
{
delete[]m_VerArr;
m_VerArr = nullptr;
}
}
插入顶点
首先确定顶点数(不能超过设定的最大顶点数)。
若可插:将顶点值赋到数组中最后一个位置m_VerArr[m_NumVertex],顶点个数++。
void GraphLink::InsertVertex(char v)
{
if (m_NumVertex >= m_MaxVertex)return;
m_VerArr[m_NumVertex++].m_VerValue = v;
}
插入边
插入顶点v1到顶点v2的边时,由于链表中记录的是顶点的下标,所有首先需要有一个获取下标的函数:
获取下标
遍历数组记录下标,找到顶点即可找到下标返回,若没找到:返回-1。
int GraphLink::GetVertexIndex(char c)
{
for (int i = 0; i < m_NumVertex; i++)
{
if (m_VerArr[i].m_VerValue == c)
return i;
}
return -1;
}
插v1、v2之间的边
注意:无向图插一条边需要改两个表。
获取下标后,插入方法与链表头插相同。
void GraphLink::InsertEdge(char v1, char v2)
{
int p1 = GetVertexIndex(v1);
int p2 = GetVertexIndex(v2);
if (p1 == -2 || p2 == -1)return;
//v1->v2 既是在v1的边链表中插入值为p2的边节点
Edge* edge = new Edge(p2);
edge->m_next = m_VerArr[p1].m_list;
m_VerArr[p1].m_list = edge;
//v2->v1
edge = new Edge(p1);
edge->m_next = m_VerArr[p2].m_list;
m_VerArr[p2].m_list = edge;
m_NumEdge++;
}
删除顶点
用覆盖删除的方法:数组最后一个顶点覆盖要删的,并修改链表内受影响下标的值。
void GraphLink::DelVertex(char v)
{
int p = GetVertexIndex(v);
if (p == -1)return;
Edge* pp = m_VerArr[p].m_list;
char destvalue;
while (pp)
{
destvalue = m_VerArr[pp->m_destindex].m_VerValue;
DelEdge(v, destvalue);
pp = m_VerArr[p].m_list;
}
//覆盖
m_NumVertex--;
m_VerArr[p].m_VerValue = m_VerArr[m_NumVertex--].m_VerValue;
//修改
Edge* q = nullptr;
pp = m_VerArr[p].m_list;
while (pp != nullptr)
{
int k = pp->m_destindex;
q = m_VerArr[k].m_list;
while (q)
{
if (q->m_destindex == m_NumVertex)
{
q->m_destindex = p;
break;
}
q = q->m_next;
}
pp = pp->m_next;
}
}
删除边
void GraphLink::DelEdge(char v1, char v2)
{
int p1 = GetVertexIndex(v1);
int p2 = GetVertexIndex(v2);
if (p1 == -2 || p2 == -1)return;
//在p1里面删p2
Edge* pf = m_VerArr[p1].m_list;
if (m_VerArr[p1].m_list->m_destindex == p2)
{
m_VerArr[p1].m_list = m_VerArr[p1].m_list->m_next;
delete pf;
pf = nullptr;
}
else
{
while (pf->m_next->m_destindex != p2 && pf != nullptr)
{
pf = pf->m_next;
}
if (pf == nullptr)return;
Edge* p = pf->m_next;
pf->m_next = p->m_next;
delete p;
p = nullptr;
}
//v2->v1
pf = m_VerArr[p2].m_list;
if (m_VerArr[p2].m_list->m_destindex == p1)
{
m_VerArr[p2].m_list = m_VerArr[p2].m_list->m_next;
delete pf;
pf = nullptr;
}
else
{
while (pf->m_next->m_destindex != p1 && pf != nullptr)
{
pf = pf->m_next;
}
if (pf == nullptr)return;
Edge* p = pf->m_next;
pf->m_next = p->m_next;
delete p;
p = nullptr;
}
m_NumEdge--;
}
输出:
void GraphLink::PrintGraph()
{
Edge* p = nullptr;
for (int i = 0; i < m_NumVertex; i++)
{
cout << i << " " << m_VerArr[i].m_VerValue << " ";
p = m_VerArr[i].m_list;
while (p)
{
cout << p->m_destindex << "->";
p = p->m_next;
}
cout << "nul" << endl;
}
cout << endl;
}
其他图邻接表
有向图注意边的数量修改,网需要在链表结点中加上存边权值的部分。
网结构如下: